Update cross-site-scripting.md (#19857)

pull/19860/head
Rick Anderson 2020-09-14 11:45:02 -10:00 committed by GitHub
parent de0c820b87
commit 6d29ce9d75
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 86 additions and 70 deletions

View File

@ -56,84 +56,100 @@ There may be times you want to insert a value into JavaScript to process in your
```cshtml
@{
var untrustedInput = "<\"123\">";
}
var untrustedInput = "<script>alert(1)</script>";
}
<div
id="injectedData"
data-untrustedinput="@untrustedInput" />
<div id="injectedData"
data-untrustedinput="@untrustedInput" />
<script>
var injectedData = document.getElementById("injectedData");
<div id="scriptedWrite" />
<div id="scriptedWrite-html5" />
// All clients
var clientSideUntrustedInputOldStyle =
injectedData.getAttribute("data-untrustedinput");
// HTML 5 clients only
var clientSideUntrustedInputHtml5 =
injectedData.dataset.untrustedinput;
document.write(clientSideUntrustedInputOldStyle);
document.write("<br />")
document.write(clientSideUntrustedInputHtml5);
</script>
```
This will produce the following HTML
```html
<div
id="injectedData"
data-untrustedinput="&lt;&quot;123&quot;&gt;" />
<script>
var injectedData = document.getElementById("injectedData");
var clientSideUntrustedInputOldStyle =
injectedData.getAttribute("data-untrustedinput");
var clientSideUntrustedInputHtml5 =
injectedData.dataset.untrustedinput;
document.write(clientSideUntrustedInputOldStyle);
document.write("<br />")
document.write(clientSideUntrustedInputHtml5);
</script>
```
Which, when it runs, will render the following:
```
<"123">
<"123">
```
You can also call the JavaScript encoder directly:
```cshtml
@using System.Text.Encodings.Web;
@inject JavaScriptEncoder encoder;
@{
var untrustedInput = "<\"123\">";
}
<script>
document.write("@encoder.Encode(untrustedInput)");
</script>
```
This will render in the browser as follows:
```html
<script>
document.write("\u003C\u0022123\u0022\u003E");
var injectedData = document.getElementById("injectedData");
// All clients
var clientSideUntrustedInputOldStyle =
injectedData.getAttribute("data-untrustedinput");
// HTML 5 clients only
var clientSideUntrustedInputHtml5 =
injectedData.dataset.untrustedinput;
// Put the injected, untrusted data into the scriptedWrite div tag.
// Do NOT use document.write() on text sourced from attributes as
// unicode escapes will be unescape in document.write() which can lead to XSS.
document.getElementById("scriptedWrite").innerText += clientSideUntrustedInputOldStyle;
// Or you can use createElement() to dynamically create document elements
// This time we're using textContent to ensure the data is not unescaped.
var x = document.createElement("div");
x.textContent = clientSideUntrustedInputHtml5;
document.body.appendChild(x);
// You can also use createTextNode on an element to ensure data is not unescaped.
var y = document.createElement("div");
y.appendChild(document.createTextNode(clientSideUntrustedInputHtml5));
document.body.appendChild(y);
</script>
```
The preceding markup generates the following HTML:
```html
<div id="injectedData"
data-untrustedinput="&lt;script&gt;alert(1)&lt;/script&gt;" />
<div id="scriptedWrite" />
<div id="scriptedWrite-html5" />
<script>
var injectedData = document.getElementById("injectedData");
// All clients
var clientSideUntrustedInputOldStyle =
injectedData.getAttribute("data-untrustedinput");
// HTML 5 clients only
var clientSideUntrustedInputHtml5 =
injectedData.dataset.untrustedinput;
// Put the injected, untrusted data into the scriptedWrite div tag.
// Do NOT use document.write() on text sourced from attributes as
// unicode escapes will be unescape in document.write() which can lead to XSS.
document.getElementById("scriptedWrite").innerText += clientSideUntrustedInputOldStyle;
// Or you can use createElement() to dynamically create document elements
// This time we're using textContent to ensure the data is not unescaped.
var x = document.createElement("div");
x.textContent = clientSideUntrustedInputHtml5;
document.body.appendChild(x);
// You can also use createTextNode on an element to ensure data is not unescaped.
var y = document.createElement("div");
y.appendChild(document.createTextNode(clientSideUntrustedInputHtml5));
document.body.appendChild(y);
</script>
```
The preceding code generates the following output:
```
<script>alert(1)</script>
<script>alert(1)</script>
<script>alert(1)</script>
```
>[!WARNING]
> 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.
> Do ***NOT*** concatenate untrusted input in JavaScript to create DOM elements or use `document.write()` on data sourced from attributes.
>
> Use one of the following approaches to prevent code from being exposed to DOM-based XSS:
> * `createElement()` and assign property values with appropriate methods or properties such as `node.textContent=` or node.InnerText=`.
> * `document.CreateTextNode()` and append it in the appropriate DOM location.
> * `element.SetAttribute()`
> * `element[attribute]=`
## Accessing encoders in code