Implement Best Practices for App Security

Last modified: November 5, 2024

Introduction

Security is one of the most important aspects of an application, because misconfiguration or failing security can have large stakeholder consequences. The Mendix Runtime protects your application and data according to your model, and Mendix Cloud handles security at the infrastructure level.

This document describes the common aspects you should consider when delivering an application within Mendix Cloud.

Implementing Access Rules

The Mendix architecture includes the Mendix Client, which can compose its own queries (generated by widgets) and send them to the Mendix Runtime. If the Mendix Runtime were to execute these queries without touching them, the Mendix Client would be able to request data that the user should not be allowed to see.

Mendix Runtime Architecture

When designing an application, you can specify access rules on an entity (for more information, see How to Create A Secure App). These access rules are applied whenever a query (received from a client) should be executed, thus they constrain the data returned to the client. For example, users with the “Customer” role can only view orders that are associated to the customer of which this user is part.

While the data that should be viewable and editable in which role is application-specific, the following best practices are key:

  • Attributes determined by the system (like the status of an order) should never be writable
  • If an anonymous user is allowed to create objects, constrain these objects to the owner (an anonymous user is actually a System.User object created on the fly)
  • Do not set a default rule for read-and-write access – this forces you to think about each attribute that is added to an entity
  • Security constraints should be formed as entity access rules
  • Constraints on widgets in pages should not be used as a measure of security, but can filter out irrelevant data for the context of the page
  • Keep your attributes editable within data views, because if an access rule prohibits write access, your client will display it as non-editable – this way you are aware of the (correct) working of an access rule

Avoiding Injection

Injection occurs when (user) input can be misused to influence the behavior of a system. Common cases are parameters for queries (to influence the results of database queries) or HTML with JavaScript contents (to influence browser behavior).

When using Mendix-native components, there are no concerns about the possibility of injection. Queries (like XPath) are parametrized and therefore always escaped, making SQL-injection impossible. For the other way around, retrieved data shown in the user interface is escaped to the HTML format.

When you are building an application, you may use Mendix Marketplace components and external interfaces. Remember that values which originate from user input or other systems should be escaped to avoid injection (and to ensure they are properly display).

These are the common cases and best practices:

  • HTML content, usually derived from an HTML editor and displayed using an HTML viewer, format string, or an email client – these are the ways to avoid this abuse:
  • Database connections (for example, using the Database Connector), where user input is being used within constraints – these are the ways to avoid this abuse:
    • Use prepared statements, which will cause the database-specific connector to take care of escaping the value
    • Sanity-check your user input (for example, use a regular expression to check if your user input only contains alphanumeric characters, spaces, and dashes)

Applying Access Restrictions to Unnecessary Request Handlers

A Mendix app offers various endpoints that can be used to obtain information about offered services. The paths used by these endpoints end in -doc. By default, access to these endpoints is disabled when deploying to a cloud node.

Access restrictions can be configured within the Mendix Portal. They can be found in the Environment details of your cloud node. This is an example of this overview showing the default settings after deploying to a new environment:

Mendix Cloud Access Restrictions Overview

Examples are the ws-doc or rest-doc endpoints that enumerate all the published web and REST services of the application. An attacker could use this information to discover possible areas to exploit.

You can take the following preventative measures:

  • Disable unused endpoints within the Mendix Portal completely by applying a deny all access preset on them
  • Apply IP filtering or client certificate authentication to restrict access

Keep the following in mind:

  • If there are other app-specific request handlers that should have an access restriction applied, then click New to add them as additional paths
  • The URLs of test and acceptance environments can easily be guessed; in order to take effective measures, the restrictions should be applied to these environments also

Applying Authentication on Services

When you expose APIs, you provide a way for users and external systems to access (create, read, update, and/or delete) data within your Mendix application. As APIs are just a different interface to access your data, it is extremely important to restrict data access through authentication and authorization best practices.

Turning On API Security

Firstly, you need to answer the question Requires authentication with Yes or No.

The platform guides you towards choosing Yes for the API endpoints you create. Intuitively this seems correct, as when the Yes option is toggled on. Mendix Studio Pro will reveal a variety of authentication options. These options will restrict which users or external systems have access to your API endpoint. From a security perspective this is exactly what is wanted.

However, choosing between Yes and No is not this straightforward. Choosing Yes will force your API requests to be executed in the context of a user account and require an active session to be established. Skipping the step where you retrieve the user account and establish a session can have a significant performance improvement for your API. This is why choosing No can still be a viable option for your API, and it might even be the recommended option in many situations.

