CORS, XSS och CSRF med exempel på 10 minuter
Denna artikel bör vara din inkörsport till befintliga standarder för webbsäkerhet, de vanligaste webbattackerna och metoderna för att förhindra dem. I slutet kommer du också att få reda på hur och varför Samy var allas hjälte (utom Rupert Murdochs, antar jag)
Cross-origin resource sharing, eller CORS, är en säkerhetsfunktion i IE10+, Chrome 4+, Firefox 3.5+ eller nästan alla versioner av webbläsare som släppts efter 2012 utom Opera Mini.
När CORS konfigureras på en server som är tillgänglig på domän website.com
måste resurser från den domänen som begärs via AJAX initieras från tillgångar som serveras från samma domän.
Med andra ord, om vi aktiverar CORS på domain-b.com
och konfigurerar den så att den endast tillåter GET
-begäranden från domän domain-b.com
, så om du vill använda en bild som är tillgänglig under https://domain-b.com/images/example.png
i canvas på din webbplats som finns på domain-a.com
, kommer den bilden inte att laddas för de flesta av dina besökare.
Dina resurser som skyddas av CORS kommer fortfarande att vara tillgängliga när de begärs av ett verktyg eller en webbläsare som inte respekterar CORS policy
.
CORS-konfiguration
CORS är inaktiverade som standard, vilket innebär att det inte finns någon lämplig serverhanterare som konfigurerar CORS, vilket innebär att du inte kan få tillgång till resurser från olika ursprung i din XHR. Om du inte gör något eller om du specifikt aktiverar CORS endast för specifika domäner kommer alla AJAX-förfrågningar som försöker komma åt dina resurser att avvisas eftersom webbläsare respekterar CORS policy
.
Detta är anledningen till att du stöter på CORS-problem när du börjar utveckla SPA med hjälp av VueJS och NodeJS. Din VueJS-tillämpning finns på http://localhost:8080
och när du försöker komma åt NodeJS-servertillämpningen på http://localhost:8000
får du ”No Access-Control-Allow-Origin header is present
” eftersom det är två olika ORIGINS
(kombination av PROTOCOL
, HOST
och PORT
).
En enkel lösning på CORS-problemet i VueJS utvecklingsläge är att ställa in devServer-proxy i din vue.config.js
-fil enligt följande:
module.exports = { ... devServer: { proxy: 'http://localhost:8000', }, ...}
För att ställa in CORS i produktionen bör du lägga till lämplig lyssnare för OPTIONS
-förfrågan. Denna lyssnare bör skicka svar 200
med no body
men med Headers
som definierar din önskade CORS-policy:
Access-Control-Allow-Origin: https://domain-b.comAccess-Control-Allow-Methods: GET
För mer information om hur man konfigurerar CORS kontrollera https://enable-cors.org/index.html, och för att dyka djupare i CORS policy
kontrollera https://livebook.manning.com/book/cors-in-action/part-1/
XSS
XSS står för Cross Site Scripting och är en typ av injektion. Den är listad som 7:e av de tio största sårbarheterna som identifierades av OWASP under 2017. Cross site scripting är en metod där angriparen injicerar ett skadligt skript på en betrodd webbplats (avsnittet har uppdaterats, tack Sandor) Det finns tre typer av sådana attacker.
- Stored XSS – Sårbarhet som kommer från oskyddade och inte renodlade användarinmatningar som lagras direkt i databasen och visas för andra användare
- Reflected XSS – Sårbarhet som kommer från oskyddade och inte renodlade värden från webbadresser som används direkt på webbsidor
- DOM-baserad XSS – Liknande som reflected XSS, oskyddade och inte renodlade värden från webbadresser som används direkt på webbsidor, med skillnaden att DOM-baserad XSS inte ens går till serversidan
Attack
1. Stored XSS
Här är ett exempel på en attack. Angriparen kommer in på din webbplats och hittar ett oskyddat inmatningsfält, t.ex. ett kommentarsfält eller ett användarnamnsfält, och skriver in ett skadligt skript i stället för det förväntade värdet. När det värdet sedan visas för andra användare kommer det att exekvera skadlig kod. Det skadliga skriptet kan försöka få tillgång till ditt konto på andra webbplatser, kan vara inblandat i DDoS-attacker eller liknande. Visuell representation (källa geeksforgeeks.org):
2. Reflekterad XSS
Reflekterad XSS är en attack som sker när en angripare upptäcker en sida med en sådan sårbarhet, till exempel:
förväntad URL: https://mywebpage.com/search?q=javascript
Obligatorisk URL: https://mywebpage.com/search?q=javascript
Obligatorisk 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>
Efter upptäckten lockar angriparen användaren att klicka på en sådan skadlig URL och voila. Användarens känsliga data utnyttjas.
Angreppets livscykel illustreras i ett exempel från geekforgeeks.com:
3. DOM-baserad XSS
Den här typen av angrepp är densamma som den reflekterade men med den skillnaden att den skadliga URL
-delen inte skickas till servern alls. Ovanstående exempel:
förväntad URL: https://mywebpage.com/search?q=javascript
skadlig URL (reflekterad XSS): https://mywebpage.com/search?q=<script>alert('fortunately, this will not work!')</script>
skadlig URL (DOM-baserad XSS): https://mywebpage.com/search#q=<script>alert('fortunately, this will not work!')</script>
Differensen ligger i att tecknet #
används i stället för ?
. Webbläsarna skickar inte delen av URL:en efter # till servern så de skickar den direkt till din klientkod.
Skydd
Varje värde som kan anges av användaren och som används i din app (antingen på serversidan eller på klientsidan) bör behandlas som otillförlitliga data och bör därför behandlas innan de används! Du bör göra säkerhetskontroller både i din serverapp och i din klientapp!
Som framgår av dokumentationen så undviker VueJS själv strängar innan värdet hämtas från variabeln. Nyare versioner av Angular undviker också strängar implicit, så om du använder Vanilla JS, JQuery eller liknande bör du implementera string escape manuellt.
Det finns tre vanligaste tillvägagångssätt för behandling av otillförlitliga data som listas nedan och den idealiska metoden beror på den faktiska typen av fältet som du behöver behandla.
1. Strängvalidering
Validering är en metod där användaren definierar en uppsättning regler och kräver att icke-pålitliga data ska uppfylla dessa regler innan man går vidare. Denna metod är bra för talvärden, användarnamn, e-post, lösenord och liknande fält med konkreta syntaxregler.
Kontrollera om det finns befintliga bibliotek för ditt ramverk innan du överväger att skriva egna validatorer.
2. String escape
Escape-metoden är användbar i de fall där du bör ge användaren möjlighet att använda skiljetecken. Denna metod går igenom strängen och letar efter specialtecken, t.ex. <
>
, och ersätter dem med lämpliga HTML-tecknenhetsnamn. Här är en grundläggande funktion som du kan använda:
function escapeText(text) { return text.replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"')}
Again, check for existing libraries before writing your own.
3. String sanitization
Sanitizing string används när användaren tillåts skriva in vissa HTML-taggar i sina kommentarer, artiklar eller liknande. Sanitize-metoden går igenom texten och letar efter HTML-taggar som du anger och tar bort dem. Ett av de mest populära biblioteken som använder detta tillvägagångssätt är Google Closure.
Denna metod är resurskrävande och anses vara skadlig, så gör mer forskning innan du väljer den.
Webbläsare (inga tillgängliga källor sedan vilken version, IE fixade detta problem 2014.) undviker automatiskt webbadresser innan de skickas till serverns sida och gör dem tillgängliga i window.location
-objektet också, så andra och tredje typen av angrepp finns här bara för att vara medveten om dem och för att klargöra att webbadressparametrar också bör behandlas som icke-pålitlig data.
För mer detaljerad information om XSS och hur du skyddar din applikation om du roterar många icke betrodda data, se OWASP Cheatsheet on XSS prevention.
CSRF
Cross site request forgery eller CSRF är en typ av attack som inträffar när en skadlig webbplats, e-post, blogg, snabbmeddelande eller program får en användares webbläsare att utföra en oönskad åtgärd på en annan betrodd webbplats där användaren är autentiserad. Denna sårbarhet är möjlig när webbläsaren automatiskt skickar en auktoriseringsresurs, t.ex. en sessionscookie, IP-adress eller liknande med varje begäran.
ATTACK
Vi antar att användaren är inloggad i din oskyddade webbapplikation för aktiebörser och att du använder antingen sessionscookie eller JWT-cookie för autentisering. Angriparen använder också din tjänst och kan kontrollera hur ditt API fungerar. Angriparen lurar användaren att köra ett skript (genom att klicka på en SPAM-länk i ett e-postmeddelande eller liknande) som skickar en förfrågan till ditt API https://www.stockexchange.com/users/withdraw?how_much=all&address=MY_ADDRESS
(fruktansvärd API-design, fråga inte). Eftersom förfrågan utförs från en webbläsare som skickar autentiseringsuppgifter med varje förfrågan, kommer din webbserver för aktiehandel att autentisera användaren och utföra transaktionen, och den lurade användaren kommer att förlora hela sitt saldo utan att vara medveten om det, eftersom allt hände i bakgrunden. Visuell representation(källa miro.medium.com)
SKYDD
Glckligtvis finns det lätt implementerade mönster som förhindrar dessa webbattacker. Ett av de vanligaste mönstren är användningen av CSRF token
. I princip är förfarandet följande:
- Generera en unik token för varje användares begäran, så kallad
CSRF token
. - Lagra den säkert på servern och skicka tillbaka den till användaren som nyttolast i svaret.
- Lagra
CSRF token
på klientsidan. - När användaren försöker utföra en begäran som ändrar tillståndet* skickas
CSRF token
med begäran som nyttolast. - För att utföra begäran på serversidan kontrollerar du om
CSRF token
finns och om den är giltig.
Det här är det enklaste sättet att förhindra CSRF-attacker för alla användare.
Om du bara har att göra med besökare som använder moderna webbläsare kan du förlita dig på SameSite
-attributet i sessionscookien (tack Gergely)
Då serverns svar kan bearbetas i XHR-svaret, finns det inget skydd mot CSRF-attacker om din webbapplikation är XSS-sårbar!
För att dyka djupare, se OWASP Cheatsheet on CSRF.
BONUS
Kort dokumentärfilm om Samy, författaren till den mask som slog ner MySpace 2005 och som missbrukade XSS-sårbarheten, och som passerade MySpaces CSRF-försvar.
https://youtu.be/DtnuaHl378M
Mer information om Samys mask
https://samy.pl/myspace/tech.html