Skip to content

Commit 6d29ce9

Browse files
Update cross-site-scripting.md (#19857)
1 parent de0c820 commit 6d29ce9

1 file changed

Lines changed: 71 additions & 55 deletions

File tree

aspnetcore/security/cross-site-scripting.md

Lines changed: 71 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -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="&lt;&quot;123&quot;&gt;" />
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="&lt;script&gt;alert(1)&lt;/script&gt;" />
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\u0022123\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

Comments
 (0)