This is the fourth day of my participation in Gwen Challenge
The Web Application Security Checklist
Teo Selenius (authorized)
Little Bear and little Egg
For developers, network security is extremely important. Any code error, dependency bug, or database port exposed to the public network can send you straight to a hot search.
So where can I find detailed guidance on lightning protection? OWASP’s Top 10 list is too short, and it focuses more on bug listing than prevention. By contrast, ASVS is a good list, but it still falls short of the actual requirements.
This list presents 72 practical tips for securing your Web applications from all angles. Everybody look, ready to go into the pit!
1. Threat defense on the browser
1. Use ONLY HTTPS to defend against network attacks
As we all know, a secure application requires that all connections between the browser and the Web server be encrypted. In addition, it is recommended to disable some older cipher suites and protocols. When using HTTPS, it is not enough to encrypt only the “sensitive” parts of a website. Otherwise, an attacker could intercept an unencrypted HTTP request and then fake the response from the server, returning malicious content. Fortunately, HTTPS is currently very easy to do. We can get the certificate for free via Let’s Encrypt, plus CertBot for free renewal.
Moving on to our list, the next one is HSTS, which is closely related to HTTPS.
Use HSTS and preloading to protect users from SSL stripping attacks
The server can use HSTS or Strict Transport Security headers to enforce an encrypted connection. It means you need to always access the site using an HTTPS connection.
HSTS protects against SSL stripping attacks. In a so-called SSL stripping attack, an attacker on the network intercepts the first HTTP request (usually unencrypted) made by a browser and immediately fakes the reply to the request, pretending to be a server and demoting the connection to a plaintext HTTP.
It is worth noting that HSTS only takes effect if the user has successfully accessed the application at least once. To overcome this limitation, submit our website to hstspreload.org so that browsers can hardcode our domain name into the HSTS list.
As follows:
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Copy the code
Warning:
When HSTS is implemented, it will force all network requests to and from the site to be encrypted, and may not be accessible if the site request still contains plain text. So, set a small max-age parameter to debug, and then increase it if everything works. After successful debugging, preload is added, leaving preload on for the last step, since turning it off is cumbersome and painful.
3. Set security cookies to protect users from network attacks
Attach the Secure attribute to cookies. This property prevents cookies from being leaked on (accidental or forced) unencrypted connections.
Set-Cookie: foo=bar; . other options... SecureCopy the code
4. Generate HTML securely to avoid XSS vulnerabilities
To avoid the XSS (Cross-site scripting) vulnerability, there are two approaches:
- A completely static website (such as JavaScript SPA + back-end API). The most effective way to avoid the problem of generating HTML is to not generate HTML at all, as described above, or try the cool NexJS.
- Template engine. For traditional Web applications, most of the HTML is dynamically generated on the backend server from parameters provided. In this case, do not create HTML through string concatenation. The recommended approach is to use template engines such as Twig for PHP, Thymeleaf for Java, Jinja2 for Python, and so on.
Also, it is important that the template engine is configured correctly so that parameters are automatically encoded, and that you do not use any “unsafe” functions that can bypass this encoding. Don’t put HTML in callback functions, attributes (without quotes), href/ SRC, and the like.
5. Use JavaScript safely to avoid XSS vulnerabilities
To avoid XSS (cross-site scripting) vulnerabilities on the JavaScript side, never pass untrusted data into functions or properties of executable code. Common functions or attributes of this type include:
- Eval, setTimeout, setInterval, etc.
- React’s dangerouslySetInnerHTML.
- OnClick, onMouseEnter, onError, etc.
- Href, SRC, etc.
- Location, location. The href, etc.
6. Sandbox untrusted content to avoid XSS vulnerabilities
It is best to avoid untrustworthy content, but often not entirely: the need to obtain HTML remotely for presentation, for example, or to allow users to write with wySIWYG editors, and so on.
To avoid XSS (cross-site scripting) vulnerabilities in these scenarios, clean up the content using DOMPurify first, and then render the content in a sandbox.
Even if a WYSIWYG editor library purports to remove malicious content from HTML, it can still be repurged and sandboxed to further ensure security.
Another common situation is that we want to display ads and other content on the web. In this case, simply using IFrame is not sufficient because the same-Origin policy allows a cross-domain frame to change the URL of the parent frame (our website) to a phishing site. Therefore, remember to use the sandbox property of IFrame to avoid this situation.
7. Adopt content security policies to avoid XSS vulnerabilities
Content security policies (CSP) are good defenses against XSS (cross-site scripting) attacks, click-to-hijack attacks, and so on. So be sure to use it! By default, CSP blocks almost all dangerous operations, so the less additional configuration the better. As follows:
Content-Security-Policy: default-src 'self'; form-action 'self'; object-src 'none'
Copy the code
It allows you to load scripts, styles, images, fonts, and so on, but nothing else, from the source code of your Web application. Most notably, it will prevent the inline script () from running, thus better preventing XSS vulnerabilities.
In addition, the form-action:’self’ directive prevents malicious HTML forms from being created on a website (such as “your session is expired, please enter a password here” form) and submitted to an attacker’s server.
Whatever you do, don’t specify script-src: unsafe inline; if you do, the CSP will become worthless.
Finally, if you are concerned about CSP impacting your production environment, you can deploy in Report-only mode first:
Content-Security-Policy-Report-Only: default-src 'self'; form-action 'self'
Copy the code
8. Set HttpOnly cookies to protect users from XSS attacks
Setting the HttpOnly attribute for cookies prevents them from being accessed by JavaScript code. This setting also makes it harder for hackers to steal Cookie information in the event of a cross-scripting attack. Of course, some cookies that need to be accessed by JavaScript code cannot do this.
Set-Cookie: foo=bar; . other options... HttpOnlyCopy the code
9. For download function, set reasonably to avoid XSS vulnerability
Avoid the XSS vulnerability by setting Content-Disposition: Attachment in the header when providing users with download capabilities. This setting disallows direct rendering of files in the user’s browser, thus avoiding vulnerabilities that can arise from downloading files in HTML or SVG format. As follows:
Content-Disposition: attachment; filename="document.pdf"
Copy the code
If we want to allow certain files (such as PDF) to open in the browser and are sure it is safe to do so, we can omit the header or change the attachment to inline for that type of file.
10, for API response, reasonable Settings to avoid XSS vulnerabilities
Reflective file Download (RFD) attacks are usually implemented by building a URL to download a malicious file from an API. This vulnerability can be defended by returning a Content-Disposition header with a secure file name in the API HTTP response.
11. Utilize the anti-Cross-site request forgery (CSRF) mechanism of existing platforms to avoid CSRF vulnerabilities
To avoid the anti-cross-site request forgery vulnerability, it is important to ensure that the platform we use has anti-cross-site request forgery enabled and that this configuration is working as intended.
12. Verify the state parameter of OAuth authentication to avoid CSRF vulnerability
A type of cross-site request forgery vulnerability related to OAuth authentication is where a hacker inadvertently lets a user log in using his or her account. Therefore, if you are using OAuth authentication, be sure to validate the state parameter.
13. Use HTTP correctly to avoid CSRF vulnerabilities
Do not use HTTP methods other than POST, PUT, PATCH, and DELETE to make data changes. GET requests are generally not included in the anti-cross-site request forgery mechanism.
14. Set the same origin attribute for Cookie to avoid CSRF, XS-Leak and XSS vulnerabilities
Set the SameSite property for cookies. SameSite protects against most cross-site request forgery attacks, as well as many cross-site leaks.
The SameSite property has two modes: lax and strict.
Loose mode protects against most cross-site timing and cross-site request forgery attacks, but not against cross-site request forgery vulnerabilities based on Get requests. As follows:
Set-Cookie: foo=bar; . other options... SameSite=LaxCopy the code
Strict mode protects against this type of Get request-based vulnerability, as well as reflective cross-site scripting vulnerabilities. However, strict mode is not suitable for regular applications because it breaks the authentication link. If a user is already logged into a web site and now wants to open a link to the application on a new page, the new page that opens will not automatically log in for the user. Session cookies are also not sent with requests due to strict schema restrictions. Strict mode Settings are as follows:
Set-Cookie: foo=bar; . other options... SameSite=StrictCopy the code
15. Create a new session ID for each login to prevent session fixation attacks
Session fixation attacks generally occur in the following situations:
-
The attacker injects cookies (such as JSESSIONID=ABC123) into the user’s browser. Don’t worry, attackers have plenty of ways to do this.
-
The user logs in with his credentials and submits JSESSIONID=ABC123 set by the attacker in the login request.
-
The application authenticates cookies and users.
-
At the same time, the attacker with the Cookie can also log in through the identity of the user.
To prevent this, the program needs to create a new session ID to be returned to the user after authentication, rather than validate cookies that may have been tampered with.
16. Name cookies properly to prevent session fixation attacks
Can Cookie naming also affect the security of web applications? Indeed! To name the Cookie as __Host-**, the browser will:
- The Cookie cannot be accessed through unencrypted links to avoid session fixation attacks and other attacks involving Cookie reading and writing.
- Subdomains are not allowed to rewrite the Cookie to prevent attacks from subdomain sites (either compromised or malicious).
The following is an example of this setting:
Set-Cookie: __Host-foo=bar ... other options...Copy the code
17. Set cache-control header to prevent user information from being stolen
Caching is the process of storing visited websites and downloaded files somewhere on your hard drive until someone deletes them manually. By default, browsers cache everything on a page to speed up access and save network bandwidth.
To keep information secure in a public network environment, we need to have an appropriate cache-control header for all HTTP responses, especially for non-public and dynamic content.
The following is an example of this setting:
Cache-Control: no-store, max-age=0
Copy the code
18. Set clear-site-data header to prevent user information from being stolen
Another header that effectively ensures that records are cleared when the user exits is clear-site-data. When the user logs out, the header can be carried in the HTTP request. The browser clears the cache, Cookie, storage, and execution context under the domain name. Most browsers support this header.
The following is an example of this setting:
Clear-Site-Data: "*"
Copy the code
19. Properly handle “exit” to prevent user information from being stolen
After the user logs out, it is important to invalidate the access token and session identifier. This way, even if an attacker gets this information from access history/cache/memory etc, it is no longer valid.
Also, if you have single sign-on, remember to call the single sign-on exit port. Otherwise, since the single sign-on session is still active, the exit will be invalid and the user will automatically log in by clicking “Log in” again.
Finally, get rid of cookies, HTML5 storage, etc., that you might have used. The clear-site-data mentioned above is not yet supported by some browsers, so it’s best to clean it up manually.
20. SessionStorage is used for JavaScript passwords to prevent user information from being stolen by latecomers
SessionStorage is similar to LocalStorage, but is unique to each TAB page and will be cleared automatically after the browser/TAB page is closed.
Note: If you want to synchronize user authorization information between multiple tabs open within the system, you need to synchronize sessionStorage information with events.
21. Do not transmit sensitive information through urls
Urls are not designed to transmit sensitive information. It is displayed on the screen, stored in browser history, easily leaked with referrer headers, recorded in server logs, etc. Therefore, do not pass sensitive information in the URL.
22. Adopt Referrer policy to prevent URL address leakage
By default, when linking from the system to an external web site, the browser sets a header with the Referrer to tell the site where the visit came from. This header contains the entire URL, which can be a bit private.
A Referrer-Policy header can be set in the HTTP response to disallow this default behavior:
Referrer-Policy: no-referrer
Copy the code
23. Set an independent domain name for applications to prevent interference between same-origin applications
If we set up application domain names like www.example.com/app1/ and www.example.com/app2/, it is very dangerous…
Therefore, we need to give each application a separate domain name. So, this kind of circumstance should be set to: https://app1.example.com/ and https://app2.example.com/
Note: Subdomains under the same domain can set cookies for the entire domain. For example, App1.example.com could set a Cookie for example.com, which would also apply to App2.example.com. Allowing cookies to be set for a site sometimes opens the door to vulnerabilities such as session fixation. A list of common suffixes can be used to address this problem. Alternatively, you can prevent the Cookie from being overwritten by its quilt domain name by naming it __Host-.
24. Carefully use CORS (Cross-domain resource sharing)
The browser security model relies heavily on the same origin policy, which prevents cross-domain reading of applications. CORS (Cross-domain resource sharing) is a means to allow websites to access cross-domain resources. So, before you decide to use it, it’s best to find out if you really need it.
25, Limit the sources of requests
If your service at api.example.com needs to be accessed by a GET request from www.example.com, you can specify the following header on the api.example.com service:
Access-Control-Allow-Origin: https://www.example.com
Copy the code
If you have a public service interface (such as a calculator service for JavaScript clients on the Internet), then you can specify a random source:
Access-Control-Allow-Origin: *
Copy the code
If you only want a limited number of domains to access it, you can read the requested Origin header in the program for comparison and post-processing. However, it is recommended to use a ready-made library to operate, do not masturbate, it is easy to make mistakes.
Use the Allow credentials option with caution
By default, cross-domain resource sharing does not have user credentials. However, if you specify the following header on the Web server side, it is allowed to carry:
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Credentials: true
Copy the code
This header combination is quite dangerous. Because it gives cross-domain access to a logged in user and uses that permission to access web site resources. So, if you have to use it, be careful.
27. Verify HTTP method
Minimize the attack surface by allowing only the REQUIRED HTTP methods.
Access-Control-Allow-Methods: GET
Copy the code
28. Use WebSockets reasonably, avoid anti-cross-site request forgery and other vulnerabilities
WebSockets are still a relatively new technology, and there is a risk that technical documentation will use it less. Therefore, it is necessary to do the following when using:
-
Encrypts the connection
Just as we should use https:// instead of http:// and WSS :// instead of ws:// when adopting WebSockets
HSTS also affects WebSockets by automatically upgrading unencrypted WebSocket connections to WSS ://
-
Authenticate the connection
If cookie-based authentication is used and the WebSocket server and the application server are in the same domain name, the existing session can continue to be used in the WebSocket. But be sure to validate the request source!
If it is not cookie-based, you can create a single-use, time-limited authorization token in the system that is bound to the user’s IP to authorize the WebSocket.
-
Validate the connection source
The key to understanding WebSockets is to know that the same origin policy is not valid for them. Any web site that can establish a WebSocket connection with your system can access user information directly when using Cookie authentication. Therefore, the connection source must be identified during the WebSocket handshake. You can verify this by validating the Origin parameter in the request header.
If you want to be doubly safe, you can use the anti-cross-site request forgery token as the URL parameter. Instead of using anti-cross-site request forgery, which is primarily used to provide security for other parts of the application, you need to create a one-time, separate token for each task.
29. Use U2F token or client certificate to protect key users from phishing attacks
If the system is likely to be threatened by a phishing attack, in English, “If there is a possibility that: An attacker creates a fake site to gain the trust of the administrator /CEO or other users to steal their user name, password and verification code. “U2F tokens or client certificates should be used to prevent such attacks, even if the attacker has a user name, password and verification code.
Note: emphasis on phishing protection for ordinary users often bring unnecessary trouble. However, providing one more option is not a bad thing for the end user. It is also necessary to inform users of the dangers of phishing attacks in advance.
30. Protect against cross-site leaks
Cross-site leaks are a series of browser-side channel attacks. This attack allows malicious sites to infer information from users of other Web applications.
Such attacks have been around for some time, but browsers have only recently begun to add targeted prevention mechanisms. Learn more details about this type of attack and the security controls you should take in this article.
2. Server-side threat defense
Secondly, server-side threat defense. The following suggestions are summarized from different aspects of application system, infrastructure, application architecture, application monitoring, and event response:
2.1 Application System
Verify the validity of user input
The most critical aspect of this approach is to validate all user input as strictly as possible. Proper validation makes system vulnerabilities harder to find and exploit. Reject invalid user input without attempting to clean it. Verification aspects include the following:
- Use strict data types. DataTime for dates, Integer for numbers, and so on. Use enumerated types for fixed options. Avoid the string type.
- If strings must be used, at least give a length limit.
- If you must use strings, minimize the number of characters that can be entered.
- If you want to work with JSON, use the JSON schema for validation.
- If you are working with XML, use the XML schema for validation.
Elegant exception processing, avoid technical details leakage
Do not display stack logs or similar debugging information to the end user. The global exception handler is used to process exceptions and display simple error messages to the browser. This makes it harder for attackers to find and exploit vulnerabilities in the system.
Don’t do your own authentication
There are all kinds of problems that can arise when authenticating users: it is not easy to defend against password guessing attacks, user enumeration attacks, to manage password resets, to store user credentials. As complicated as password processing is, we ordinary people should not try it.
Auth0 and similar tools are used for authentication directly, and some widely used, secure software modules are used to implement the communication protocol (OpenID Connect is the most common). If you don’t want to use a third-party identity provider like Auth0, you can build your own service like KeyCloak instead.
Authentication on everything, reduce the attack surface
By default, the application authenticates everything except static resources, exception pages, or logout pages.
35. Use multiple identities
What if someone breaks into the authentication service? If that’s a concern, go straight to multiple authentication (which in human language means you need a cellphone verification code in addition to your password). That way, even if the authentication service is hacked and an attacker can impersonate anyone, there is still no way to know which captcha the phone received.
Avoid unauthorized access to data or functions through strict permission control
Permission control is not an easy task, but there are ways to handle it properly: just remember not to forget to verify user permissions in controller methods, which can lead to user overreach vulnerabilities, including:
- Do not grant access to all controller methods by default.
- Assign access rights to each controller based on user roles.
- Use method-level security controls to limit access to service methods.
- Use a centralized permission management tool to prevent unauthorized access to each record.
- It adopts the architecture combining front-end Web application and background API, and takes permission control for each App and API, not only for the part connected to the Internet.
To further clarify permissions management tools, here are some key points:
- Data records should have fields that can be controlled by permissions, such as
int ownerId
. - An authorized user must have an ID.
- There should be a class that can be used to evaluate the access rights of the user when the ownerId of the data record matches the user ID.
- Based on the above, you can integrate the authorization evaluation classes into the authorization control system of the application platform, such as the PreAuthorize, PostAuthorize, and so on of Spring Security products.
- If more complex permission control is required, a complete ACL system can also be built.
Use appropriate tools and techniques to avoid injection vulnerabilities
The injection class has many and similar vulnerabilities, including SQL injection, HTML injection, XML injection, XPath injection, command injection, SMTP injection, response header injection, and so on. The name is different but the essence is the same, and the corresponding solution is similar:
- Cause: String concatenation is used to build parameterized messages for specific protocols.
- Solution: Use appropriate, secure, off-the-shelf tools to accomplish this task.
I won’t go into too much detail here, but just remember: Whatever your protocol is, keep this in mind. Some common injection-class vulnerabilities are listed below.
Create a secure database query statement to avoid SQL injection vulnerability
To avoid SQL injection vulnerabilities, remember never to concatenate SQL queries with strings yourself. Adopting an object relational mapping framework (ORM) can make development more efficient and application more secure.
If you want to build more fine-grained queries, you can use a lower-level ORM.
If you can’t use ORM, try preprocessed statements, but be careful that these statements are more error-prone than ORM.
Warning:
The ORM framework is not a panacea for two reasons. First, it supports native SQL queries, which are best avoided. Second, ORM frameworks, like any other software, are exposed to bugs from time to time. So, follow the strategy we’ve emphasized over and over again: validate all input, use a Network application firewall (WAF), and keep your software packages up to date, and you’ll be basically safe.
Careful use of the operating system command line, to prevent command injection related vulnerabilities
Do not execute operating system commands if you can avoid them. If it can’t be avoided, it’s best to follow these guidelines:
-
Build commands and their parameters with appropriate libraries/methods. Arguments must be of type list. Do not create commands with separate strings.
-
No need to use the shell to invoke commands.
-
Predefined command parameters. With curl, for example, an attacker can write to a local file system if the user uses -o to specify parameters.
-
Understand how the program executes and validate the parameters accordingly. With curl, you might just want the user to pull from a site, but if he pulls from file:///etc/passwd, it’s dangerous.
-
Think before you act. In the example above, even if to verify the access address is http:// or https:// at the beginning, the attacker can also be launched an agreement at the beginning of the two attacks, such as: http://192.168.0.1/internal_sensitive_service/admin.
-
Again: Really think before you act. Even if you verify DNS to ensure that the command does not contain sensitive Intranet addresses, do you disable the mapping of certain DNS records to 192.168.0.1? If the answer is no, it’s dangerous.
40. Properly configure XML parsers to avoid XML vulnerabilities
The danger of XML as a markup language is that it can access system resources. Some implementations of XSLT even support embedded code. Therefore, it must be handled with great caution.
-
If you can, avoid accepting XML/XSLT from untrusted sources.
-
If you’re passing parameters to XML, XSLT, or XPath, remember to use secure software components rather than string concatenation/formatting.
-
Use mainstream, secure software components to parse XML/XSLT. Do not use the wrong libraries or code to process XML. Also, do not, under any circumstances, attempt to hand-lift a parser such as SAML; it is very error-prone.
-
Configure parsers properly: disable XSLT documents, disable Xinclude, disable document type definitions, disable external entities, and enable DOS protection. The exact configuration will vary as you implement it, but it’s important to do some in-depth research on the parser you choose.
41, use the appropriate class to build URL, avoid URL injection vulnerability
URL injection often occurs when:
flavour = request.getParam("flavour");
url = "https:/api.local/pizzas/" + flavour + "/";
return get(url).json();
Copy the code
If flavour is set to:
../admin/all-the-sensitive-things/
Copy the code
Then the API request will become a https://api.local/admin/all-the-sensitive-things/, isn’t it dangerous?
Again, the solution is to use an appropriate URL-building library to pass parameters to the URL so that the parameters can be properly encoded.
42. Use appropriate classes to build paths to avoid path traversal vulnerabilities
Like URL addresses, if an attacker manages to sneak in somewhere in the path… /.. /.. /, the file path may end up pointing to an unexpected location. To avoid this, create a class that can safely construct the path and verify that the final path is in the desired directory. Avoid using untrusted data in file paths, or better yet, avoid file systems altogether and go straight to the cloud.
Use file systems with caution and accept untrusted content
If you allow users to write to the server’s file system, all sorts of problems can arise. Switch to cloud storage, or use binary BLObs in your database.
If you must access disks, follow these guidelines:
-
Do not let untrusted data affect the internal file path.
-
Save the files in an isolated directory away from Webroot.
-
Before writing to disk, verify that the file content matches the expected format.
-
Set file system permissions properly to prevent writing to unwanted locations.
-
Do not extract compressed packages, such as ZIP, because they can contain any file, including links and paths to anywhere on the system.
Do not dynamically execute code to avoid remote code execution vulnerabilities
Do not use eval or equivalent functions. Find another way to implement code execution. Otherwise, untrusted data will have the potential to make function calls, which will give it the opportunity to execute malicious code on the server.
Reasonable use of serialization, to avoid deserialization vulnerability
Deserialization of untrusted data is dangerous and can easily lead to remote code execution.
-
Do not use serialization if you can avoid it.
-
If an object can be serialized on the server side, it is digitally signed. When you need to deserialize them again, verify the signatures before continuing deserialization.
-
Use mainstream software components and keep them up to date. Many deserialization libraries will always be found to be vulnerable. GSon is a good choice.
-
Use a simple text format, such as JSON, instead of binary. In addition, problematic formats such as XML should be avoided because you need to worry about XML vulnerabilities in addition to deserialization.
-
Validate the serialized object before processing it. For example, with JSON, validate the JSON document against a strict JSON schema before continuing with deserialization.
2.2 Infrastructure
46. Use network Application Firewall (WAF)
Installing a firewall reduces a lot of risk. ModSecurity is a good open source option.
47. Configure the Web server to prevent HTTP desync attacks
HTTP desync, also known as HTTP request smuggling attacks, is when an attacker hijacks HTTP requests sent by random users to the system. Such attacks generally occur when:
-
When a front-end server, such as a load balancer or reverse proxy server, receives a request with header parameters such as Content-Length and Transfer-Encoding, it passes the request unprocessed to the background.
-
The server receiving the request in the background (usually the application server) uses (or is tricked into using) a different mechanism than the front-end server to determine where the HTTP request starts and ends, such as content-Length for the front-end server and transfer-Encoding for the application server.
-
Front-end servers reuse connections to back-end servers;
-
The front-end server uses HTTP/1 (instead of HTTP/2) when connecting to the back-end server.
So how to prevent? Generally based on the product used:
-
Consult the reverse proxy product supplier to ensure that the product has the ability to proactively defend against attacks;
-
Configure the front-end server, using HTTP/2 when connecting with the background;
-
Configure the front-end server to prevent sending HTTP requests from multiple clients using the same connection.
-
Adopt a Network application firewall (WAF) and ensure that it has modules to prevent request smuggling.
48. Use containers
Let the target application run in isolation from other applications. In this way, even if an attack occurs, the attacker does not have permission to access unauthorized files, systems, or network resources. Therefore, it is best to use Kubernetes or a cloud environment to deploy your application. If you must use a server for some reason, you can manually constrain the application with Docker.
49. Use SELinux/AppArmor
Even if an application is run through a container, it still needs to further constrain the application by employing SELinux or AppArmor policies to reduce the threat posed by container vulnerabilities.
50. Use the service account with the least permission
The advantage of this method is that even if the attack event occurs, it can reduce the loss caused by the attack. Again, it’s impossible to list all of them, so here are just a few examples to help you understand:
- Even if you use Docker, or even SELinux/AppArmor, don’t run your app as root. Create a separate account for your application with as few permissions as possible to make it less likely that an attacker will exploit a container or kernel vulnerability.
- If databases are used, ensure that database users in your application have as few permissions as possible to access the database;
- If an API is integrated with your application, make sure your application has as few permissions as possible to access the API.
51. Restrict external network connections
An attacker usually needs to establish a certain backchannel of communication to establish a channel of manipulation or to steal data. In addition, some vulnerabilities also require an external network connection to be discovered and exploited.
Therefore, do not allow applications to access external networks, including DNS. Try running the nslookup www.example.com command on your server. If it succeeds, you are not restricting your external network connections properly. How to deal with such issues generally depends on the infrastructure.
You can disable external TCP, UDP, or ICMP connections in the following ways:
- Gateway firewalls, if available;
- For older servers, use a local firewall (such as iptables or Windows firewall).
- If Docker is used on the server, you can use iptables.
- If Kubernetes is used, the network policy definition can be used.
DNS is a little trickier to handle, and we usually need to allow access to some hosts.
- If you have a local hosts file, it is easy to use any of the above methods to disable DNS completely.
- If not, then you need to configure a private zone in your upstream DNS that restricts access to the specified DNS server at the network layer. This private zone allows access to only a few pre-specified hosts.
Track DNS records to prevent subdomain hijacking
Subdomain name hijacking occurs in the following scenarios:
-
Suppose we have a domain name example.com;
-
For a promotion, we bought another domain name www.my-cool-campaign.com and created an alias mapping from campaign.example.com to www.my-cool-campaign.com;
-
After this promotion, the www.my-cool-campaign.com domain expired;
-
However, the alias mapping from campaign.example.com to www.my-cool-campaign.com still exists;
-
If someone buys the expired domain name, campaign.example.com goes directly to that domain name;
-
If the attacker provides some malicious content under the www.my-cool-campaign.com domain name, it is directly accessible through the campaign.example.com domain name;
So keep an eye on your DNS records. If you need to deal with a number of similar situations, it is highly recommended that you have an automatic monitoring plan.
2.3 architecture
53. Create internal apis to access data sources
You should not place too much trust in web applications that connect to the Internet. For example, it should not be allowed to make direct database connections. Otherwise, when someone cracks the application, the entire database is at risk.
Instead, we should build multi-component architectures, such as:
-
Our application at www.example.com uses Auth0 for authentication.
-
When the application accesses the internal API service api.example.local, it carries the token of the authorized user and puts it in the Authorization of the request header.
-
The API service at api.example.local restricts access based on the user’s token and reads and writes to the database based on the permissions granted.
If a hacker wanted to break into our application today, even if he succeeded, he would not have access to the entire database, but would simply use a user’s token to access the portion of data that the token allows access to.
Internal connections also need to be encrypted and verified
Don’t blindly trust the security of the Intranet. There are many ways to hack it. For access between systems, TLS (HTTPS) is used for encryption. It is best to authenticate connections at both the network and system levels.
Centralized management of sensitive information
Without an appropriate sensitive information management scheme, it is difficult to keep authorization short-term, auditable, and confidential. Therefore, it is recommended to use tools such as HashiCorp Vault to centrally manage passwords, encryption keys, and similar information.
2.4 monitor
Collection, analysis, alarm
Collect logs centrally to a separate system, such as SIEM (Security Information and Event Monitoring System). In this system, the alarm can be given when some events representing vulnerability and attack occur. When a serious threat occurs, relevant personnel can be notified immediately.
57. Collect system security events
Perhaps the most important source of logs is the system itself. When suspicious behavior occurs, the system should be able to raise exceptions, log events, and, if possible, even automatically block users or IP addresses that might cause problems. Common suspicious behaviors include:
- Incorrect validation of input values (for example, trying to enter a value that is not available in the UI)
- Access control errors (for example, trying to access a record that cannot appear in the UI)
- A database syntax error indicates that someone has discovered a vulnerability to SQL injection and needs to act quickly
- XML errors indicate that someone has discovered an XML injection vulnerability or is trying to exploit XXE (XML external Entity) vulnerability
- An error request indicates that a user may have sent a request that was rejected by the application. An example is RequstRejectedException of the Spring framework
- Anti-cross-site request forgery token validation errors generally indicate that someone is trying to find vulnerabilities in the system
58. Collect runtime security logs
Use a runtime security monitoring tool such as Falco to detect abnormal system access. Falco is especially useful if Kubernetes are used. Logs can also be collected and monitored remotely.
59. Collect SELinux/AppArmor logs
If we have a SELinux policy in place to prevent connections to the outside, but the system suddenly makes AN HTTP request to an outside web site, such as BurpCollaborator.net, that needs immediate attention. Or your system tries to access /etc/passwd. In both cases, someone has discovered a flaw in our system.
Collect Web server events
For Web server software, at least access logs and error logs must be collected and sent to the centralized log server. This will help us quickly sort out the timeline when responding to an emergency.
Collect network application firewall (WAF) logs
If you are using a Network Application Firewall (WAF) as recommended above, collect this log as well. But don’t set an alarm for this log, because it will basically receive all kinds of problems from the Internet, and not some of them you don’t need to worry about.
2.5 Event Response
62. Develop a response plan
Once our systems are monitored and hardened, it will be difficult for attackers to quickly locate system vulnerabilities, and even if they are found, we will be able to quickly understand the situation.
But it’s not enough to just know the facts. You also need to prepare for:
- Quickly analyze system logs to learn about the current status and take corresponding measures
- In products such as application firewalls, you can quickly restrict individual URL addresses and parameters
- If necessary, quickly shut down the system
Vi. Development management
Threat model
Think systematically about “what could go wrong” and adjust accordingly. When designing a new system, the earlier you start, the better. When changes are made to the system, go through the process again.
Such as:
Xiao Wang: What if the attacker breaks into our server which is connected to the Internet?
Chen: That’s the end of it!
Xiao Wang: Ok! This means that we have a trust relationship here, and we believe that the server connected to the Internet will not be breached. Can we trust that?
Chen: Not necessarily! There are a hundred ways that our server could be hacked, such as a vulnerability in our code, or a vulnerability in our dependencies, or a vulnerability in the software installed on our Web server.
Xiao Wang: Ok! Then let’s break that bond of trust. What should I do next?
Chen: Let’s break down the system like this: create some internal interfaces to actually access the database, so that the front-end Web server can’t directly access everything in the background.
Xiao Wang: That’s a good idea! What else could possibly go wrong?
Chen: Well, what if a hacker breaks into our Intranet?
Xiao Wang: Then everything will be lost, because the connections between servers on the Intranet are unencrypted.
Chen:…
That’s the threat model, and it doesn’t have to be complicated. Use this approach to identify possible threats to the system.
Source code mandatory review
Use technical controls to prevent code from being submitted to the repository without review by others. This is the foundation of building a secure development environment because it can:
-
If an attacker breaks into a developer’s computer, or if the developer itself attempts to launch an attack, the malicious code cannot be directly migrated into the code base;
-
If a developer’s error leads to the introduction of buggy code, it is likely to be discovered before it is checked by others.
Automated continuous integration pipelines, allowing only simple access
Developers should have the authority to trigger Jenkins builds, and the Jenkins permission configuration should be limited to this and not allow other permissions. A single developer should not be able to introduce arbitrary code during the construction phase. Of course, jenkinsfiles can also be saved in a version management tool if code reviews are mandatory as recommended above.
66. Sign the artifacts
If you are building a container image, you can sign the image as a build step. Store the signing key in a secure place. The build phase requires access to the key, but it is forbidden to store the key with Jenkinsfile in the version management tool. A better approach is to store the key somewhere like a HashiCorp Vault and then pull it at build time.
67. Add static application scanners to the continuous integration pipeline
Use tools like SpotBugs and find-sec-Bugs (or depending on your technology stack) in the continuous integration pipeline. They can help you find known bugs before you deploy your code.
Alternatively, it can be installed as a plug-in for the IDE on the developer’s computer and run the tools to check the code before it is migrated.
Check dependencies at build time to ensure the minimum set of dependencies
Every software package your application relies on is a source of risk. By relying on dependencies, we pull third party code and execute it on our application server, so we have to figure out what package we are relying on and why.
-
Keep the dependency set to a minimum;
-
Only use dependencies that we trust. They must be widely used and well known;
-
Use a build framework to validate dependencies.
In addition, the external connections of application servers are strictly controlled to avoid the existence of back doors.
69. Perform security scans for dependencies
Use the OWASP dependency checking tool to scan for common security problems in dependencies. In addition to the continuous integration pipeline, these tools can also be run in a developer’s development environment.
Continuous integration pipeline for image security scan
If containerization is used, a tool such as Trivy can be used to scan container images for some general vulnerabilities.
Automated deployment and signature verification
Developers can have permission to deploy in production, but the scope should be limited to specific images that have been built and signed in previous phases, rather than direct access to the production server. If you are using Kubernetes, you can verify the signature of the image to be deployed through Notary or the open policy proxy.
72. Set up a security person
A man’s energy is limited. We can’t expect every developer to be proficient in penetration testing or security engineer. Just as you can’t expect all security experts to be good developers. Therefore, it is possible to have a security focused person on the team to communicate with developers and architects to help protect our applications and spread security awareness among the team.
Third, the conclusion
Avoiding vulnerabilities alone is not enough to ensure application security; you must consider the whole picture and proactively defend against them. Here’s a summary of some of the main approaches:
-
Use the latest version of software components to perform risky operations, such as authentication, access control, encryption, database access, or XML parsing, and ensure that these components are configured correctly, such as disabling external entities while XML parsing.
-
Use security controls provided by the platform, such as anti-cross-site request forgery protection.
-
Use security controls provided by Web browsers, such as HSTS, SameSite cookies, and content security policies.
-
Centralize security controls, especially authentication and access control, to avoid omissions such as forgetting to control security on certain controller methods.
-
Use a Web application firewall to prevent application vulnerabilities from being discovered and exploited.
-
Restrict applications by limiting access to files, network, and system resources.
-
Use the threat model to discover threats in the architecture and deal with them accordingly. This includes security control of each developer’s source code at the source code level and front-end Web server security control at the architecture level.
-
Monitor the system and make exception handling plan.
-
Use vulnerability scanners to scan code, images, and dependencies in development and continuous integration environments.
-
Conduct security training for developers, architects, etc., and assign a security person to the team.
If you’re at the end of it, there’s another way to gain more knowledge, but it’s a lot harder than finishing this article. Join us and get stronger!
The road to strength is full of thorns, so the strong are respected