The best practices when selecting No as Requires authentication option are as follows.

  • Provide the HTTP Response object as a parameter to the microflow used as the API handler.
  • Configure the required headers for authentication as part of a published REST operation and add them explicitly to the API handling microflow as input parameters. This could, for example, be an “X-API-Key” header or “Authorization” header. By adding the header as an input parameter it will be included in the generated Swagger documentation hosted at /rest-doc. Here it can be manually set as a parameter and used as part of the “try it out” feature for that API operation.
  • Perform your own validations on this header information at the very start of the API handling microflow.
  • Abort execution of the rest of the API handling microflow when validations fail.
  • Manipulate the status code and response directly in the HTTP response object that was provided as a parameter. It is recommended that you return a 401 Unauthorized in cases where authentication fails and a 403 Forbidden in cases where the authentication was successful, but the provided credentials to not grant access to the requested resource or allow the rest of that API operation’s logic to be executed.

By performing your authentication checks in this way, you will have the flexibility of the Custom authentication option described below, but it comes with the lowest performance hit. This is at the expense of losing the user context, which in most scenarios is acceptable for APIs.

Choosing Yes comes with the benefits of having the time zone and language settings available for that API user account. It can also provide better traceability of changes made through API requests. Additionally, it gives the possibility of applying restrictions to requested entities based on the System.User object used for the API account.

Selecting Authentication Option

APIs that do require authentication have either two or three options to fulfill that requirement, based on whether they are Published Web Services or OData/REST endpoints.

All these authentication options will later be combined with the API’s Allowed Roles configuration. Allowed roles can be any of the roles you have defined in User Roles, including the role assigned to Anonymous users.

You can choose one or more of the authentication options described below. If you choose more than one authentication option, they will be checked in the order: Custom -> Username and Password -> Active Session

Authentication Option 1, Username and Password

If you choose this option, the API will expect a Basic auth HTTP request header to be set on each incoming request. The basic auth header format is: "Authorization": "Basic userid:password", where userid:password have been base64 encoded.

This “Authorization” header will be combined with the allowed roles, and checked against the app users, recorded in the System.User entity. Credentials provided in the basic auth header will be checked as follows:

  • for REST and OData – endpoints will only look for accounts that have the attribute WebServiceUser set to “FALSE”

  • for SOAP endpoints – WebServiceUser should be “TRUE”

Authentication Option 2, Active Session

If you choose this option, the API will expect a “X-Csrf-Token” HTTP request header to be set on each incoming request. This authentication option is particularly interesting for custom JavaScript and widget implementations.

The session token can be acquired by calling mx.session.getConfig("csrftoken") in JavaScript. This method call should be used before each API call to prevent cross-site request forgery (CSRF/XSRF).

Authentication Option 3, Custom

If you choose this option, the API passes the HttpRequest including all the attached HTTP request headers to a microflow. These can be used in your microflow to verify the existence of a valid custom Authorization header or other identifier (or identifiers). The microflow returns a System.User object or entity specialization thereof. This can be a new or existing object, based on the content of the HTTP request headers.

This functionality allows you, for example, to contact an external Identity Provider or verify the access to the API endpoint and resource based on scopes and claims encoded in a JWT token.

After the request has been authenticated, the role-based security model of Mendix will be applied to the microflows that are executed as the result of the API endpoint, resources, and paths that have been configured. If Apply entity access has been turned on, the API call will also check for read/write access to the requested entities and attributes before returning any data.

To understand the full authentication flow, take a closer look at Published REST Request Routing.

Limiting API Access through IP Restrictions and Certificates

Additional API security measures can be implemented through the use of IP restrictions and/or certificates, creating a secure bubble of trusted requesting users and systems.

Using the Encryption Module When Storing Sensitive Information

Your application might require sensitive information that should be extra encrypted. These are some examples:

  • Connection information for consumed services (like credentials, service locations, or keys)
  • Personal information (like bank account numbers or social security numbers)

This data is defined within the domain model and stored within the database of your application. To minimize the impact of this information when it is leaked, Mendix recommends storing this data in a (symmetric) encrypted manner. The Encryption module available from the Mendix Marketplace provides a way to encrypt this sensitive information in a database record based on an encryption key that is stored at the Mendix application server.

Using Credentials in Your App

You may need to store sensitive information, such as credentials, in your app. To limit access to this sensitive information, Mendix recommends the following:

  • Credentials are recorded in constants which can be set when your app is deployed—in the Mendix Portal, for example, if you are deploying to Mendix Cloud.

  • The constants should be blank by default (not populated with the credentials) in the app.

    • Values for the constants can be provided during testing by creating a configuration.
  • Only authorized people should be given access to set the constants when the app is deployed. This is done through the app roles and (for Mendix Cloud) the node permissions.

Credentials should not be stored in your database as this means that they are also included in backups. Even if they are encrypted, your app will know the encryption key so that they can be decrypted.

Using a Third-Party Identity Provider

When developing an application, authentication is one of the basic considerations. Even though Mendix comes with a basic authentication mechanism, your application’s security is improved when authentication is delegated to an enterprise grade identity provider like ADFS.

Mendix offers the SAML module that enables your application to be connected with these services.

