Prevent Cross-Site Scripting (XSS) Attacks
- 5 minutes to read
During a cross-site scripting (XSS) attack, threat actors inject malicious scripts into web applications. An attacker inputs a value that includes an executable script and the application renders/uses the value later. Each time a user visits the impacted portion of the application, the script executes. To prevent code injection, all user input must be encoded (stripped of executable code).
Encode User Input
DevExtreme-based ASP.NET Core text editors (such as TextBox, Autocomplete, and HtmlEditor) do not encode user input. We highly recommend that you sanitize user input before submitting it to the server:
@using(Html.BeginForm("Action", "Controller", FormMethod.Post, new { onsubmit = "submitForm(event)" })) {
@(Html.DevExtreme().TextBox().ID("text-box"))
@(Html.DevExtreme().Button().UseSubmitBehavior(true).Text("Submit the Form"))
}
<script>
function submitForm(e) {
const editorValue = $("#text-box").dxTextBox("instance").option("value");
// Encode the editorValue with your favorite sanitizing tool before sending this value to the server
// ...
e.preventDefault();
}
</script>
Encode Template Data
ASP.NET Core controls do not encode template content. To encode values in a template, use a third-party sanitizing tool as follows:
@{
var tabs = new[] {
new { id = 0, content = "<img src=1 onerror=alert('XSS') />" },
new { id = 1, content = "<script>alert('XSS')</script>" },
new { id = 2, content = "Tab content" }
};
}
@(Html.DevExtreme().Tabs()
.ID("tabs-container")
.DataSource(tabs)
.SelectedIndex(0)
.ItemTemplate(new JS("myTabs_itemTemplate"))
)
<script>
function myTabs_itemTemplate(itemData) {
const encodedContent = // encode the itemData.content value;
return encodedContent;
}
</script>
Potentially Vulnerable API
Several DevExtreme-based ASP.NET Core components include API members that allow you to insert unencoded HTML. The following sections describe these members and actions you should take to mitigate security-related risks.
CustomizeTooltip()
To customize tooltips in SVG-based components, call the CustomizeTooltip()
method. This method registers a client function that returns tooltip settings. One of returned options is the html
field that specifies formatted content for the tooltip. If the specified HTML string contains JavaScript code, the component will execute it.
To prevent XSS attacks, ensure that the html
field’s value does not contain malicious code. Alternatively, you can replace the html
field with the text
field:
@(Html.DevExtreme().PieChart()
.ID("pie")
.Legend(l => l.Visible(false))
.Series(s => s
.Add()
.ArgumentField("Region")
.ValueField("Val")
)
.Tooltip(t => t
.Enabled(true)
.CustomizeTooltip("myChartAnnotationConfig_customizeTooltip")
)
.DataSource(new[] {
new { Region = "Asia", Val = 4119626 },
new { Region = "Africa", Val = 1012956 },
new { Region = "Northern America", Val = 344124 },
new { Region = "Latin America and the Caribbean", Val = 590946 },
new { Region = "Europe", Val = 727082 },
new { Region = "Oceania", Val = 35104 }
})
)
<script>
function myChartAnnotationConfig_customizeTooltip(arg) {
return {
// html: '<script>alert("XSS")<\/script>'
text: '<script>alert("XSS")<\/script>'
};
}
</script>
EncodeHtml()
The PivotGrid component and columns of DataGrid, Gantt, and TreeList components encode their content and display it as plain text. They also implement the EncodeHtml()
method that allows you to disable built-in HTML encoding. For security reasons, we recommend that you keep encoding enabled.
@{
var products = new[] {
new { ProductID = 1, ProductName = "<img src=1 onerror=alert('XSS') />", UnitPrice = 10},
new { ProductID = 2, ProductName = "<script>alert('XSS') </script>", UnitPrice = 15},
new { ProductID = 3, ProductName = "Product 1", UnitPrice = 9 }
};
}
@(Html.DevExtreme().DataGrid<SampleOrder>()
.ShowBorders(true)
.DataSource(products)
.Columns(columns => {
columns.Add().DataField("ProductID");
columns.Add().DataField("ProductName")/*.EncodeHtml(false)*/;
columns.Add().DataField("UnitPrice");
})
)
Html
DevExtreme-based ASP.NET Core components that contain items (such as List, SelectBox, and Toolbar) allow you to obtain item appearance settings from data source fields. The html
field specifies item markup and is not encoded.
Unlike html
field values, values of the text
field are always encoded. To prevent XSS attacks, use the text
field or ensure that html
field values do not contain malicious code:
@{
var tabs = new[] {
// new { id = 0, html = "<img src=1 onerror=alert('XSS') />" },
// new { id = 1, html = "<script>alert('XSS')</script>" },
// new { id = 2, html = "Tab content" }
new { id = 0, text = "<img src=1 onerror=alert('XSS') />" },
new { id = 1, text = "<script>alert('XSS')</script>" },
new { id = 2, text = "Tab content" }
};
}
@(Html.DevExtreme().Tabs()
.ID("tabs-container")
.DataSource(tabs)
.SelectedIndex(0)
)
MapMarkersTooltipBuilder.Text()
The Map component can display multiple markers with tooltips. You can pass tooltip content to MapMarkersTooltipBuilder.Text method overloads. If you pass an HTML string that contains JavaScript commands, the Map component will execute them.
If you obtain tooltip content from an untrusted source, encode tooltip content as follows:
<script>
var unencodedTooltipText = "<script>alert('XSS')<\/script>";
function encodeValue(unencodedValue) {
const encodedContent = // encode the unencodedValue with your favorite sanitizing tool
return encodedContent;
}
</script>
@(Html.DevExtreme().Map()
.ID("map")
.Provider(GeoMapProvider.Bing)
.ApiKey(k => k.Bing("Aq3LKP2BOmzWY47TZoT1YdieypN_rB6RY9FqBfx-MDCKjvvWBbT68R51xwbL-AqC"))
.Markers(markers => {
markers.Add().Coordinates(40.755833, -73.986389)
.Tooltip(t => t.Text(new JS("encodeValue(unencodedTooltipText)")));
})
)
NoDataText()
The NoDataText()
method allows you to specify text displayed when the UI component does not contain any data. If you pass an HTML string, the component will evaluate it.
To prevent XSS attacks, encode a value obtained from a third party (loaded from a data source, entered by a user) before you pass it to the NoDataText()
method:
<script>
var unencodedNoDataText = "<script>alert('XSS')<\/script>";
function encodeValue(unencodedValue) {
const encodedContent = // encode the unencodedValue with your favorite sanitizing tool
return encodedContent;
}
</script>
@(Html.DevExtreme().List()
.ID("simpleList")
.NoDataText(new JS("encodeValue(unencodedNoDataText)"))
)