Je site is HTTPS. Dat is niet voldoende.

Ingediend door Dirk Hornstra op 02-oct-2018 21:47

Je hebt meerdere sites om jouw website te controleren. Je hebt dus securityheaders.io, maar ook Mozilla heeft een site om controles uit te voeren: https://observatory.mozilla.org/ 
LET OP: als je je site gaat scannen, zet dan wel even een vinkje bij "Don't include my site in the public results" en "Hide results". Anders komt jouw site met zijn slechte resultaten in het overzicht, dat is wel een beetje de script-kiddies uitdagen om jouw site eens onder handen te nemen.

Ik had werk-gerelateerd al een aantal sites onder handen genomen en was daarbij op een blog-post van Elmah gestuit waarbij securityheaders.io als voorbeeld wordt genomen en je kant-en-klare stukken web.config aangeleverd krijgt. Perfect natuurlijk. Hierbij even de rechtstreekse link: https://blog.elmah.io/improving-security-in-asp-net-mvc-using-custom-headers/

Onderaan deze post plaats ik even deze items, mocht Elmah ooit besluiten om het artikel offline te halen of op een andere manier niet meer te bereiken zijn, dan hebben we in ieder geval hier een back-up :)

Ik kan dit echter niet gebruiken voor mijn site, want mijn site is een PHP site die op Linux draait. No web.config for me. Kan ik dit dan instellen in een .htaccess-bestand? Ik vermoed van wel en een snelle Google-search levert me meteen resultaat: https://htaccessbook.com/increase-security-x-security-headers/

En dat is inderdaad simpel. In mijn .htaccess-bestand plaats ik onderstaande tekst:


<IfModule mod_headers.c>
    Header set X-XSS-Protection "1; mode=block"
    Header set X-Frame-Options SAMEORIGIN
    Header set X-Content-Type-Options nosniff
   # doe alleen includesubdomains als ALLE subdomeinen ook HTTPS zijn. is dat niet het geval en je zet dit aan, dan ben je de sjaak! :$
    #Header set Strict-Transport-Security "max-age=31536000; includeSubDomains"
    Header set Strict-Transport-Security "max-age=31536000; "
    Header set Content-Security-Policy "default-src 'self'"
    Header set Referrer-Policy no-referrer
    Header set Feature-Policy "accelerometer 'none'; camera 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; payment 'none'; usb 'none'"
</IfModule>

Dit werkt. Als ik mijn site opnieuw scan gaat ie van een score F (zeg maar slecht) naar een A+ (helemaal top!). 

Problem solved. Of toch niet.

Want als je dan naar je website gaat zie je dat ie er ineens wel wat vreemd uit ziet. Als je in Google Chrome de <CTRL> en <SHIFT> toets ingedrukt houdt en dan op de letter i drukt, krijg je de console in je browser te zien. Herlaad daarna opnieuw de pagina. Je ziet dan allemaal rode foutmeldingen in je console verschijnen. Je had er namelijk geen rekening mee gehouden dat je jQuery gebruikt (geladen van een externe CDN), je wat met afwijkende lettertypes doet die ook niet lokaal op  je webserver staan. Oftwel, even de regeltjes weghalen en even stuk voor stuk zaken terugzetten en zo aanpassen dat er geen foutmeldingen meer verschijnen. Daarom is het ook aan te raden om eerst een kopietje van je site te maken en het daar in te regelen, zodat je dat rustig kunt doen en niet verontruste klanten aan de lijn krijgt met de vraag of hun website gehackt is ;)

Ik heb aan mijn kant nog wat aangepast. Daardoor ging ik terug naar status A, dat vind ik eerst goed genoeg. Daarmee kreeg ik een "standaard Wordpress" zonder console-foutmeldingen. Enige aanpassing was de volgende:


Header set Content-Security-Policy "default-src 'self' fonts.googleapis.com 'unsafe-inline' fonts.gstatic.com data:"

Tevens draai ik nog een aantal subdomeinen. Omdat ik geen zin/tijd had om die Content-Security-Policy goed te configureren heb ik in de .htaccess in de rootmap van het subdomein het volgende geplaatst:


Header unset Content-Security-Policy

Daarmee draaide het subdomein ook weer naar wens!


INFO
Hierbij de elementen van het blog van Elmah (link). Let wel, deze post is van 15 augustus 2016. Het kan dus zijn dat instellingen wijzigen, browsers andere headers ondersteunen, etc. Neem het dus niet klakkeloos over, maar controleer of je wijzigingen/toevoegingen het gewenste resultaat hebben.

X-Frame-Options
The X-Frame-Options header ensure, that hackers don't iframe your site, in order to trick you into clicking links which you never intended to. If you are using ASP.NET MVC 5 or newer, this header is added automatically. Adding the header in previous versions or other web frameworks is easy using web.config:


<system.webServer>
  <httpProtocol>
    <customHeaders>
      <add name="X-Frame-Options" value="DENY" />
    </customHeaders>
  </httpProtocol>
</system.webServer>

 

In this example, I deny any possibility of iframing the website. If you are using iframes on the same domain, you can change the value to SAMEORIGIN.

X-Xss-Protection
The X-Xss-Protection is a feature implemented in most modern browser, which will stop loading the page when a cross-site scripting attack is detected. Adding the header happens through web.config as well:


<system.webServer>
<httpProtocol>
<customHeaders>
<add name="X-Xss-Protection" value="1; mode=block" />
</customHeaders>
</httpProtocol>
</system.webServer> 

