Maintaining Security in Rapid Application Development

With great power, comes great responsibility. With Mendix you can create an application 10x faster than traditional code. How about spending some of that time checking your security?

A blog by Rom van Arendonk, Mikael Verhoef & Adnan Ramlawi

Mendix makes the life of a developer a lot easier. It enables us to develop applications in a fraction of the time it would normally take. A lot of security is handled by the platform itself. However, there are aspects that developers need to take into account. As this can be confusing and overlooked sometimes, this blog is dedicated to the following subjects:

  1. Recap: Security features in Mendix
  2. Common Pitfalls
  3. Mendix Data API

Recap: Security features in Mendix

Out-of-the-box, Mendix already has quite a few security features. For example, the default database is inaccessible to any other application than the Mendix app. Another feature is that the main business logic is kept on the application server and the platform natively supports different user roles. Access can be configured on different levels: From Microflows, all the way down to entity attributes.

Business logic in Mendix is primarily captured in Microflows, but not all Microflows are accessible by the client. For every Microflow that is accessible through the client, the developer must specify which user roles are allowed to call that Microflow. Additionally, you can apply entity access to a Microflow. Microflows for which entity access is applied will take into account the user rights that are specified in the domain model. Microflow actions such as a retrieve and a change object will be restricted by the entity access that is specified for the user that is executing the business logic. This is possible because the platform passes on user session data to the Microflow.

Besides calling Microflows, a user can also perform actions on an object. The available actions on an object are: changing values, creating, deleting and committing. All actions performed by a user in the front-end of the application are a combination of the actions described above and calling Microflows. On the entity level, the different rights per user role are specified using access rules. In some cases you want to provide different rights based on the status of that object (e.g. a normal user can only change values of an entity based on an enumeration value) or ownership of an object. By doing this, you get the desired functional limitations for a user. Bear in mind that if multiple access rules apply to a single user for the same object, the user is granted all rights that each access rule specifies: every access rule grants a user more access, it never restricts a user!

Common Pitfalls

Most applications have multiple user roles. Not just to restrict actions, but also to control who gets to see or change a particular dataset. It really depends on the type of application whether this is a security risk or not. However, once you start developing a multi-tenant application or an application to which people from outside your company have access to, information security suddenly becomes significantly more important. Once you allow anonymous users access to your application (i.e. everyone on earth who knows of your application), this becomes a top priority. Especially with new regulations like the GDPR.

For this blog, we assume that the Mendix platform has a flawless implementation of their role based access controls: users simply can’t increase their privileges on their own and are restricted to what the Mendix business engineer has configured. However, there are still some pitfalls to avoid as a Mendix business engineer.

Conditional visibility is not security
A regular misconception is that applying conditional visibility or conditional editability in the front-end is also a way of securing your application. This does seem true when you only look at the front-end of the app, but the exact opposite is true. The Mendix (front-end) app communicates with the application server through REST calls. With just a little knowledge of REST, a user can perform a lot more actions on your data than intended. If a user has full entity access rights, that user can perform all of the actions – like creating, deleting, changing values, and saving objects – by using REST calls. By doing so, a user is able to make changes and commit to the database without calling Microflows and therefore without performing the necessary validation on the data. So, conditional visibility and editability are a nice way to manage the UX of your app. However, it has nothing to do with securing your data and the actions a user can perform on it. More on this in later blogs.

Incorrectly configured entity access
This simple sentence encompasses many classes of problems. The most obvious one is the absence of XPath constraints on entity access rules. XPath constraints ensure that only a part of the data set is accessible by a user, and not all of it. Consider an application to order office supplies. For a company’s internal app, this could limit the orders to which a user has access to e.g. only the orders of his business unit. For a multi-tenant app, this could limit the orders to those of his company. For an application with anonymous users, this would typically give an anonymous user access to only their current order. A failure to set XPath constraints on sensitive data is a data breach waiting to happen.

