OutSystems Reactive Security: Stop using CRUD actions on the client-side

Samuel Marques
4 min readJul 19, 2022

--

Have you ever found yourself watching the news and reading an article about a new data breach concerning a company that you know? That’s the new daily. Now imagine that this happens in a project that you have developed. This article focuses on how to secure your OutSystems Reactive applications and get a better night’s sleep.

Introduction

OutSystems Reactive brought more data and logic to the client-side, enabling faster performance. Nonetheless, applications have become more vulnerable to security threats.

As you might know, for each and every aggregate and server action on the client-side, there is a REST API method exposed that handles its request. This means that your aggregates, data actions, and server actions are translated into REST web-services by the platform. These same REST endpoints are protected by the screen roles, however, special attention is required when using the Anonymous Role, Registered Role or when multiple roles can access the same screen.

This poses a challenge when validating your data. Not only do you need to validate it on the client-side, but also re-validate everything again on the server-side.

In this article, I will guide you through multiple best practices and explain why you shouldn’t use CRUD actions on the client-side.

Real-life scenario

Let’s take a look at the following scenario. You have a form and you need to save the form data into the database. Pretty simple right?

What could be the problem with this implementation? Usually, the create or update actions receive, as input parameter, an Entity Record. In this case, the Order_CreateOrUpdate action receives, as input parameter, an Order Record and, returns a OrderId as output parameter. The entity Order has twelve attributes, although the form only has five inputs. Even though we only need to update 5 attributes in the database, the Order_CreateOrUpdate is receiving all 12 attributes. This could lead to unauthorized changes to your data.

Looking at the request in the browser developer console, we can easily see that we are sending far more attributes than we need. The biggest problem is that we can tamper with all the values with ease, and as a result, change data that we shouldn’t be able to change.

Solution

There isn’t a single solution, but, let’s look at one among many. Instead of using the CreateOrUpdate server action, we can create a new server action that only receives the needed fields/data. In the image below, a new server action Order_Save was created and inside it, we use the CreateOrUpdate where we only update the fields we really want.

This new Order_Save action should be created in your BL module and the CreateOrUpdate stays in the CS module. No major business logic should be added to the CS module.

Looking again at the browser developer console, we can verify that now only the needed data is sent to the server-side. In addition to increasing the application security, we are also reducing the request payload.

Tips

  • Protect your reads. Take advantage of the built-in function like GetUserId()¹ and Check<Role>Role¹, you can use them directly on your aggregates. Don’t expose sensitive data on the client-side. Retrieve only the necessary data for the screen.
  • Protect your rights in the database. Please validate that the authenticated user can actually write into the database. Once again, take advantage of the built-in function like GetUserId()¹ and Check<Role>Role¹.
  • Do not rely on data from local/client variables. Double validate your data on the server-side.
  • Fork screens with different functionality per role. It’s more secure and easier to maintain.
  • Consider replacing aggregates with many joins by advanced queries, where only the data/fields you need are fetched from the database. Although OutSystems optimizes aggregates for not retuning data you don’t need, the entire entity structure is returned, exposing your data model and increasing your request payload.

Conclusions

As we saw previously, anyone can use their favorite browser dev tools to inspect and modify JavaScript, check what server requests are being done, and even tamper with those same requests. Being a developer means much more than creating a simple functionality. We need to produce clean and efficient code, perform unit testing, design an application architecture, write technical documentation, think about security aspects and much more. You don’t want to risk developing an application with potential security risks that could see your customer’s data exposed on the internet. I really hope this article helps you to develop more secure applications with OutSystems. Happy coding!

¹ In a server-side context, if you are using the value of the GetUserId() and Check<Role>Role functions, make sure they don’t come from the client-side — e.g., a local or client variable. The main reason for this is that they can be manipulated using tools that alter client-side code in the user’s browser.

Samuel Marques — Tech Lead at DOITLEAN

Thanks to João Barata, Fábio Fantato, and Ian Berry.

--

--