The following are recommendations to follow when you develop some aspects of your application in order to avoid some common issues and develop in the most secure way your applications. Is important to review the article Hardening of GeneXus Systems and Deployments with GAM.
Each reality, according to its business rules and logic, will have its own sensitive operations. By activating GAM, it is possible to implement re-authentication to make sure that the user running them is the one logged in and not someone else impersonating him or her.
Access to the operation should be controlled by offering users a prompt or redirection to another panel so that they can re-enter their credentials. The logic of this panel will use the Login() function of the external object GAMRepository with the additional parameter isBatch:
&GAMLoginAdditionalParameters.isBatch = True
// Login User
&LoginOK = GAMRepository.Login(&UserName, &UserPassword, &GAMLoginAdditionalParameters, &Errors)
If not &LoginOK
// Process Error
In the event of an error, do not continue with the redirection to the protected operation; if the validation is made within a procedure where the operation is executed, return immediately.
For more details, read: GAM Login Method
The purpose of subscribing to “GAM Events” is to allow the execution of additional external code after a GAM event has occurred; i.e. customized event handling after GAM's own internal handling. Examples of events are addition/deletion/modification of users and roles.
This is particularly important for alerting users about potentially unauthorized changes to their profile. For this, the developer must implement a procedure that complies with the input and output parameters specified by GAM and according to its logic, alerts users about the updating of their data by the means available, usually by email.
The parameter rule of the procedure should look as follows:
Parm(in:&EventName, in:&jsonIN, out:&jsonOUT);
Then, in the procedure code a variable of GAMUser type can be loaded from the &jsonIN parameter because the corresponding event to subscribe to is User_Update. From there you can obtain the user's email address to send the alert. If it is a false alarm, the user can ignore it.
To record the subscription to a GeneXus program event, you can use the web back office or the GAM API.
For more details, read: GAM Events subscription
Any file that is not generated by the application independently of user-controlled data and is not there since deployment should be considered as unreliable. The upload functionalities of user-provided files such as images, Excel spreadsheets, and PDF documents, among others, can be manipulated to upload other unexpected file types. On one hand, this requires strict validations in the GeneXus code considering allowed extensions. On the other hand, all files must be located outside the root directory of the application.
By default, uploaded files are temporarily stored in the PrivateTempStorage directory, which is not accessible. Later on, their location depends entirely on the loading logic. As for multimedia files, they are often moved to the PublicTempStorage directory where they are publicly accessible. If they are stored through programming in other locations, it is extremely important that the destination directory is separate and restricted.
Ideally, access to static content should be achieved through programming by considering the following:
- The server file system is not accessible via HTTP.
- The access URL does not contain a visible path. Instead, use a complex identifier such as a UUID (Universal Unique Identifier) associated with the file, which allows obtaining the actual path through programming for processing.
- With programmatic control, it is possible to find out if the user is anonymous or registered in the system, to obtain his permissions and confirm that he is authorized to access.
- Use GeneXus’ HTTPResponse object to return the static file, having the file location loaded into a variable:
- Specify the type of content by adding the Content-Type header with its corresponding MIME Type value. For example, if it is a PDF document:
- In the case that the file has to be downloaded, you have to include the following header indicating the filename (it doesn’t have to match the name on the source server):
&HttpResponse.AddHeader(“Content-Disposition”, “attachment;filename=” + &FileName)
- Likewise, it is possible to add headers such as X-Frame-Options or X-Content-Type-Options if they are not automatically added by the server (see “Configuring HTTP headers”).
For more details, read:
Integrated security levels
When you activate GAM in the knowledge base, the default integrated security level is Authentication. This covers access control for all objects so that they cannot be accessed without prior authentication. However, with this level of integrated security, it is not possible to control access on a per role basis; i.e. access is not restricted to users with different roles.
For permission-based access control after authentication, the security level integrated into the object must be changed to Authorization. As a result, access to all roles is denied by default (except for the administrator role) and permissions must be explicitly set for each role, which in turn is assigned to the corresponding users.
The proposal to improve application security consists of configuring the integrated security level to Authorization at the knowledge base level. This causes all objects to have this level, as long as the property has not been modified in any particular object (in which case the modified value is maintained). The improvement here is that the solution is less likely to leave objects unprotected or uncontrolled access based on user permissions, with the cost of setting a permission policy for application roles for each object. To keep the cost down, it is important to take this measure as early in the development as possible. Another benefit is that at the end of this task you will have full knowledge of which objects only require user authentication or must be publicly accessible.
For more details, read: Integrated Security Level property