Vorige week schreven we over Internet.nl en de drie controle-punten waar websites op gescoord worden. Een van de onderdelen hiervan, de HTTPS-beveiliging, is dusdanig uitgebreid dat het een eigen artikel waardig is. Want HTTPS, dat is nog niet zo simpel als ‘even een certificaatje installeren’. Er komt nog het een en ander bij kijken om het helemaal op en top veilig te maken, zo blijkt wel uit de resultaten van SecurityHeaders.io.
HTTPS
De werking en techniek achter SSL-verbindingen en HTTPS zijn al eens eerder uitvoerig besproken. De bottom line is dat, stel dat er iemand het verkeer meeluistert tussen jou en de server waarmee je verbonden bent, niet kan zien wat je daadwerkelijk van en naar de server stuurt. Maak je géén gebruik van een beveiligde verbinding, kan een hacker woord voor woord meelezen.
Alleen het instellen van een HTTPS-verbinding doet dan eigenlijk al voldoende. Maar, wil je écht goed bezig zijn, geeft Internet.nl je nog een handige site om te raadplegen: Securityheaders.io
Security Headers
Bij het communiceren tussen browser en server wordt er gebruik gemaakt van zogenaamde HTTP Headers. Dit zijn een soort instructies van de HTTP server met informatie over dingen zoals compressie (verkleinen van gegevens), cache en de server zelf.
Security Headers zijn een bepaald soort HTTP Headers, speciaal gericht op het beveiligings-gedeelte. Hoe gaat een browser om met het benaderen van de website via HTTP(S), iFrames en doorverwijzingen naar andere sites bijvoorbeeld.
Ook SecurityHeaders.io werkt met een scoretabel. A+ is het hoogste, F het laagste. We gaan hier natuurlijk voor minimaal een A en hiervoor houden we rekening met de volgende headers.
Strict-Transport-Security
HSTS (HTTP Strict Transport Security) is eigenlijk niks meer als een automatische upgrade naar HTTPS. Als HSTS aan staat voor een server of domeinnaam, zal al het webverkeer over deze domeinnaam upgradede worden naar HTTPS. Dat scheelt individuele aanpassingen in code voor bijvoorbeeld scripts of plaatjes.
Het instellen van HSTS gebeurt via een .htaccess-bestand of HTTPD-configuratie. Dat gebeurt met de volgende regel:
Header set Strict-Transport-Security "max-age=31536000; includeSubdomains;" env=HTTPS
De max-age
is het aantal seconden dat deze informatie door de browser vastgehouden wordt. Geadviseerd wordt om deze in te stellen op 31536000
(1 jaar) maar in ieder geval hoger te zetten dan 10368000
(120 dagen).
Door includeSubdomains
mee te geven in de header, geeft de server aan dat er niet alleen voor het hoofddomein de upgrade naar HTTPS plaats moet vinden, maar ook voor alle subdomeinen.
X-Frame-Options
Soms wil je iemand te slim af zijn. Je eigen domeinnaam gebruiken, maar op de achtergrond een andere site inladen bijvoorbeeld. ‘Vroeger’ gebeurde dat vaak bij aanbieders van ‘gratis’ websites, bijvoorbeeld WordPress.com. Daarbij krijg je namelijk je eigen subdomein (sitenaam.wordpress.com), maar je wilt natuurlijk je eigen domein in de adresbalk hebben staan. Een simpele iframe is dan een uitkomst.
Door een iframe stuur je namelijk de browser ergens anders heen om daar de inhoud te gaan halen. Dat betekent dat er op de voorgrond (wat wij als bezoekers zien) een website komt, maar dat die op de achtergrond door de browser van een andere server afgehaald wordt.
Is dat een probleem? Ja, en wel om twee redenen.
De eerste is dat er dus misbruik gemaakt kan worden van gratis diensten. In het geval van WordPress bijvoorbeeld krijg je gratis hosting maar enkel met een verwijzing naar WordPress.com in de URL. Als je dat gaat omzeilen door je eigen domeinnaam er voor te zetten, maak je op die manier misbruik van de goedheid van de leverancier. Niet netjes.
Ten tweede zit je met een beveiligings-issue. Stel, iemand laadt jouw site in middels een iframe. Een compleet andere domeinnaam dus, maar wel met jouw website er op. Er draait nu als het ware een kopie van jouw website online. Met die kopie kan een kwaadwillende hacker van alles doen, bijvoorbeeld linkjes aanpassen, formulieren onderscheppen of andere lijpe dingen. Ook niet netjes.
Om het gebruik van iframes voor jouw site of server te voorkomen, kun je de volgende security header toepassen:
Header always set X-Frame-Options "SAMEORIGIN"
Bezoekers van de website die de site via een iframe geserveerd krijgen, zullen nu niets anders zien dan een witte pagina.
X-XSS-Protection
Cross Site Scripting (XSS) wordt door hackers vaak gebruikt. Door legitieme formulieren (denk aan een contactformulier of gastenboek) te bestoken met onveilige inhoud vanuit een andere site, proberen ze op die manier websites te infecteren.
Hier kun je in je eigen websitecode al veel van afvangen, maar browsers helpen hier ook een stukje in mee. Gebruik hiervoor de volgende header:
Header always set X-Xss-Protection "1; mode=block"
X-Content-Type-Options
Niets is wat het lijkt. Vooral niet als je digitaal bezig bent. Een foto lijkt altijd een foto, maar is dat ook zo?
Slimme hackers voegen iets toe aan bestanden en maskeren dan wat het eigenlijk is. Dit is voornamelijk gevaarlijk als de website zelf een optie geeft om bestanden te uploaden. Zo kunnen ze bijvoorbeeld een profielfoto uploaden waarbij de afbeelding niet alleen de daadwerkelijke profielfoto bevat, maar ook een verstopt .exe-bestand (een uitvoerbaar programma).
Als een bezoeker dan het profiel van de hacker bekijkt en de foto door de browser wordt weergegeven, zal de browser zelf kijken en zich afvragen “Wat is dit voor iets?”. De webserver zegt namelijk dat het een plaatje is, maar het bestand zelf zegt misschien wel iets anders. “Ik ben een bestandje, voer mij uit.”
Dat willen we natuurlijk niet hebben en vertellen de browser dus dat hij gewoon moet luisteren naar wat de server aangeeft. Dat gebeurt zo:
Header always set X-Content-Type-Options "nosniff"
Nee, je mag niet meer ruiken (“nosniff”) naar wat het is. Doe maar gewoon wat wij zeggen.
Referrer-Policy
Als je van site naar site hopt, bijvoorbeeld door een link naar een andere site in jouw blogartikel, worden er door de browser ook headers meegestuurd. Het gaat hier dan om de zogenaamde ‘Referrer’, oftewel de ‘waar kom je vandaan’ headers.
Deze referrer-informatie wordt vaak toegepast door de website statistieken software (zoals Google Analytics) om te bepalen hoe bezoekers op je site uitkomen. Maar, misschien wil je wel helemaal niet dat andere website-beheerders kunnen zien dat bezoekers van jouw site naar een andere site gaan, vooral als de site waar naartoe gegaan wordt niet beveiligd is met HTTPS, terwijl je dat zelf bent.
Dit kan je instellen met de volgende Security Header:
Header set Referrer-Policy "no-referrer-when-downgrade"
Content-Security-Policy
Het moderne internet is een wereldwijd netwerk waar miljarden mensen kijken naar en gebruik maken van inhoud die door duizenden of tienduizenden webmasters, programmeurs en designers wordt gepubliceerd. Veel van deze inhoud wordt gedeeld met elkaar, zodat niet iedere webmaster het digitale wiel opnieuw uit hoeft te vinden. Denk aan bekende frameworks zoals Bootstrap (styling), jQuery (JavaScript) en Google Fonts (lettertypen).
Het is dan ook niet vreemd dat een website ook externe bronnen gebruikt. Zo zie je vaak dat een browser de daadwerkelijke inhoud van de website van de server krijgt, maar dat de server vervolgens zegt: “Ga de lay-out maar bij Twitter Bootstrap halen, ik gebruik icoontjes van FontAwesome en voor websitestatistieken moet je even een scriptje bij Google Analytics downloaden.”
Dat is prachtig, maar wie zegt dat we dat ook daadwerkelijk willen? Wat gebeurt er als een hacker op de een of andere manier het voor elkaar heeft gekregen om de server te laten zetten “oh ja, er staat ook nog iets op www.hackercollective.com/hackscript.js, ga dat ook even halen”? Dan doet de browser dat zonder vragen te stellen. En hop, daar gaat je veiligheid.
Door gebruik te maken van een CSP (Content Security Policy) geeft de server aan de browser door welke (externe) links gevolgd mogen worden. En al het andere? Dat valt buiten de boot.
Het instellen van een CSP maakt je website dus des te veiliger, maar hoe doe je dat? Hoe weet je precies vanuit welke bronnen worden ingeladen als je gebruik maakt van WordPress met diverse thema’s en plug-ins? Dan wordt het wel heel lastig.
Een dergelijke Security Policy is dus eigenlijk alleen bruikbaar als je precies weet waar je je inhoud vandaan haalt. Als je alles zelf hebt gemaakt bijvoorbeeld. Of als je, in plaats van gebruik te maken van de servers van Google, jQuery en FontAwesome, de benodigde bestanden eerst download naar je eigen server en ze van daar uit laat serveren.
Als je dat eenmaal op orde is, zou je de volgende header kunnen gebruiken:
Header always set Content-Security-Policy: default-src 'none'; script-src https://domeinnaam.nl
Hiermee zeg je tegen browsers dat alleen inhoud van je eigen domeinnaam.nl via HTTPS ingeladen mogen worden. Al het andere moet lekker buiten de deur blijven.
In het geval van het eerdere screenshot, zou de header-regel er zo uit zien:
Header set Content-Security-Policy "default-src 'self' 'unsafe-inline' 'unsafe-eval' *.bootstrapcdn.com *.googleapis.com *.cloudflare.com *.gstatic.com *.fontawesome.com *.google-analytics.com"
Hiermee geef je voor alle type bestanden (default-src) aan dat ze vanuit het eigen domein (self), in de code (unsafe-inline en unsafe-eval) of vanuit de genoemde domeinnamen mogen komen.
HTTPD.conf of .htaccess?
Al deze headers worden door de webserver meegegeven en kunnen als zodanig op twee plekken ingesteld worden. Ofwel in de configuratie van de webserver zelf (httpd.conf) zodat ze voor alle websites op de server werken, ofwel in het .htaccess bestand van een enkele website. Waar doe je wat?
De enige die website-gebonden is, is de Content-Security-Policy header. Dat is namelijk afhankelijk van welke externe bronnen je gebruikt en dat is weer afhankelijk van de website die je draait. Deze zet je dus in het .htaccess-bestand van de website zelf.
Alle andere headers kunnen goed meegenomen worden in de webserver-configuratie. Gebruik je DirectAdmin? Zet hem dan in /usr/local/directadmin/data/templates/custom/virtual_host2.conf en virtual_host2_secure.conf.
DirectAdmin
Om de serverwijde headers in een keer in te stellen, gebruik je aangepaste templates. Deze vind (of plaats) je in de map /usr/local/directadmin/data/templates/custom/.
cd /usr/local/directadmin/data/templates
cp virtual_host2*.conf custom
cd custom
Met deze drie commando’s ga je eerst naar de templates map, maak je een kopietje van alle vhost-configuratie-files van Apache 2 en ga je ten slotte naar de custom map.
In het VirtualHost blok (boven de ServerName) kun je dan de headers zetten.
Conclusie
Het internet beveiligen is zo makkelijk nog niet. Maar, met dit soort handige sites als Internet.nl en SecurityHeaders.io kom je een heel eind.
Er zijn nog veel meer dingen om te controleren. In volgende artikelen komen deze ook nog aan bod, bijvoorbeeld wat DANE of TLSA nu eigenlijk is en wat het verschil is tussen SSL en TLS en de verschillende versies van TLS. Zo blijven we bezig.
Dit artikel is geplaatst op 09 juli 2018. Het kost je ongeveer 10 minuten om het te lezen.