Basic Security Guidelines for Web Applications
Learn why web application security best practices matter and how to protect sensitive data, prevent cyberattacks, and earn users' trust.
Today, most interactions and transactions take place online, and web applications have become indispensable tools for businesses, institutions, and users. However, this reliance on the virtual environment has also brought a growing concern to the forefront: security. Security flaws can result in data breaches, loss of user trust, financial losses, and irreparable damage to a brand's reputation.
As the number of cyberattacks increases, from simple intrusions to more sophisticated threats such as ransomware and social engineering, it is essential for developers, technology managers, and teams responsible for web applications to stay up to date on security best practices. These guidelines help mitigate risks, protect sensitive data, and ensure the continuity and integrity of systems.
Investing in security is not just a technical matter, but a strategic one too. Demonstrating a commitment to protecting user data is a competitive advantage and an essential pillar for the sustainable success of any web application.
This article is based on Mozilla's Web Security document and explores the key guidelines and best practices that should be understood and applied to reduce vulnerabilities and build more secure, reliable applications that meet the expectations of an increasingly connected world.
Web Security Summary
This summary presents essential guidelines for ensuring the security of web applications, ranking each practice according to its importance, implementation difficulty, and priority. See the recommendations below:
| Guideline | Difficulty | Notes |
|---|---|---|
| HTTPS | MEDIUM | All website communications should use HTTPS or equivalent secure protocols. |
| HTTP Redirects | LOW | All websites should automatically redirect to HTTPS. APIs should disable HTTP. |
| LOW | Both passive and active resources should be loaded exclusively over TLS protocols. | |
| HTTP Strict Transport Security (HSTS) | LOW | It should be configured with a minimum duration of six months. |
| TLS Configuration | MEDIUM | Use the most secure TLS configuration, such as Mozilla's recommended "Intermediate" configuration. |
| Content Security Policy (CSP) | HIGH | Recommended for existing websites. Focus on disabling inline scripts for greater protection. |
Read also: How to remove my website from a blacklist
HTTP Strict Transport Security (HSTS)
HTTP Strict Transport Security (HSTS) is an HTTP header that tells browsers to connect to a website only over HTTPS, even if the original scheme is HTTP. Browsers that receive the HSTS setting for a website will automatically upgrade all requests to HTTPS. In addition, HSTS instructs browsers to handle TLS- and certificate-related errors more strictly, preventing users from bypassing the error page.
The HSTS header consists of one required parameter (max-age) and two optional ones (includeSubDomains and preload), separated by semicolons.
Directives
- max-age: Specifies how long browsers should redirect to HTTPS, in seconds.
- includeSubDomains: Indicates whether browsers should upgrade requests to subdomains.
- preload: Allows the website to be included in the HSTS preload list.
The max-age value should be set to a minimum of six months (15768000 seconds). Longer periods, such as two years (63072000 seconds), are recommended. Once configured, the website must continue to support HTTPS until the expiration time is reached.
The includeSubDomains directive tells the browser that all subdomains of the current origin should also be upgraded to HTTPS via HSTS. Take care when enabling this setting, as it may disable websites on subdomains that do not yet have HTTPS enabled.
The preload directive allows the website to be included in the HSTS preload list. Browsers will automatically upgrade connections to HTTPS without needing to receive the initial header. This is recommended for high-risk websites, but also requires includeSubDomains to be configured.
Examples
Connect to the website only over HTTPS for the next two years:
Strict-Transport-Security: max-age=63072000
Connect to the website and its subdomains over HTTPS for the next two years and include them in the preload list:
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
HTTP Redirects
Websites can continue listening on port 80 (HTTP) to prevent users from receiving connection errors when they type a URL in the address bar, since browsers often make the first request over HTTP. However, websites listening on port 80 should redirect to the same resource over HTTPS. After the redirect, HSTS should ensure that all future attempts to access the website over HTTP are sent directly to the secure site.
API endpoints or websites that are not intended for the general public should disable HTTP entirely.
Avoid redirecting from HTTP to HTTPS on a different host, as this prevents HSTS from being configured. For example, use the following flow when redirecting:
- Correct: First redirect from
http://exemplo.com/tohttps://exemplo.com/, then fromhttps://exemplo.com/tohttps://outroexemplo.com/. - Incorrect: Redirect directly from
http://exemplo.com/tohttps://outroexemplo.com/.
Implementation Examples
Redirect all HTTP requests to the same resource over HTTPS using nginx:
server {
listen 80;
return 301 https://$host$request_uri;
}
Redirect requests from http://site.exemplo.org/ to https://site.exemplo.org/ using Apache:
<VirtualHost *:80>
ServerName site.exemplo.org
Redirect permanent / https://site.exemplo.org/
</VirtualHost>
Content Security Policy (CSP)
Content Security Policy (CSP) is an HTTP header that allows website operators to precisely control where their site's resources can be loaded from. Using this header is the best way to prevent cross-site scripting (XSS) vulnerabilities. Because implementing CSP on existing websites can be difficult, it is required for all new websites and strongly recommended for existing high-risk websites.
Primary Benefits
The main benefit of CSP comes from disabling the use of unsafe inline JavaScript. Inline JavaScript, whether reflected or stored, allows poorly escaped user input to generate code that the browser interprets as JavaScript. By using CSP to disable inline JavaScript, it is possible to eliminate almost all XSS attacks against the website.
Note that disabling inline JavaScript means that all JavaScript must be loaded from <script> tags with a src attribute. Event handlers such as onclick used directly in tags will fail, as will JavaScript inside <script> tags without src. In addition, inline styles in <style> tags or in the style attribute will also fail to load. Care must therefore be taken when designing websites to make CSP easier to implement.
Implementation Notes
- Configuring CSP as
default-src https:is a great first goal, as it disables inline code and requires HTTPS. - For existing websites with large codebases that make disabling inline scripts impractical,
default-src https: 'unsafe-inline'is still useful because it prevents resources from loading over HTTP, but it does not provide protection against XSS. - It is recommended to start with a restrictive policy, such as
default-src 'none'; img-src 'self'; script-src 'self'; style-src 'self';, and add sources as needed during testing. - Instead of using the preferred HTTP header, pages can include a
<meta http-equiv="Content-Security-Policy" content="...">tag. If they do, it must be the first<meta>inside the<head>tag. - Be careful with URIs in the
data:format, as they are unsafe inscript-srcandobject-src(or when inherited fromdefault-src). - Avoid using
script-src 'self'on websites with JSONP endpoints. They should specify safe paths to the directories containing the scripts. - If the website does not need to run plugins such as Flash or Silverlight, disable them with
object-src 'none'. - Use the
report-uridirective to receive JSON-formatted reports about CSP violations, allowing them to be fixed quickly.
Before implementation, it is recommended to use the Content-Security-Policy-Report-Only header to monitor potential violations.
Examples
Disable inline code/eval and allow resources only over HTTPS:
Content-Security-Policy: default-src https:
Similar policy using a tag:
<meta http-equiv="Content-Security-Policy" content="default-src https:">
Disable plugins and allow resources from the same origin and images from a specific origin:
Content-Security-Policy: default-src 'self'; img-src 'self' https://i.imgur.com; object-src 'none'
Report violations without enforcing the policy yet:
Content-Security-Policy-Report-Only: default-src https:; report-uri /csp-violation-report-endpoint/
Cross-Origin Resource Sharing (CORS)
The Access-Control-Allow-Origin HTTP header defines which external origins are allowed to access the content of pages on your domain through methods such as XMLHttpRequest. Files such as crossdomain.xml and clientaccesspolicy.xml provide similar functionality for Flash and Silverlight-based applications, respectively.
These files or headers should not be present unless specifically required. Valid use cases include content delivery networks (CDNs) that host JavaScript/CSS libraries and public API endpoints. If present, they should be limited to the minimum number of origins and resources required for proper operation.
For example, if the server provides a website and an API intended to be accessed via XMLHttpRequest from remote websites, only the API resources should return the Access-Control-Allow-Origin header. Failing to follow this practice allows external origins to read the content of any page on your domain.
Examples
Allow any website to read the contents of this JavaScript library so that subresource integrity works:
Access-Control-Allow-Origin: *
Allow only https://dashboard.exemplo.org to read the results returned by this API:
Access-Control-Allow-Origin: https://dashboard.exemplo.org
Allow Flash on https://dashboard.exemplo.org to read page content:
<cross-domain-policy xsi:noNamespaceSchemaLocation="http://www.adobe.com/xml/schemas/PolicyFile.xsd">
<allow-access-from domain="dashboard.exemplo.org"/>
<site-control permitted-cross-domain-policies="master-only"/>
<allow-http-request-headers-from domain="dashboard.exemplo.org" headers="*" secure="true"/>
</cross-domain-policy>
Allow the same for Silverlight:
<?xml version="1.0" encoding="utf-8"?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="*">
<domain uri="https://dashboard.exemplo.org"/>
</allow-from>
<grant-to>
<resource path="/" include-subpaths="true"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
CSRF Prevention (Cross-Site Request Forgery)
Cross-Site Request Forgery (CSRF) attacks are a class of attacks in which unauthorized commands are transmitted to a website from a trusted user. Because these attacks inherit the user's cookies, and therefore session information, they appear to be valid commands. A CSRF attack might look like this:
<!-- Attempt to delete a user's account -->
<img src="https://contas.exemplo.org/gerenciamento/excluir?confirmar=true">
When a user visits a page containing this HTML fragment, the browser will attempt to make a GET request to that URL. If the user is authenticated, the browser will send their session cookies, and the account deletion attempt will succeed.
Although there are several mitigation strategies, such as Origin/Referer checks and challenge-response systems (such as CAPTCHA), the most common and transparent way to mitigate CSRF is by using anti-CSRF tokens. These tokens prevent CSRF attacks by requiring a secret, unique, and unpredictable token to be present for every destructive change. These tokens can be configured for the entire user session, rotated regularly, or created uniquely for each request.
Although SameSite cookies are the best defense against CSRF attacks, they are still not fully supported in all browsers. Therefore, they should be used in conjunction with other anti-CSRF measures.
Examples
A secret anti-CSRF token included in a form to delete an account:
<input type="hidden" name="csrftoken" value="1df93e1eafa42012f9a8aff062eeb1db0380b">
Server sets an anti-CSRF cookie that JavaScript must send as an X header:
Set-Cookie: CSRFTOKEN=1df93e1eafa42012f9a8aff062eeb1db0380b; Path=/; Secure; SameSite=Strict
On the client, JavaScript adds the token as an X-CSRF-Token header in the XMLHttpRequest request:
var token = readCookie('CSRFTOKEN'); // read the cookie
httpRequest.setRequestHeader('X-CSRF-Token', token); // add as an X-CSRF-Token header
Referrer Policy
When a user navigates to a website via a hyperlink or when a website loads an external resource, browsers inform the destination website of the request's origin using the HTTP Referer header (sic). While this can be useful for various purposes, it can also put users' privacy at risk. Referrer Policy gives websites detailed control over how and when browsers transmit the Referer header.
In legacy browsers, if a page at https://exemplo.com/pagina.html contains <img src="https://nao.exemplo.com/imagem.jpg">, the browser will send a request like this:
GET /imagem.jpg HTTP/1.1
Host: nao.exemplo.com
Referer: https://exemplo.com/pagina.html
In addition to privacy risks, the browser may also transmit URLs used internally that were not intended to be disclosed. If you, as the website operator, want to limit exposure of this information, you can use Referrer Policy to remove the Referer header or reduce the amount of information it contains.
Directives
- no-referrer: Never send the
Refererheader. - same-origin: Send the
Refererheader, but only for requests to the same origin. - strict-origin: Send the referrer to all origins, but only the URL without the path (for example,
https://exemplo.com/). - strict-origin-when-cross-origin: Send the full referrer for the same origin and only the URL without the path for external origins.
Notes
- Although there are other referrer policy options, they do not protect user privacy or limit exposure in the same way as the options listed above.
- The strict-origin-when-cross-origin directive is the default behavior in all modern browsers.
- Referrer Policy is well supported by modern browsers. In recent versions of Firefox and Safari, "unsafe" directives (such as
no-referrer-when-downgrade,origin-when-cross-origin, andunsafe-url) behave like thestrict-origin-when-cross-origindefault.
Examples
On exemplo.com, send the Referer header only when loading or linking to other resources on exemplo.com:
Referrer-Policy: same-origin
Send the shortened referrer to an external origin and the full referrer to the local host:
Referrer-Policy: strict-origin-when-cross-origin
Disable referrers for browsers that do not support strict-origin-when-cross-origin:
Referrer-Policy: no-referrer, strict-origin-when-cross-origin
Set the policy with a tag:
<meta http-equiv="Referrer-Policy" content="no-referrer, strict-origin-when-cross-origin">
Set the policy directly on the HTML element:
<a href="https://exemplo.org/" referrerpolicy="no-referrer">
robots.txt
The robots.txt file is a text file placed in a website's root directory to tell robots (such as crawlers used by search engines) how to behave, instructing them not to crawl certain paths on the website. This is particularly useful for reducing the load on a website by disabling the crawling of automatically generated content. It can also help prevent clutter in search results, especially for resources that do not benefit from indexing.
Websites can optionally use robots.txt, but it should only be used for these purposes. It should not be used to prevent the disclosure of private information or to hide parts of a website. Although this prevents such content from appearing in search engines, it does not prevent attackers from discovering it, since the robots.txt file is often used as a reconnaissance source.
Examples
Block all search engines from crawling this website:
User-agent: *
Disallow: /
Attempt to hide certain directories using robots.txt (not recommended):
User-agent: *
Disallow: /secret/admin-interface
Subresource Integrity (SRI)
Subresource Integrity (SRI) is a recent W3C standard that protects against attacks that modify the contents of JavaScript libraries hosted on content delivery networks (CDNs) to create vulnerabilities on all websites that use those libraries.
For example, JavaScript code on jquery.org loaded from example.org has full access to the contents of the example.org website. If this resource is compromised, it can modify download links, deface the website, steal credentials, cause denial-of-service (DoS) attacks, and more.
SRI locks an external JavaScript resource to known content at a specific point in time. If the file is later modified, compatible browsers will refuse to load it. Therefore, SRI is required for all external JavaScript resources loaded from sources not controlled by Mozilla.
Notes
CDNs must support the Cross-Origin Resource Sharing (CORS) standard by setting the Access-Control-Allow-Origin header. Most CDNs already support this, but if the CDN you use does not support CORS, contact the Security Assurance team for support.
Directives
- integrity: A cryptographic hash of the file, preceded by the hash function used to generate it.
- crossorigin: Must be set to
anonymousto tell browsers to send anonymous requests without cookies.
Examples
Load jQuery 2.1.4 from a CDN with SRI enabled:
<script src="/storage/blog/importado/diretrizes-basicas-de-seguranca-para-aplicacoes-web-8d909bb3.js"
integrity="sha384-R4/ztc4ZlRqWjqIuvf6RX5yb/v90qNGx6fS48N0tRxiGkqveZETq72KgDVJCp2TC"
crossorigin="anonymous"></script>
Content-Type Options (X-Content-Type-Options)
The X-Content-Type-Options HTTP header is supported by Internet Explorer, Chrome, and Firefox (starting with version 50) and instructs them not to load scripts and stylesheets unless the server indicates the correct MIME type. Without this header, these browsers may incorrectly detect files as scripts and stylesheets, which can lead to cross-site scripting (XSS) attacks.
Therefore, all websites should set the X-Content-Type-Options header and the appropriate MIME types for the files they serve.
Examples
Prevent browsers from incorrectly detecting files that are not scripts as scripts:
X-Content-Type-Options: nosniff
Frame Options (X-Frame-Options)
The X-Frame-Options HTTP header allows websites to control how they can be embedded in an iframe. Clickjacking is a practical attack that allows malicious websites to trick users into clicking links on your site, even when it appears they are not on your site. Therefore, using the X-Frame-Options header is mandatory for all new websites, and existing sites should add it as soon as possible.
X-Frame-Options has been superseded by the Content Security Policy (CSP) frame-ancestors directive, which offers much more granular control over the origins authorized to embed the site. Since frame-ancestors is still not supported in IE11 and earlier, Edge, Safari 9.1 (desktop), and Safari 9.2 (iOS), websites are advised to use X-Frame-Options in addition to CSP.
Websites that need to be embedded in iframes should use Content Security Policy (CSP) and/or employ JavaScript defenses to prevent clickjacking attacks from malicious origins.
Directives
- DENY: Blocks any attempt to embed the site in iframes (recommended).
- SAMEORIGIN: Allows the site to be embedded in iframes from its own origin.
- ALLOW-FROM uri: Deprecated directive. Use the CSP
frame-ancestorsdirective instead.
Examples
Prevent the site from being embedded using X-Frame-Options and CSP:
Content-Security-Policy: frame-ancestors 'none'
X-Frame-Options: DENY
Allow only the site itself to embed the site:
Content-Security-Policy: frame-ancestors 'self'
X-Frame-Options: SAMEORIGIN
Allow only framer.example.org to embed the site:
Content-Security-Policy: frame-ancestors https://framer.example.org
X-Frame-Options: DENY
Implementing and Verifying Web Application Security
Web application security is an essential component of protecting users' data and privacy. This document presented a comprehensive set of guidelines that, when implemented correctly, help mitigate common risks and vulnerabilities. However, implementing these guidelines is only the first step. Regularly testing and validating these settings is equally crucial to ensure they are working as expected.
To help with the verification process, online tools can analyze your website and provide detailed reports on the implementation of security best practices. Here are some recommendations:
Recommended Security Testing Tools
- Mozilla Observatory
Mozilla Observatory is a robust tool that analyzes your website's security settings, including HTTP security headers, HTTPS, CSP, HSTS, and much more. It provides scores and detailed recommendations to improve security.
Visit here - Security Headers
This free service lets you quickly test your website's security headers, such asX-Content-Type-Options,X-Frame-Options, andContent-Security-Policy. It highlights missing or misconfigured settings and suggests improvements.
Visit here - SERPWorx Security Headers Checker
An alternative that also checks the implementation of security headers on your website, providing clear, practical information about what is correct and what needs to be adjusted.
Visit here - SRI Hash Generator
If your website uses external resources, this tool generates hashes to implement Subresource Integrity (SRI), ensuring that files loaded from CDNs have not been tampered with.
Visit here
Recommended Practices for Regular Testing
- Automate security checks: Use continuous integration tools to run automated tests with every website update.
- Conduct manual audits: Supplementing automated tools with human reviews can help identify more complex issues.
- Educate the team: Ensure developers and operators understand the importance of security guidelines and know how to implement them.
Implementing these measures will not only help protect your systems and users, but also build a strong reputation in the market as a trustworthy organization committed to security. Use these tools regularly to stay ahead of threats and ensure your website remains secure in an ever-evolving threat landscape.