The value if 1 simply marks the protection as enabled.

X-Content-Type-Options
To avoid MIME type sniffing, you can add the X-Content-Type-Options header. This makes it harder for hackers to guess the right mime type, by inspecting the content. Adding the header is easily done through web.config:


<system.webServer>
<httpProtocol>
<customHeaders>
<add name="X-Content-Type-Options" value="nosniff" />
</customHeaders>
</httpProtocol>
</system.webServer>

Referrer-Policy
Browsers automatically add the Referer header, when a user click a link on your site. This means that a linked website, will be able to see where the users are coming from. While this is a great feature for Analytics, you may have sensitive information in your URLs, which you don't want to forward to other domains. To remove the referrer entirely, add the following header to web.config:


<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Referrer-Policy" value="no-referrer" />
</customHeaders>
</httpProtocol>
</system.webServer>

In real life, you may want another value for Referrer-Policy. Removing the referrer entirely, makes it impossible to see the internal traffic flow on your website. Check out Referrer-Policy on mozilla.org for a list of possible values.

X-Permitted-Cross-Domain-Policies
To restrict Flash components to make cross-origin requests, you should disable it entirely (unless you are using Flash of course). To do so, add the X-Permitted-Cross-Domain-Policies to web.config:


<system.webServer>
<httpProtocol>
<customHeaders>
<add name="X-Permitted-Cross-Domain-Policies" value="none" />
</customHeaders>
</httpProtocol>
</system.webServer>

Strict-Transport-Security
If you haven't implemented HTTPS on your website, you should. After doing so, you can prevent any communication happening over HTTP using the Strict-Transport-Security header:


<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Strict-Transport-Security" value="max-age=31536000" />
<!-- doe include subdomains als je ZEKER weet dat je alle subdomeinen zelf in bezit hebt en wilt doorverwijzen
<add name="Strict-Transport-Security" value="max-age=31536000; includeSubDomains" />
-->
</customHeaders>
</httpProtocol>
</system.webServer>

The max-age value tells browsers to use this setting for the specified number of seconds. In this case a year. The includeSubDomains part can be excluded, if you are hosting non-HTTPS websites on subdomains (like a blog).

X-Powered-By
The X-Powered-By header is automatically added by ASP.NET. To make it less obvious which technology you are using to host your website, you should remove this header through web.config:


<system.webServer>
<httpProtocol>
<customHeaders>
<remove name="X-Powered-By" />
</customHeaders>
</httpProtocol>
</system.webServer>

X-AspNetMvc-Version
Much like X-Powered-By, X-AspNetMvc-Version is a header automatically added by the framework. To avoid telling hackers that you use MVC and which version, you should remove it. X-AspNetMvc-Version cannot be removed through web.config, but you can disable it from code. Add the following to your Startup.cs or Global.asax.cs: MvcHandler.DisableMvcResponseHeader = true; Server ASP.NET also reveals the server hosting the application. If a hacker know that you are using IIS, this narrows the number of weaknesses that he/she needs to try. To remove the Server header, remove it from code in either a filter or through Global.asax.cs:


protected void Application_PreSendRequestHeaders() {
    if (HttpContext.Current != null) { HttpContext.Current.Response.Headers.Remove("Server"); }
}

Feature-Policy
The Feature-Policy header, is a recent addition to the range of security-related headers. When specifying the header, you tell the browser which features your site uses or not. This is a great feature, especially if you embed other websites. To add the header, make the following change in web.config:


<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Feature-Policy" value="accelerometer 'none'; camera 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; payment 'none'; usb 'none'" />
</customHeaders>
</httpProtocol>
</system.webServer>

Here, we tell the browser that our site shouldn't allow use of the accelerometer, camera, and more. Which features you need to add, totally depend on your site. For more information, check out the specification.

UPDATE 13 februari 2022:

Feature-Policy wordt niet meer gebruikt, deze is vervangen door Permissions-Policy: link. Content-Security Policy is hier boven niet benoemd, maar is ook goed om mee te nemen: link. Onderstaande inhoud van een basic web.config zorgt voor een HTTPS redirect en geeft momenteel aan A+ score:


<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.web>
        <compilation debug="true" targetFramework="4.8" />
        <httpRuntime targetFramework="4.8" />
    </system.web>
    <system.webServer>   
        <rewrite>
            <rules>
                <rule name="HTTPS afdwingen" stopProcessing="true">
                    <match url="(.*)" />
                    <conditions>
                        <add input="{HTTPS}" pattern="off" ignoreCase="true" />
                    </conditions>
                    <action type="Redirect" url="https://{HTTP_HOST}{REQUEST_URI}" redirectType="Permanent" appendQueryString="true" />
                </rule>
            </rules>
        </rewrite>
        <httpProtocol>
            <customHeaders>
                <remove name="X-Powered-By" />
                <add name="X-Frame-Options" value="DENY" />
                <add name="X-Xss-Protection" value="1; mode=block" />
                <add name="X-Content-Type-Options" value="nosniff" />
                <add name="Referrer-Policy" value="no-referrer" />
                <add name="X-Permitted-Cross-Domain-Policies" value="none" />
                <add name="Strict-Transport-Security" value="max-age=31536000" />
                <add name="Permissions-Policy" value="accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()" />
                <add name="Content-Security-Policy" value="default-src 'self'" />
            </customHeaders>
        </httpProtocol>        
    </system.webServer>
</configuration>