Update cross-site-scripting.md (#19857)
parent
de0c820b87
commit
6d29ce9d75
|
@ -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="<"123">" />
|
||||
|
||||
<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="<script>alert(1)</script>" />
|
||||
|
||||
<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
|
||||
|
||||
|
|
Loading…
Reference in New Issue