Mathias is responsible for ReTest Security web-application security services. He is responsible for advising companies that develop software (DevSecOps) as well as black- and white-box pen testing of applications.
He has been so nice to insert useful sources when relevant.
#1 Use a Web Application Firewall
A basic Web Application Firewall (WAF) is an inexpensive security solution. We would recommend that to anyone who has an application that is accessible on the Internet.
This is a software which analyzes all traffic that is passed through with the aim of blocking malicious traffic. Some WAFs can even block bots and most types of DDoS attempts.
By having a WAF, you protect your application against many of the widespread, automated attacks. Even for an attacker with high technical skills, it will become more difficult to find vulnerabilities in your web application, because a WAF will mean that the attacker will have to spend more time to bypass the protection.
At the same time, the methods the attacker will have to use will more likely lead to you becoming aware of the attack in your logs in real time.
There are many different types of WAFs. Which one suits you best depends on your application, where it will be placed, your budget, and your need for support with the solution.
#2 Leverage Browser Security; Use Security Headers
Modern browsers have several built-in security mechanisms that you can take advantage of when building applications. They are turned on by sending data in some special headers.
Among other things, you can block clickjacking attacks (where the attacker embeds your page in one of his own) by sending the X-Frame-Options header with the value deny. You can also make it so that the browser can only access the encrypted HTTPS pages on the domain, or define that resources from third-party sources that are outside the domain’s policy must not be loaded.
It is generally a very good idea to configure your application to take advantage of the browsers’ security mechanisms by sending the various security headers.
Furthermore, you must also be aware that headers can leak information about an application’s underlying technologies.
Many frameworks and technologies send, by default, a header with this info as well as their full version number. This is useful knowledge for anyone interested in attacking the application, especially if you haven’t updated in time, and it is leaked that the application uses old and vulnerable versions.
OWASP has good guides and resources covering the various security headers:
#3 Reduce your attack surface
The more exposed to the Internet your application is, the higher the chance that there is at least one critical vulnerability that can be found. If an attacker has the opportunity to interact directly with a system, then the attacker more easily gains a great understanding of how the application works.
This is especially true if it is possible to get error messages back from back-end APIs. The information can make the process of finding vulnerabilities more efficient.
Therefore, we recommend reducing the amount of services that you have exposed to the Internet as much as possible, for example by blocking access from all but a few IP addresses. You can also choose to reduce the possibility of interacting directly with your back-end by, for example, using a proxy or using serverless functions to proxy and clean both input and output.
More information about attack surfaces in an IT security context:
#4 Make sure all input gets validated
Most critical vulnerabilities in web applications are injection attacks. They occur when developers allow user-definable data to be used directly in “dangerous” functions. This can lead to remote code execution (RCE), if user-definable data is used in a system call without being cleaned and/or validated.
It can also lead to user-defined HTML being added to the front-end and being run in the user’s browser (cross site scripting (XSS)), as well as allowing the attacker to add more to an SQL query, causing the system to read data from a file that should not otherwise be accessible through the application.
We recommend that all user-definable input be validated before it is allowed to be used in the application. If an input is not correct, then we recommend rejecting the request, unless it is possible to clean up the input in a way that does not affect normal functionality.
Unit tests for various scenarios with valid, incorrect and vulnerable data are a good idea to carry out, to ensure that the input validation works as expected.
More information about input validation can be read here:
#5 Make Communication Between User and Application Confidential
It is important that all information sent over the Internet is confidential. This is achieved by using cryptography so that sensitive information and session keys do not become available to third parties. Therefore, we recommend that all applications you have exposed to the Internet are only accessible over HTTPS.
In some of the encryption methods and protocols supported by HTTPS, there are known vulnerabilities, and there is ongoing development, where some of these are generally not considered secure anymore. It is a good idea to have an ongoing process to remove support for vulnerable protocols and encryption methods. This is if all devices that must be able to use the application have support for using newer secure protocols and methods.
A good tool to help with configuring HTTPS, and a guide to various requirements for HTTPS can be found here:
#6 Design your Rights System According to the “Principle of Least Privileges”
When you design which rights the different user groups should have, we recommend that you follow the “principle of least privileges”. In practice, this means that every user must only have access to the functions and data that the user needs. It requires a little extra thought in the design phase, but improves security considerably.
If a user is entitled to more than necessary, the attack surface is increased when the attacker reaches the relevant user stage. By considering this principle, you can reduce the possibilities that someone can abuse functionality to acquire access to sensitive data, access administrative functionality, or find and exploit vulnerabilities in the functionality. If access is minimized, the risk of ordinary users having access to vulnerable functionality is reduced.
It is also a good idea to consider which user is running the application on the server. It is often this user that the attacker gains access to if he/she finds and exploits a remote code execution vulnerability. If the user has access to the entire system, then the consequences will be great if an attacker gains access to the user.
Further information can be found here:
#7 Set up your cookies securely
This means that it will not be possible to access cookies in the event of a cross site scripting (XSS) attack.
More information about the two parameters can be found here:
#8 Follow a secure software development checklist
Everyday life is busy in any development department. It can be a very good idea to follow an established checklist for secure software development, so that you ensure that you cover the most important areas of application security.
If you are not required to follow a specific list, we would recommend that you follow the OWASP Application Security Verification Standard (ASVS). This is an open-source industry standard for building secure web applications that is built on the experiences of many different organizations.
Since it is not possible to get an official certification that you follow ASVS, it can be easier to make the list fit into your organization – by just picking the advice that you think is the most important for your application.
It can be a big investment if an application has to follow all requirements/controls in ASVS. Therefore, we recommend starting by including it when you develop new functionality. The list is structured according to topics, so that it is possible for the developers to quickly get an overview of which security-relevant considerations can be made regarding new functionality specific to the area of the application that you are developing.
When there is time to focus solely on securing the application, the framework serves as a good checklist to prioritize which security changes need to be made first.
OWASP has divided the requirements into three levels: The first is what they define as minimum requirements for all applications that are secured against “low hanging fruit” vulnerabilities. The second level is what most applications should try to achieve over time. The third level is for safety-critical applications, as well as if the application processes very critical information.
Link to OWASP ASVS: https://owasp.org/www-project-application-security-verification-standard/
#9 Scan your code for vulnerabilities on an ongoing basis
There are many tools that can be used to scan the code for vulnerabilities and general bad practice code . If you do not already use such tools yourself or get it as a service, we would recommend that you include it as part of your CI/CD pipeline. In this way, you reduce the number of potential vulnerabilities that are allowed to enter the production environment.
If you do not have a CI/CD pipeline set up, we recommend that you regularly manually scan the code with the same tools to resolve any vulnerabilities.
Several of the tools appear in this list: https://owasp.org/www-community/Source_Code_Analysis_Tools
#10 Keep your systems up to date
The consequence of running with old software can, in the worst case, be that an attacker gains total control over the application.
We see many web applications that use technologies and frameworks running on outdated versions. This is despite updates/patches being available. It is recommended that you keep the systems updated as frequently as your business processes allow.
If possible, it would be ideal to keep the system updated automatically. Here, a solid testing stage in your CI/CD pipeline can be used to validate that the updates have not destroyed functionality in your application.
If this is not possible, then we would recommend regularly having an employee manually update the application. And then validate that the normal functionality is still working as expected. The last solution typically provides the best cost/benefit for smaller applications/organizations.