Your application can gain the following benefits from using an identity provider:

  • User management is centralized (for example within Active Directory), which simplifies the on- and off- boarding of new employees or changed roles
  • The Mendix app does not contain (hashed) passwords
  • Identity providers can add extra layers of security, like two-factor authentication
  • Stronger password policies are applied
  • The user experience is improved by facilitating single sign-on (SSO)

Applying a Strong Password Policy

By default, Mendix forces a strong password policy. The same password policy that is configured in Mendix Studio Pro is also used for apps running in a hosted environment (for example, on test, acceptance, and production).

It is very tempting to simplify the password constraints for development purposes (for example, making it possible to use a single character to login). However, Mendix recommends avoiding this approach so that deployments will continue to force a strong password policy.

The password policy can be set by via the guidelines described in Password Policy.

Renaming the Administrator User

Each application requires power users who should be able to administer technical functions (like configuring SSO). By default, the user who has these capabilities is called MxAdmin and has the Administrator role.

This information can be exploited by an attacker (for example, by trying to guess the password). Even though Mendix will block the user for about 5 minutes after three unsuccessful login attempts, renaming the default MxAdmin user is recommended.

The user name of the administrator can be changed in ’s App Security settings on the Administrator tab.

When deployed to Mendix Cloud, the information about the administrator user name and role is taken into account when using the Change admin password button on the environment. After changing the settings in and redeploying the application, a successful admin password change will trigger the creation of a user in the app with the new name and role.

Using SSL on Consumed Web Services Whenever Possible

Most apps consume (web) services that could be located within an organization itself or at an external third party. When such a service is consumed by an application, your request crosses multiple networks and devices before it reaches its endpoint (the service). A potential attacker in between would be able to read and manipulate the conversation between the application and the service.

By using an SSL connection and adding the public key of the endpoint within your application, you will ensure the following:

  • The conversation between you and the service has not been tampered with
  • The conversation is not readable if it was ever intercepted
  • The identity of your endpoint is confirmed

There are several scenarios possible for protecting your outgoing connections using encryption. These depend on the infrastructure possibilities and protocols used. For more information, see How to Secure Outgoing Connections from Your App.

You can add individual certificates in your app’s settings in . Test, acceptance, and production environments require their certificates to be uploaded to Mendix Cloud (for more information, see Certificates).

Adding HTTP Headers

HTTP headers can add an additional layer of security and help you detect certain attacks. For information on how to add HTTP headers, see the HTTP Headers section in Environment Details.

An example of an attack is when an application is embedded in an iframe. Applications that can be embedded within an iframe can be misused by attackers. By using an overlay, it could trick users into clicking buttons and make them perform actions within the application on their behalf without knowing it. This approach is called clickjacking.

By sending a header to the user’s browser, it can block the use of the Mendix application within an iframe and avoid this type of attack. The header is set by default to block embedding within an iframe. For Mendix Cloud, this can be configured using HTTP Headers in your node’s environment details within the Mendix Portal. If you change this value, you will also need to ensure that SameSite cookies are set to the correct value. See Iframes and Running Apps for more information.

If you are running your Mendix app on Mendix for Private Cloud, you can configure the HTTP headers as part of advanced operator configuration. See the Endpoint (network) Configuration section of Creating a Private Cloud Cluster.

The Mendix Cloud Foundry Buildpack and Mendix Docker Buildpack also provide an option to configure HTTP headers.

If you use a traditional deployment of your Mendix app, using Windows or Linux, you need to set up these headers on the web server in front of your Mendix application server, for example in Microsoft Internet Information Services (IIS).

Maintaining a High Level of App Hygiene

As an application grows in functionality, it also increases the chance of containing logic that could be exploitable for an attacker. Also, over time, vulnerabilities within logic can be discovered. Keeping your app hygiene at a high level will reduce the chances of a vulnerable application.

To keep your app hygiene at a good level, perform the following steps:

  • Remove unused modules, widgets, and Java libraries
  • Remove microflows that are not being used (these appear as warnings in Studio Pro)
  • Avoid using components with known vulnerabilities (like Java or JavaScript libraries)

A good source of known vulnerabilities is the Common Vulnerabilities and Exposures website.

Configuring User Roles and Access

Which users and roles are defined within an application is different per app and app. However, there are some key guidelines to keep in mind when validating the user security:

  • Anonymous access should be disabled if it has no function within the application
    • Some applications have anonymous access enabled, solely to serve a custom login form – this can be replaced by modifying the default login.html within your theme (which will also help the user experience with an improved loading time)
  • Roles managing other user roles should be as strict as possible (configured via User management within the user role options)
  • The role of the app’s administrator user (default MxAdmin) should only be able to create the actual administrative accounts (or configure SSO)

Scanning Uploaded Files for Malicious Content

Security in Mendix does not include scanning files that end-users upload or download from your application for viruses and malware.

To scan uploaded files for malicious content, do one of the following: