HTTP Security Checklist
This entire page is based on web security guidelines from Mozilla Infosec, the HTTP documentation from Mozilla as well as documentation from OWASP. Due to this the content on this page is licensed under CC BY-SA 4.0.
TL:DR; A web server which enforces HSTS will instruct web clients to force HTTPS on all outgoing requests, even if they are towards another domain.
The purpose of HSTS is to protect connecting web clients against downgrade attacks, from HTTPS to HTTP (see: Cloudflare). This could be performed by redirecting the legitimate user from the legitimate HTTPS server to another malicious HTTP (non-TLS) web server.
HSTS protects against this because it is actually a HTTP header which tells the browser to
- 1.Force TLS on all HTTP requests (to HTTPS)
- 2.Perform stricter error handling which regard to TLS
In addition, HSTS requires the web sever to also respond with a
max-ageheader (which must be at least 6 months) which the browser will use to remember for how long HSTS should be used.
Heads up: If a browser connects to your web server with HSTS and you then disable it, the browser will not be able to connect until either (1) 6 months has passed or (2) HSTS is activated again.
Due to this TLS is a pre-requisite to HSTS and TLS must remain enabled at all times!
TL:DR; A web client connecting to a web server, which instructs the client to use X-Frame-Options, will not allow the client to render the web page in an HTTP frame to protect the user from clickjacking attacks when browsing domains.
HTTP frames such as
<iframe>has historically been used with malicious intent through Clickjacking attacks and in order to protect against them X-Frame-Options should be used. The purpose of X-Frame-Options is to prevent this with respect to HTTP frames. The reason this is relevant is that it its otherwise possible to not just render the content of a domain but also change it's appearance.
This makes it possible to make the frame transparent and place it on top of other content. In this manner, a
<button>in the invisible frame which performs, for example, a bank transaction could be aligned on top of another button which the user is compelled to press in the malicious web page.
X-Frame-Options protects against this because, In practice, when a web browser connects to a web server, the server replies with a
X-Frame-OptionsHTTP header which either (1) denies any framing or (2) allows framing but only for the same domain which the web server made the reply for.
TL:DR; A web browser is logged into a website, another website which the user visits may be able impersonate the user and thus perform actions as the user unless a CSRF protection mechanism is implemented.
When a user visits a website and log into their account, the web browser needs to store the something which from which the web server can derive the user's identity from. Often websites uses HTTP cookies to store a Session ID which acts as a representation of that the specific user is currently logged in.
In as long as that cookie exists the web browser will send that cookie to the web server per default in every following request to the domain which the web server is listening to. This creates the perfect scenario to perform a CSRF attack.
Heads up: This attack is not limited to cookies. CSRF attacks could be performed in other conditions where a trust is established between a web browser and a web page.
<form action="<nowiki>http://bank.com/transfer.do</nowiki>" method="POST">
<input type="hidden" name="acct" value="MARIA" />
<input type="hidden" name="amount" value="100000" />
<input type="submit" value="View my pictures" />
To protect against this, the bank website needs to implement CSRF protection. This can be done by several methods such as CAPTCHA or requiring that each Anti-CSRF Tokens.
TL:DR; A web server instructs a web browser to store information in a cookie will not protect from information leakage unless the default configuration is overridden.
HTTP Cookies are stored by web browsers by instruction of the web server. The configuration of how the cookie is accessed by the browser and sent to other web servers is also defined by the web server which sent the instruction, not the browser. As such there are several settings in the configuration which needs to be taken into account.
By default there are no restrictions on how whether cookies can be sent over an unencrypted HTTP connection. Often we only want to transmit the cookie if the connection uses TLS which is exactly what the
securedirective does! It allows the web browser to be instructed to prevent sending the cookie.
document.cookieand steal it unless the
HttpOnlydirective is set.
By default, when the
domaindirective is not set, only the same domain which instructed the web browser to set the cookie can access it. This is most often the preferred usage.
Heads up: By setting the
domain=domain.tlddirective you actually allow all subdomains to domain.tld to access the cookie. If you are not entirely in control of the DNS this usage should be used with caution as malicious.domain.tld would also be able to access the cookie.
By using the
domaindirective, the web browser permits other domains and its subdomains to access a cookie. If you do not want the subdomains to access the cookie, use the
SameSitedirective instructs whether the web browser should send cookies in cross-origin requests. The purpose of the directive is to offer (some) protection against CSRF attacks. The directive can be set to three distinctive values:
SameSitedirective demands that
Secure=trueis also used. The directive will not have any effect otherwise.
- Strict: Will not send the cookie with any cross-origin requests and only sent to same-site requests. If you are on foo.com which has a
<a href="bar.com">link which the user clicks, no cookies will be sent to bar.com. As such this is more suited for high security environments such as bank sites but not your average web page. If facebook.com implements
SameSite=Strictit means that if you have previously logged into Facebook you will be prompted to login again if you arrive from a google search since the Facebook cookie with your login credentials is not sent.
- Lax: Similar to
Strictbut will allow cross-origin HTTP
GETrequests. This means that it would be possible to login to Facebook in the example above with
SameSite=Laxwhen the user clicks on a
<a href="facebook.com">link. Note that
Laxstill does not send cookies for AJAX, iframe, or any other request type except pure HTTP GET requests.
- None: The cookie is sent with any cross-origin request whether it's pure HTTP requests, AJAX, iframe etc.
TL:DR; A web browser which receives a resource with incorrect MIME type will try to identify it in a manner which could be exploited. As a preventive measure, the web browser should be instructed to reject resources with absent or incorrect MIME type.
X-Content-Type-Optionsheader specifies how the web browser should handle resources such as stylesheets and scripts which have either an incorrect MIME type or no explicitly defined MIME type.
The usual behavior when this occurs is that the web browser tries to guess the MIME type in a manner which is implemented differently depending on the browser vendor. By using the header with the
nosniffdirective, the browser is instructed to not load any resources which does not have an explicit MIME type, thereby protecting the end-user against attacks which exploit incorrect MIME type identification.
X-Content-Type-Optionshas only one directive:
nosniff. This means that the header can be regarded as a boolean where the header is either set with the
nosniffdirective or is not set at all.
In this regard, since the web client trusts the reply of the trusted web server, it will trust any content even though it is served by another domain and potentially malicious web server.
TL:DR; A web server which enforces CORS will not accept any script-initiated requests originating from a web client which is connected to a web server on any other domain unless explicitly specified.
The purpose of CORS is to limit malicious cross-domain requests and control how and from where a web server can be accessed by a client running code from a different web server.
Specifically, CORS is only applicable for cross-origin HTTP requests which occurs when all the following conditions are satisfied.
- 1.A non-user initiated request is being sent using scripts such as with AJAX or
- 3.The request (1) destination is towards another domain B.
In the example above, domain B receives a cross-origin request and thus have the ability to allow/deny the request with CORS policies using the
Access-Control-Allow-OriginHTTP header. This will instruct the web client if a content from the domain A (or any domain) is allowed to make request to domain B.
There are two directives which are relevant here,
Heads up: Public key pinning is considered to only be a justifiable option on domains which are among the highest risk levels. With this in regard it is most likely not the first security control to implement.
The idea behind public key pinning is that a web client which, on a regular basis, connects to a given domain should verify not only that the certificate of the domain is signed by a trusted Root Certificate Authority (CA), but also which specific CA.
The purpose of HTTP Public Key Pinning is to protect the client, which has previously visited your site, from communicating with your domains in the event that the CA has changed unexpectedly. While there may be a legitimate reason behind this it may also be a result of a malicious act by an adversary.
HTTP Public Key Pinning can be a powerful tool but it is however not the most popular option as it emphasizes confidentiality and integrity over availability.
Other security features worth looking at
- In case CSP is not implemented or is not supported then X-XSS-Protection should be used in order to protect against [reflected cross-site scripting (XSS)](https://en.wikipedia.org/wiki/Cross-site_scripting#Non-persistent_(reflected)) attacks.