@@ -56,84 +56,100 @@ There may be times you want to insert a value into JavaScript to process in your
5656
5757``` cshtml
5858@{
59- var untrustedInput = "<\"123\" >";
60- }
59+ var untrustedInput = "<script>alert(1)</script >";
60+ }
6161
62- <div
63- id="injectedData"
64- data-untrustedinput="@untrustedInput" />
62+ <div id="injectedData"
63+ data-untrustedinput="@untrustedInput" />
6564
66- <script >
67- var injectedData = document.getElementById("injectedData");
65+ <div id="scriptedWrite" / >
66+ <div id="scriptedWrite-html5" />
6867
69- // All clients
70- var clientSideUntrustedInputOldStyle =
71- injectedData.getAttribute("data-untrustedinput");
68+ <script>
69+ var injectedData = document.getElementById("injectedData");
7270
73- // HTML 5 clients only
74- var clientSideUntrustedInputHtml5 =
75- injectedData.dataset. untrustedinput;
71+ // All clients
72+ var clientSideUntrustedInputOldStyle =
73+ injectedData.getAttribute("data- untrustedinput") ;
7674
77- document.write(clientSideUntrustedInputOldStyle);
78- document.write("<br />")
79- document.write(clientSideUntrustedInputHtml5);
80- </script>
81- ```
75+ // HTML 5 clients only
76+ var clientSideUntrustedInputHtml5 =
77+ injectedData.dataset.untrustedinput;
8278
83- This will produce the following HTML
79+ // Put the injected, untrusted data into the scriptedWrite div tag.
80+ // Do NOT use document.write() on text sourced from attributes as
81+ // unicode escapes will be unescape in document.write() which can lead to XSS.
82+ document.getElementById("scriptedWrite").innerText += clientSideUntrustedInputOldStyle;
8483
85- ``` html
86- <div
87- id =" injectedData"
88- data-untrustedinput =" < ;" ; 123" ;> ; " />
84+ // Or you can use createElement() to dynamically create document elements
85+ // This time we're using textContent to ensure the data is not unescaped.
86+ var x = document.createElement("div");
87+ x.textContent = clientSideUntrustedInputHtml5;
88+ document.body.appendChild(x);
8989
90- <script >
91- var injectedData = document .getElementById (" injectedData" );
90+ // You can also use createTextNode on an element to ensure data is not unescaped.
91+ var y = document.createElement("div");
92+ y.appendChild(document.createTextNode(clientSideUntrustedInputHtml5));
93+ document.body.appendChild(y);
9294
93- var clientSideUntrustedInputOldStyle =
94- injectedData . getAttribute ( " data-untrustedinput " );
95+ </script>
96+ ```
9597
96- var clientSideUntrustedInputHtml5 =
97- injectedData .dataset .untrustedinput ;
98+ The preceding markup generates the following HTML:
9899
99- document .write (clientSideUntrustedInputOldStyle);
100- document .write (" <br />" )
101- document .write (clientSideUntrustedInputHtml5);
102- </script >
103- ```
100+ ``` html
101+ <div id =" injectedData"
102+ data-untrustedinput =" < ; script> ; alert(1)< ; /script> ; " />
104103
105- Which, when it runs, will render the following:
104+ <div id =" scriptedWrite" />
105+ <div id =" scriptedWrite-html5" />
106106
107- ```
108- <"123">
109- <"123">
110- ```
107+ <script >
108+ var injectedData = document .getElementById (" injectedData" );
111109
112- You can also call the JavaScript encoder directly:
110+ // All clients
111+ var clientSideUntrustedInputOldStyle =
112+ injectedData .getAttribute (" data-untrustedinput" );
113113
114- ``` cshtml
115- @using System.Text.Encodings.Web;
116- @inject JavaScriptEncoder encoder ;
114+ // HTML 5 clients only
115+ var clientSideUntrustedInputHtml5 =
116+ injectedData . dataset . untrustedinput ;
117117
118- @{
119- var untrustedInput = "<\"123\">";
120- }
118+ // Put the injected, untrusted data into the scriptedWrite div tag.
119+ // Do NOT use document.write() on text sourced from attributes as
120+ // unicode escapes will be unescape in document.write() which can lead to XSS.
121+ document .getElementById (" scriptedWrite" ).innerText += clientSideUntrustedInputOldStyle;
121122
122- <script>
123- document.write("@encoder.Encode(untrustedInput)");
124- </script>
125- ```
123+ // Or you can use createElement() to dynamically create document elements
124+ // This time we're using textContent to ensure the data is not unescaped.
125+ var x = document .createElement (" div" );
126+ x .textContent = clientSideUntrustedInputHtml5;
127+ document .body .appendChild (x);
126128
127- This will render in the browser as follows:
129+ // You can also use createTextNode on an element to ensure data is not unescaped.
130+ var y = document .createElement (" div" );
131+ y .appendChild (document .createTextNode (clientSideUntrustedInputHtml5));
132+ document .body .appendChild (y);
128133
129- ``` html
130- <script >
131- document .write (" \u003C\u0022 123\u0022\u003E " );
132134 </script >
135+ ```
136+
137+ The preceding code generates the following output:
138+
139+ ```
140+ <script>alert(1)</script>
141+ <script>alert(1)</script>
142+ <script>alert(1)</script>
133143```
134144
135145> [ !WARNING]
136- > Don't concatenate untrusted input in JavaScript to create DOM elements. You should use ` createElement() ` and assign property values appropriately such as ` node.TextContent= ` , or use ` element.SetAttribute() ` /` element[attribute]= ` otherwise you expose yourself to DOM-based XSS.
146+ > Do *** NOT*** concatenate untrusted input in JavaScript to create DOM elements or use ` document.write() ` on data sourced from attributes.
147+ >
148+ > Use one of the following approaches to prevent code from being exposed to DOM-based XSS:
149+ > * ` createElement() ` and assign property values with appropriate methods or properties such as ` node.textContent= ` or node.InnerText=`.
150+ > * ` document.CreateTextNode() ` and append it in the appropriate DOM location.
151+ > * ` element.SetAttribute() `
152+ > * ` element[attribute]= `
137153
138154## Accessing encoders in code
139155
0 commit comments