Browser and client-side hardening focuses on enabling and using the security features within a user’s browser. The following settings protect the users of your web applications from their side (client-side/browser), rather than the server-side (the application itself), as with most application security advice.
While I believe that all applications should allow for users to “paste” values into the password field (to allow for the use of password managers), I do not believe that applications should allow browsers to store passwords using the “remember me” feature. I may be forced to eat my words at some point, but until the security of browsers improves, it is my opinion that all passwords should be stored in a password manager.
Another item for browser and client-side hardening is to disable caching for sensitive pages. In the past, I would have advised that if a page is delivered over HTTPS, that it must contain sensitive information, and therefore should not be cached. But now that things have changed, and quite frankly since Troy Hunt has opened my eyes, I believe that all pages of every web application should be delivered over HTTPS, that would prescribe that nothing should ever be cached. With that caveat, I would like to suggest that if a page of your application contains anything sensitive, you should not allow it to be cached. Pages that do not contain sensitive information may be cached for faster retrieval.
HTTPS should be forced on the server AND from within the application. The newest version of TLS (Transport Layer Security) should always be supported, which as of this writing is TLS 1.2. Older versions of encryption that have known vulnerabilities should be disabled unless you have a clear business reason that has been evaluated against the risk of supporting backwards compatibility. As of this writing all versions of SSL (Secure Sockets Layer) and TLS 1.0 should be disabled on all servers.
Security headers are used to tell browsers what to do, in regard to security. They can turn on features, ensure certain data is not accessed, and much more. Below is a brief explanation of many security headers and which settings should be used in general. If you do not have a valid business justification to do otherwise, you should always use these restrictive settings, in order to protect your users.
X-XSS-Protection: Instructs modern browsers to enable the built-in XSS protection (if it was previously disabled) and to block requests that contain an attack (usually a link from a phishing email). This does not block all XSS, but it does block requests from links that are obvious.
X-XSS-Protection: 1; mode=block
Content-Security-Policy (CSP): Naming the sources of your content that comes from outside your site, such as scripts or images. This is important because the first thing many attackers do is call out to other resources in order to do more damage. This can stop or greatly reduce the damage caused by many attacks.
If you have no content from another site (a rare situation), you can use this:
Content-Security-Policy: default-src ‘self’; block-all-mixed-content;
If you do contain content from other sources (most sites do), refer to Scott Helme’s introduction to CSP.
X-Frame-Options: Used to block your website or web app from being framed (an overlay over your webpage, that you do not control). This is not an exhaustive control, but it is enforced by most modern browsers. This should be used in conjunction with CSP above.
X-Frame-Options: SAMEORIGIN (to allow your site to frame itself)
X-Frame-Options: DENY (to block all framing)
X-Content-Type-Options: Tells the browser not to “sniff” the content-type (take an educated guess as to what the content type is), and to rely on the content-type provided by the application. This blocks a specific type of attack using malicious interpretation of the content, and there is rarely a legitimate business reason to not specify the content-type.
Referrer-Policy: when users leave your site to go to another site, your site sends “referrer information”, including the URL of where the user came from. This header strips all subdomain information (which could be sensitive or personal) and sends only the main URL information. https://dev.to/, as opposed to https://dev.to/shehackspurple. This header protects the privacy of your users.
Strict-Transport-Security (HSTS): Forces HTTPS, even if the user tries to connect via HTTP. Always include subdomains.
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Permitted-Cross-Domain-Policies: This header is only required if you have content that you do not want to be reused as content for other sites. This could, for instance, be used by an artist to block other sites from linking their art within another site. This would not stop other sites from downloading the images and serving them as part of the site content, but it would make it more difficult, and it would also be a clear copyright violation. This security header is optional.
Access-Control-Allow-Origin: when using CORS (cross-origin resource sharing), this security header will specify which resources (from another domain) are allowed to be accessed and used by your site. If you are not using CORS you do not need this security header. Note: this should NEVER be set to “*”.
Expect-CT: This is a brand new security header and is not yet supported by all providers. Expect-CT triggers the user’s browser to verify the certificate of your application’s server. As taken from the OWASP Security Headers Project: The Expect-CT header is used by a server to indicate that browsers should evaluate connections to the host emitting the header for Certificate Transparency compliance.
Note: if you allow your certificates to expire or become otherwise non-compliant, this will ensure that user’s browsers refuse connection to your site.
Expect-CT: max-age=86400, enforce, report-uri=”https://myserver/report"
Feature-Policy: This new security header tells modern browsers which features we want to allow for our website. Most websites do not require the use of the microphone, webcam, or gyroscope. Disabling these features for our site means we protect our user if our application was compromised, and also that they are not concerned that we are violating their privacy.
Feature-Policy: camera ‘none’; microphone ‘none’; speaker ‘self’; vibrate ‘none’; geolocation ‘none’; accelerometer ‘none’; ambient-light-sensor ‘none’; autoplay ‘none’; encrypted-media ‘none’; gyroscope ‘none’; magnetometer ‘none’; midi ‘none’; payment ‘none’; picture-in-picture ‘none’; usb ‘none’; vr ‘none’; fullscreen *;
enableVersionHeader: We want to remove this header, which gives attackers extra information that they do not require, such as the version of the programming framework we are using. The example below is for ASP.Net. Removal of this header is different for every framework.
<httpRuntime enableVersionHeader=”false” />
Server: We also want to remove this informational header which shares the operating system our server is running, including the version. This information can be used by an attacker to plan a more targeted attack, and there is no advantage to sharing this information publicly.
Examples of how to disable this on your server this can be found on Scott Helme’s site. It cannot be done programmatically.
I strongly suggest you verify your settings, via any of these sites: https://securityheaders.com, https://www.ssllabs.com and http://hardenize.com. You can also implement these checks in your CI/CD pipeline. For instructions for adding security headers to ASP.Net or .Net CORE, see my blog post on this topic.
I have learned much of this with the help of my DevSlop project team member, Franziska Buehler, and I strongly suggest you read her blog too. She specializes in Web Application Firewalls (WAF), WAF signatures, reverse proxies, and she built a pipeline that automates WAF tuning for our DevSlop project.
Up next in the ‘Pushing Left, Like a Boss’ series: Session Management.