The second class of problems is too broadly configured read and write access. Mendix entices you a bit by giving the Mendix business engineer the option to have a ‘default access’ for a set of user roles, giving that level of access to each newly added attribute or association of the entity. Furthermore, Mendix provides you with a button to set all attributes to read or read and write. These options should never be used: giving access to an attribute (and especially giving write access) should always be a conscious decision for each attribute made by the business engineer.

So, let’s say you have a large project in production and perhaps you have not followed the two points we stated above. How can you easily check this? We have created a handy tool for this, more on this later!

Mendix Data API

Mendix provides us with a client API to enable developers to work on custom Mendix widgets or other client side extensions to our Mendix application. A deep dive into the API teaches us that it is an extensive list of different functions that can be used. Awesome!

The first one that catches our interest is the getMap function, which makes the metadata of the domain model available on the front end.

Input:
mx.meta.getMap();


Output:

Administration.Account: …

Administration.AccountPasswordData: …

MyFirstModule.Entity: …

System.User: …


With this information, we find a complete overview of all the metadata of all domain models in the project. By itself, this does not give us a great deal of information However, we can use the data.get function to retrieve those objects using XPath as we now know the objects that are available, and see what data is stored in the database! If we wanted to look at the Accounts in the system for instance, we would use the following get statement:

Input:

mx.data.get({

   xpath: “//Administration.Account”,

   callback: function(objs) {

      …

   }

});

Output:

id: mendix.lib.MxObject(Administration.Account:5629499534213121)
jsonData:
attributes:

  • Active: {value: true}

  • Blocked: {value: false}

  • Email: {value: “firstUser@timeSeries.com”}

  • FailedLogins: {value: “0”}

  • FullName: {value: “Hello First User”}

  • IsAnonymous: {value: false}

  • IsLocalUser: {value: true}

  • LastLogin: {value: null}

  • Name: {value: “MyFirstUser”}

  • Password: {value: “{BCrypt}$2a$10$JwiqKuRKjSmKLyR/seM2eOjzpq2CDCqhZMyiTid6qRsuCyo6VmcYW”}

  • System.UserRoles: {value: Array(1)}

  • System.User_Language: {value: “6192449487634433”}

  • System.User_TimeZone: {value: “3940649673949656”}

  • System.changedBy: {value: “562949953422813”}

  • System.owner: {value: “5629499534213121”}

  • WebServiceUser: {value: false}

  • changedDate: {value: 1549285341130}

  • createdDate: {value: 1549285305817}

Using this method, we can obtain information using the console that is not available to us on the front-end. As you can see, by using only two javascript calls we were able to find the username of an account and the email address belonging to it.

The functionality described previously is needed for Mendix itself to function and enable client side widgets to interact with the application This is not necessarily a problem. It can, however, become a problem if the access levels are not set up correctly. Getting data through mx.data.get() is restricted by the access rules that are configured for a user.

To find leaks or mistakes in the setup of the access rules, you could use JavaScript to find the errors. Since this is cumbersome, we at TimeSeries developed the SecurityInspector. This tool provides you with an overview of all the objects you have access to. From the client side with the user you are logged in as, it will also provide you an overview if objects are read-only or editable.

It is important to note that this tool does not send any information to TimeSeries or other third parties. The application triggers the same requests that Mendix uses and is only available to the person using the tool.

Conclusion

This blog covered some of the basic principles of security in Mendix. As mentioned in the beginning, Mendix is a great tool to develop applications in a fraction of the time that it would take with traditional development. Mendix helps the developer with a lot of security aspects, but gives the developer the freedom to set the security based on the application’s needs. It is the responsibility of the developer to keep this an integral part of the development process.

Keep in mind that enforcing too many strict entity access rules can impact the performance while too few could give a user unwanted access. We hope the next time you develop an application, you think of this blog and make some smart design / security decisions that will benefit you (and your clients) in the long run!

This was part 1 of the security blog series.

May 7, 2019
Adnan Ramlawi