Frederic Hemberger
<script>alert(1)</script>
<script>
- manipulate the siteʼs appearance
- manipulate cookies, localStorage, etc.
- steal session credentials, tokens, etc.
- load malicious code via XMLHttpRequest
- do whatever the heck you want
</script>
Reflected (non-persistent) XSS attacks:
Usually delivered by other websites or emails
http://example.com/search.php?q=<script>alert(1)</script>
Reflected attacks on client side: DOM XSS
The text content of the search field is displayed unfiltered on the page.
Even <script>alert(1)</script>
Stored (persistent) XSS attacks:
Delivered to every visitor of the site
Just a very small range:
<frameset onload=alert(1)>
<body oninput=alert(1)><input autofocus>
<video poster=javascript:alert(1)//></video>
<!--<img src="--><img src=x onerror=alert(1)//">
<iframe src="data:text/html,<iframe src='data:text/html,%26lt;iframe onload=alert(1)>'>"></iframe>
<img[a][b]src=x[d]onerror[c]=[e]"alert(1)">
<script>alert `1`</script>
X-XSS-Protection: 1; mode=block
Data type validation
String, Number, Boolean, Date, undefined, …
Range and constraint validation
Negative/exponential numbers, String lengths,
"Your age is not 150 years", …
Business logic validation
"You must be at least 14 years old to register"
Obviously not a good idea:
<scr
<script>
ipt>alert(1)</sc
<script>
ri
<script>
pt>
<img src=jAvascript:alert('1')>
»Everybody stand back:
I know Regular Expressions!«
HTML is an irregular language and Regular Expressions
are inadequate for the job.
As seen many times on StackOverflow™
// never, never, NEVER use this!
var el = document.createElement("DIV");
el.innerHTML = '<div>My HTML string</div>';
return el.textContent || el.innerText;
// never, never, NEVER use this! (part 2)
return $('<div/>').html('<div>My HTML string</div>').text();
… use tools like DOM Purify (JS), HTML Purifier (PHP) or
AntiSamy (Java, .NET).
Choose the correct encoding depending on the context
»A test engineer walks into a bar.
Orders a beer.
Orders 999999999 beers.
Orders a lizard.
Orders -1 beers.
Orders a sfdeljknesv.«
Content Security Policy handles unwanted 3rd-party content.
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery.js"></script>
<script src="http://evil.com/evil.js"></script>
</head>
<body>
…
</body>
</html>
# .htaccess
Header always set Content-Security-Policy: ↩
"script-src 'self' http://code.jquery.com"
Loading/executing the script from evil.com is suppressed:
You can specify sources by scheme (data:, https:), hostname (example.com), fully qualified URI (https://example.com:443) or wildcard (*://*.example.com:*)
Warning: 'unsafe-inline' / 'unsafe-eval'
will execute all
inline scripts, including possible XSS vectors.
jQuery CDN, Google web fonts, embedded YouTube videos
Header always set Content-Security-Policy: ↩
"script-src 'self' code.jquery.com; ↩
style-src 'self' http://fonts.googleapis.com; ↩
font-src http://themes.googleusercontent.com; ↩
img-src 'self' data:; ↩
frame-src www.youtube.com;"
Header always set Content-Security-Policy: …↩
report-uri /my/reporting/endpoint
You can also use report-uri.io for CSP data collection
{
"csp-report": {
"document-uri": "http://example.com/signup.html",
"referrer": "",
"blocked-uri": "http://example.com/css/style.css",
"violated-directive": "style-src cdn.example.com",
"original-policy": "…"
}
}
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
25 | 4+ | 10 | 15+ | 6.1+ | 4.4 |
IE < Edge, some Android and/or older browsers may use
»X-Content-Security-Policy« or »X-Webkit-CSP«
Security is always an ongoing effort.
Revise your tools and processes when necessary.