CORS, XSS en CSRF met voorbeelden in 10 minuten
Dit artikel zou uw startpunt moeten zijn voor bestaande webbeveiligingsnormen, de meest voorkomende webaanvallen en de methoden om deze te voorkomen. Aan het eind kom je er ook achter hoe en waarom Samy ieders held was (behalve die van Rupert Murdoch, denk ik)
Cross-origin resource sharing, of CORS, is een beveiligingsfunctie van IE10+, Chrome 4+, Firefox 3.5+ of bijna elke browserversie die na 2012 is uitgebracht, behalve Opera Mini.
Wanneer CORS is geconfigureerd op een server die beschikbaar is op domein website.com
, dan moeten bronnen uit dat domein die via AJAX worden opgevraagd, worden gestart vanaf assets die vanuit datzelfde domein worden geserveerd.
Met andere woorden, als we CORS inschakelen op domain-b.com
en deze zo configureren dat alleen GET
verzoeken van domein domain-b.com
zijn toegestaan, dan zal, als u een afbeelding wilt gebruiken die beschikbaar is onder https://domain-b.com/images/example.png
in canvas op uw website die wordt gehost op domain-a.com
, die afbeelding niet worden geladen voor de meeste bezoekers.
Uw door CORS beschermde bronnen zullen nog steeds beschikbaar zijn wanneer ze worden opgevraagd door een tool of browser die CORS policy
niet respecteert.
CORS configuratie
CORS zijn standaard uitgeschakeld, wat betekent dat er geen adequate server handler is die CORS configureert, wat betekent dat u geen toegang kunt krijgen tot bronnen van verschillende oorsprong in uw XHR. In principe, als je niets doet of specifiek CORS alleen voor specifieke domeinen inschakelt, dan zal elk AJAX-verzoek dat probeert toegang te krijgen tot je bronnen worden afgewezen omdat webbrowsers de CORS policy
respecteren.
Dit is de reden waarom je CORS-probleem tegenkomt als je begint met het ontwikkelen van SPA met behulp van VueJS en NodeJS. Uw VueJS applicatie wordt gehost op http://localhost:8080
en wanneer u probeert toegang te krijgen tot NodeJS server applicatie op http://localhost:8000
krijgt u “No Access-Control-Allow-Origin header is present
” omdat dat twee verschillende ORIGINS
zijn (combinatie van PROTOCOL
, HOST
en PORT
).
Coole oplossing voor CORS probleem in VueJS ontwikkelingsmodus is om devServer proxy in uw vue.config.js
bestand als volgt in te stellen:
module.exports = { ... devServer: { proxy: 'http://localhost:8000', }, ...}
Om CORS in productie op te zetten moet u de juiste listener voor OPTIONS
verzoek toevoegen. Die luisteraar moet antwoord 200
sturen met no body
maar met Headers
dat uw gewenste CORS-beleid zal definiëren:
Access-Control-Allow-Origin: https://domain-b.comAccess-Control-Allow-Methods: GET
Voor meer info over hoe CORS te configureren check https://enable-cors.org/index.html, en om dieper in CORS policy
te duiken check https://livebook.manning.com/book/cors-in-action/part-1/
XSS
XSS staat voor Cross Site Scripting en het is een type injectie aanval. Het staat op de 7e plaats in de top 10 van kwetsbaarheden die in 2017 door OWASP zijn geïdentificeerd. Cross site scripting is de methode waarbij de aanvaller kwaadaardig script injecteert in vertrouwde website.(sectie bijgewerkt, bedankt Sandor) Er zijn 3 soorten van dergelijke aanvallen.
- Stored XSS – Kwetsbaarheid afkomstig van onbeschermde en niet gesanitiseerde gebruikersinputs die direct in database worden opgeslagen en aan andere gebruikers worden getoond
- Reflected XSS – Kwetsbaarheid afkomstig van onbeschermde en niet gesanitiseerde waarden uit URL’s die direct in webpagina’s worden gebruikt
- DOM based XSS – Vergelijkbaar met reflected XSS, onbeschermde en niet opgeschoonde waarden van URL’s die direct in webpagina’s worden gebruikt, met dit verschil dat DOM gebaseerde XSS niet eens naar de serverzijde gaat
Aanval
1. Opgeslagen XSS
Hier volgt een voorbeeld van een aanval. De aanvaller komt op uw website en vindt een onbeschermd invoerveld zoals een commentaarveld of een gebruikersnaamveld en voert een kwaadaardig script in in plaats van de verwachte waarde. Daarna, wanneer die waarde moet worden weergegeven aan andere gebruikers zal het kwaadaardige code uitvoeren. Kwaadaardig script kan proberen om toegang te krijgen tot uw account op andere websites, kan betrokken zijn bij DDoS-aanval of iets dergelijks. Visuele weergave (bron geeksforgeeks.org):
2. Reflected XSS
Reflected XSS is een aanval die plaatsvindt wanneer een aanvaller een pagina met een dergelijke kwetsbaarheid ontdekt, bijvoorbeeld:
verwachtte URL: https://mywebpage.com/search?q=javascript
schadelijke URL: https://mywebpage.com/search?q=<script>alert('fortunately, this will not work!')</script>
<body>...<div> showing results for keyword <script> document.write(window.location.href.substr(window.location.href.indexOf('q=') + 2))</script></div>......JavaScript results......</body>
Na ontdekking lokt de aanvaller de gebruiker uit om op een dergelijke schadelijke URL te klikken en voila. Gevoelige gegevens van de gebruiker worden misbruikt.
De levenscyclus van de aanval wordt geïllustreerd in een voorbeeld van geekforgeeks.com:
3. XSS op basis van DOM
Deze soort aanval is hetzelfde als de gereflecteerde aanval, maar met het verschil dat het schadelijke URL
-gedeelte helemaal niet naar de server wordt gestuurd. Voor bovenstaand voorbeeld:
verwachtte URL: https://mywebpage.com/search?q=javascript
kwaadaardige URL (gereflecteerde XSS): https://mywebpage.com/search?q=<script>alert('fortunately, this will not work!')</script>
kwaadaardige URL(DOM-gebaseerde XSS): https://mywebpage.com/search#q=<script>alert('fortunately, this will not work!')</script>
Het verschil zit hem in het teken #
dat wordt gebruikt in plaats van ?
. De browsers sturen het deel van de URL na # niet naar de server, maar geven het direct door aan de client code.
Bescherming
Elke waarde die door de gebruiker kan worden ingevoerd en in uw app wordt gebruikt (hetzij aan de serverzijde hetzij aan de clientzijde) moet worden behandeld als onvertrouwde gegevens en moet daarom worden verwerkt voordat deze wordt gebruikt! Je moet de veiligheid te controleren in uw server app en uw client app, as well!
Zoals blijkt uit de documentatie VueJS door zichzelf string escapes voordat het verkrijgen van de waarde van de variabele. Nieuwere versies van Angular ook ontsnappen strings impliciet, dus als u Vanilla JS, JQuery of soortgelijke moet je implementeren string escape handmatig.
Er zijn drie meest voorkomende benaderingen van de verwerking van niet-vertrouwde gegevens zijn hieronder opgesomd en de ideale methode is afhankelijk van het werkelijke type van het veld dat u nodig hebt om te verwerken.
1. String validatie
Validatie is de methode waarbij de gebruiker definieert set van regels, en eisen onvertrouwde gegevens aan die regels te voldoen alvorens verder te gaan. Deze methode is goed voor nummer waarden, gebruikersnaam, e-mail, wachtwoord en soortgelijke velden met concrete set van syntax regels.
Check voor bestaande bibliotheken voor uw kader alvorens te overwegen om validators schrijven door uw eigen.
2. String escape
Escape methode is nuttig voor gevallen waarin u de gebruiker in staat moet stellen leestekens te gebruiken. Deze methode gaat door de string en zoekt naar speciale tekens, zoals <
>
en vervangt ze door de juiste HTML teken entiteit naam. Hier is een basisfunctie die u zou kunnen gebruiken:
function escapeText(text) { return text.replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"')}
Overnieuw, controleer of er bestaande bibliotheken zijn voordat u uw eigen bibliotheken schrijft.
3. String sanitization
Sanitizing string wordt gebruikt wanneer de gebruiker sommige HTML-tags in zijn commentaar, artikelen of iets dergelijks mag invoeren. De sanitize methode gaat door de tekst en zoekt naar HTML tags die je opgeeft en verwijdert ze. Een van de meest populaire bibliotheken die deze aanpak gebruikt is Google Closure.
Deze methode is resource duur en wordt beschouwd als schadelijk, dus doe meer onderzoek voordat je het kiest.
Web browsers (geen beschikbare bronnen sinds welke versie, IE dit probleem opgelost in 2014.) automatisch ontsnappen URL’s voordat ze naar de server kant en waardoor ze beschikbaar in window.location
object ook, dus 2e en 3e type aanval zijn hier alleen maar om bewust te zijn van hen en om duidelijk te maken dat URL params ook moeten worden behandeld als niet-vertrouwde gegevens.
Voor meer gedetailleerde info over XSS en hoe je je applicatie goed kunt beschermen als je veel onvertrouwde data draait, kijk op OWASP cheatsheet on XSS prevention.
CSRF
Cross site request forgery of CSRF is een type aanval die optreedt wanneer een kwaadaardige website, e-mail, blog, instant message of programma de webbrowser van een gebruiker ertoe brengt een ongewenste actie uit te voeren op een andere vertrouwde site waar de gebruiker is geauthenticeerd. Deze kwetsbaarheid is mogelijk wanneer de browser automatisch autorisatiebronnen, zoals sessiecookies, IP-adres of iets dergelijks meestuurt met elk verzoek.
ATTACK
Stel dat de gebruiker is ingelogd op uw onbeveiligde beurs webapplicatie en dat u ofwel sessiecookies ofwel JWT-cookies gebruikt voor authenticatie. Aanvaller maakt ook gebruik van uw service en is in staat om te controleren hoe uw API werkt. Aanvaller truc gebruiker uit te voeren script (door te klikken op SPAM link in e-mail of iets dergelijks) dat verzoek zal sturen naar uw API https://www.stockexchange.com/users/withdraw?how_much=all&address=MY_ADDRESS
(verschrikkelijke API ontwerp, vraag het niet). Omdat het verzoek wordt uitgevoerd vanuit een browser die authenticatie payload stuurt met elk verzoek, zal uw aandelenbeurs web server de gebruiker succesvol authenticeren en transactie uitvoeren en de misleide gebruiker zal al zijn saldo verliezen zonder zich er zelfs maar bewust van te zijn omdat alles op de achtergrond gebeurde. Visuele weergave (bron miro.medium.com)
BESCHERMING
Gelukkig zijn er eenvoudig te implementeren patronen die deze webaanvallen voorkomen. Een van de meest voorkomende patronen is het gebruik van CSRF token
. In principe is de procedure als volgt:
- Genereer een uniek token voor elk verzoek van de gebruiker, de zogenaamde
CSRF token
. - Bewaar het veilig op de server en stuur het terug naar de gebruiker als payload van het antwoord.
- Bewaar
CSRF token
aan de kant van de client. - Wanneer de gebruiker probeert om een state-changing * verzoek uit te voeren stuur dat
CSRF token
met verzoek als een payload. - Voordat het uitvoeren van dat verzoek op de server controleren of
CSRF token
aanwezig is en het is geldig.
Dit is de makkelijkste manier om CSRF aanval te voorkomen voor alle gebruikers.
Als je alleen te maken hebt met bezoekers die moderne browsers gebruiken, dan kun je vertrouwen op SameSite
attribuut van session cookie.(bedankt Gergely)
Since server’s responses are processable in XHR response, then there is no protection on CSRF attack if your web application is XSS vulnerable!
Voor meer informatie zie de OWASP cheatsheet over CSRF.
BONUS
Korte documentaire over Samy, de auteur van de worm die in 2005 MySpace platlegde door misbruik te maken van het XSS-lek, en die MySpace’s CSRF-verdediging passeerde.
https://youtu.be/DtnuaHl378M
Meer informatie over Samy’s worm
https://samy.pl/myspace/tech.html