Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Door Rick Anderson
Cross-Site Scripting (XSS) is een beveiligingsprobleem waarmee een cyberaanval scripts (meestal JavaScript) op webpagina's kan plaatsen. Wanneer andere gebruikers betrokken pagina's laden, worden de scripts van de cyberaanval uitgevoerd. De cyberattacker kan vervolgens cookies en sessietokens stelen, de inhoud van de webpagina wijzigen via DOM-manipulatie of de browser omleiden naar een andere pagina. XSS-kwetsbaarheden treden doorgaans op wanneer een toepassing gebruikersinvoer accepteert en deze op een pagina weergeeft zonder die te valideren, te encoderen of te escapen.
Dit artikel is voornamelijk van toepassing op ASP.NET Core MVC met weergaven, Razor Pages en andere apps die HTML retourneren die kwetsbaar zijn voor XSS. Web-API's die gegevens retourneren in de vorm van HTML, XML of JSON kunnen XSS-aanvallen in hun client-apps activeren als ze gebruikersinvoer niet goed opschonen. Dit gedrag is afhankelijk van hoeveel vertrouwen de client-app in de API plaatst. Als een API door de gebruiker gegenereerde inhoud accepteert en retourneert in een HTML-antwoord, zijn de gegevens geopend om aan te vallen. Een cyberaanval kan schadelijke scripts injecteren in de inhoud die wordt uitgevoerd wanneer het antwoord wordt weergegeven in de browser van de gebruiker.
Om XSS-aanvallen te voorkomen, moeten web-API's invoervalidatie en uitvoercodering implementeren. Invoervalidatie zorgt ervoor dat gebruikersinvoer voldoet aan de verwachte criteria en geen schadelijke code bevat. Uitvoercodering zorgt ervoor dat alle gegevens die door de API worden geretourneerd, correct worden opgeschoond, zodat deze niet als code kunnen worden uitgevoerd door de browser van de gebruiker. Zie GitHub dotnet/aspnetcore.docs-probleem #28789 voor meer informatie.
Uw toepassing beveiligen tegen XSS
Op basisniveau werkt XSS door uw toepassing te misleiden om een <script> tag in te voegen op uw weergegeven pagina of door een On* gebeurtenis in een element in te voegen.
Om te voorkomen dat XSS in de toepassing wordt ingevoerd, moeten ontwikkelaars de volgende preventietechnieken implementeren:
Plaats nooit niet-vertrouwde gegevens in uw HTML-invoer, tenzij u de andere technieken in deze sectie volgt.
Niet-vertrouwde gegevens zijn gegevens die kunnen worden beheerd door een cyberaanval. Voorbeelden hiervan zijn invoer van HTML-formulieren, queryreeksen, HTTP-headers of zelfs gegevensbronnen uit een database. Een cyberaanval kan uw database mogelijk schenden, zelfs als ze uw toepassing niet kunnen schenden.
Voordat u niet-vertrouwde gegevens in een HTML-element plaatst, moet u ervoor zorgen dat de gegevens zijn gecodeerd met HTML.
HTML-codering zet tekens zoals het linker punthaakje of kleiner dan (
<) om in een veilige vorm, zoals (<).Voordat u niet-vertrouwde gegevens in een HTML-kenmerk plaatst, moet u ervoor zorgen dat de gegevens zijn gecodeerd met HTML-kenmerken.
Deze gespecialiseerde vorm van HTML-codering verwerkt dubbele aanhalingstekens (
"), enkele aanhalingstekens ('), ampersand (&) en minder dan (<) tekens. Als u te maken hebt met niet-vertrouwde invoer, gebruikt u HTML-codering voor algemene HTML-inhoud en HTML-kenmerkcodering voor HTML-kenmerken.Voordat u niet-vertrouwde gegevens in JavaScript plaatst, plaatst u de gegevens in een HTML-element waarvan u de inhoud tijdens runtime ophaalt.
Als u deze techniek niet kunt volgen, controleert u of de gegevens zijn gecodeerd met JavaScript. JavaScript-codering converteert gevaarlijke tekens voor JavaScript naar een hexadecimale equivalente waarde. JavaScript-codering wijzigt bijvoorbeeld het teken kleiner dan (
<) in de hexwaarde\u003C.Voordat u niet-vertrouwde gegevens in een URL-querytekenreeks plaatst, moet u ervoor zorgen dat de gegevens URL-codering hebben.
HTML-codering verkennen met Razor
De Razor engine die in MVC wordt gebruikt, codeert automatisch alle uitvoer die afkomstig is van variabelen, tenzij u dit gedrag wilt voorkomen. Er worden HTML-kenmerkcoderingsregels gebruikt wanneer u de at-symboolrichtlijn @ gebruikt. Omdat HTML-kenmerkcodering een superset van HTML-codering is, hoeft u niet te overwegen of u HTML-codering of HTML-kenmerkcodering wilt gebruiken. U moet ervoor zorgen dat u alleen het at-symbool @ in een HTML-context gebruikt en niet wanneer u niet-vertrouwde invoer rechtstreeks in JavaScript probeert in te voegen.
Razor Tag Helpers coderen ook invoer die u gebruikt in tagparameters.
Bekijk de volgende Razor weergave:
@{
var untrustedInput = "<\"123\">";
}
@untrustedInput
In deze weergave wordt de inhoud van de untrustedInput variabele uitgevoerd. De variabele bevat enkele tekens die worden gebruikt in XSS-aanvallen: kleiner dan (<), dubbele aanhalingstekens (") en rechte haakjes of groter dan (>). Als u de bron bekijkt, ziet u de weergegeven uitvoer die is gecodeerd als:
<"123">
Waarschuwing
ASP.NET Core MVC biedt een HtmlString-klasse die niet automatisch wordt gecodeerd bij uitvoer. Deze klasse mag nooit worden gebruikt in combinatie met niet-vertrouwde invoer, omdat deze een XSS-beveiligingsprobleem blootstelt.
JavaScript-codering verkennen met Razor
In sommige gevallen wilt u mogelijk een waarde invoegen in JavaScript om in uw weergave te verwerken. Er zijn twee manieren om deze taak uit te voeren. De veiligste manier om waarden in te voegen, is door de waarde in een gegevenskenmerk van een tag te plaatsen en op te halen in uw JavaScript. Voorbeeld:
@{
var untrustedInput = "<script>alert(1)</script>";
}
<div id="injectedData"
data-untrustedinput="@untrustedInput" />
<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 dynamically generated data as it can lead to XSS.
document.getElementById("scriptedWrite").innerText += clientSideUntrustedInputOldStyle;
// Or, you can use createElement() to dynamically create document elements.
// This instance uses textContent to ensure the data is properly encoded.
var x = document.createElement("div");
x.textContent = clientSideUntrustedInputHtml5;
document.body.appendChild(x);
// You can also use createTextNode on an element to ensure data is properly encoded.
var y = document.createElement("div");
y.appendChild(document.createTextNode(clientSideUntrustedInputHtml5));
document.body.appendChild(y);
</script>
Met de voorgaande markering wordt de volgende HTML gegenereerd:
<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 dynamically generated data as it can lead to XSS.
document.getElementById("scriptedWrite").innerText += clientSideUntrustedInputOldStyle;
// Or, you can use createElement() to dynamically create document elements.
// This instance uses textContent to ensure the data is properly encoded.
var x = document.createElement("div");
x.textContent = clientSideUntrustedInputHtml5;
document.body.appendChild(x);
// You can also use createTextNode on an element to ensure data is properly encoded.
var y = document.createElement("div");
y.appendChild(document.createTextNode(clientSideUntrustedInputHtml5));
document.body.appendChild(y);
</script>
Met de voorgaande code wordt de volgende uitvoer gegenereerd:
<script>alert(1)</script>
<script>alert(1)</script>
<script>alert(1)</script>
Waarschuwing
Voeg geen niet-vertrouwde invoer toe in JavaScript om DOM-elementen te maken of te gebruiken document.write() voor dynamisch gegenereerde inhoud.
Gebruik in plaats daarvan een van de volgende methoden om te voorkomen dat code beschikbaar wordt gemaakt voor OP DOM gebaseerde XSS:
- Roep
createElement()aan en wijs eigenschapswaarden toe met de juiste methoden of eigenschappen, zoalsnode.textContent=ofnode.InnerText=. - Roep de
document.CreateTextNode()methode aan en voeg deze toe op de juiste DOM-locatie. - Roep de
element.SetAttribute()methode aan. - Gebruik de
element[attribute]=opdracht.
Toegang tot coderingsprogramma's in code
U kunt OP twee manieren HTML-, JavaScript- en URL-coderingsprogramma's in uw code gebruiken:
- Injecteer ze via afhankelijkheidsinjectie.
- Gebruik de standaardcoderingsprogramma's in de
System.Text.Encodings.Webnaamruimte.
Wanneer u de standaardcoderingsprogramma's gebruikt, worden alle aanpassingen die worden toegepast op tekenbereiken (zodat ze als veilig worden behandeld) niet van kracht. De standaard coderingsprogramma's maken gebruik van de veiligste coderingsregels die mogelijk zijn.
Als u de configureerbare encoders via afhankelijkheidsinjectie wilt gebruiken, moeten uw constructors, indien van toepassing, een parameter van het type HtmlEncoder, JavaScriptEncoder en UrlEncoder accepteren.
Voorbeeld:
public class HomeController : Controller
{
HtmlEncoder _htmlEncoder;
JavaScriptEncoder _javaScriptEncoder;
UrlEncoder _urlEncoder;
public HomeController(HtmlEncoder htmlEncoder,
JavaScriptEncoder javascriptEncoder,
UrlEncoder urlEncoder)
{
_htmlEncoder = htmlEncoder;
_javaScriptEncoder = javascriptEncoder;
_urlEncoder = urlEncoder;
}
}
URL-parameters coderen
Als u een URL-queryreeks met niet-vertrouwde invoer als waarde wilt maken, gebruikt u de UrlEncoder parameter om de waarde te coderen:
var example = "\"Quoted Value with spaces and &\"";
var encodedValue = _urlEncoder.Encode(example);
Na codering bevat de encodedValue variabele de tekenreeks %22Quoted%20Value%20with%20spaces%20and%20%26%22. Spaties, aanhalingstekens, interpunctie en andere onveilige tekens worden procent gecodeerd naar de hexadecimale waarde. Een spatieteken wordt bijvoorbeeld geconverteerd naar %20.
Waarschuwing
Gebruik geen niet-vertrouwde invoer als onderdeel van een URL-pad. Geef altijd niet-vertrouwde invoer door als een querystring-waarde.
De encoders aanpassen
Coderingsprogramma's maken standaard gebruik van een veilige lijst die is beperkt tot het Unicode-bereik Basic Latin. Alle tekens buiten het aangegeven bereik worden gecodeerd als hun tekencode-equivalenten. Dit gedrag is ook van invloed op rendering door Razor Tag Helpers en HTML Helpers, omdat ze de encoders gebruiken om uw tekenreeksen uit te voeren.
Het doel van dit gedrag is om te beschermen tegen onbekende of toekomstige browserfouten. Eerdere browserfouten verstoorden het parseren op basis van de verwerking van niet-Engelse tekens. Als uw website intensief gebruikmaakt van niet-Latijnse tekens, zoals Chinees, Cyrillisch of andere, is dit gedrag waarschijnlijk niet geschikt voor uw configuratie.
U kunt de veilige lijsten voor coderingsprogramma's aanpassen om Unicode-bereiken op te nemen die geschikt zijn voor de app tijdens het opstarten. Breng de aanpassingen aan in het Program.cs-bestand .
U kunt bijvoorbeeld de standaardconfiguratie gebruiken met een Razor HTML-Helper die vergelijkbaar is met de volgende HTML:
<p>This link text is in Chinese: @Html.ActionLink("汉语/漢語", "Index")</p>
De voorgaande markering wordt weergegeven met Chinese tekst gecodeerd:
<p>This link text is in Chinese: <a href="/">汉语/漢語</a></p>
Als u het bereik van tekens die door de encoder worden behandeld als veilig wilt vergroten, voegt u de volgende regel in het Program.cs-bestand in:
builder.Services.AddSingleton<HtmlEncoder>(
HtmlEncoder.Create(allowedRanges: new[] { UnicodeRanges.BasicLatin,
UnicodeRanges.CjkUnifiedIdeographs }));
U kunt de veilige lijsten met coderingsprogramma's aanpassen om Unicode-bereiken op te nemen die geschikt zijn voor uw toepassing tijdens het opstarten, in ConfigureServices().
Als u bijvoorbeeld de standaardconfiguratie gebruikt, kunt u een Razor HtmlHelper als volgt gebruiken;
<p>This link text is in Chinese: @Html.ActionLink("汉语/漢語", "Index")</p>
Wanneer u de bron van de webpagina bekijkt, ziet u dat deze als volgt is weergegeven, met de Chinese tekst gecodeerd;
<p>This link text is in Chinese: <a href="/">汉语/漢語</a></p>
Als u de tekens die door de encoder worden behandeld als veilig wilt vergroten, voegt u de volgende regel in de ConfigureServices() methode in startup.cs;
services.AddSingleton<HtmlEncoder>(
HtmlEncoder.Create(allowedRanges: new[] { UnicodeRanges.BasicLatin,
UnicodeRanges.CjkUnifiedIdeographs }));
In dit voorbeeld wordt de veilige lijst uitgebreid met de Unicode Range CJK Unified Ideographs. De volgende uitvoer toont de gerenderde weergave voor een breder scala aan veilige tekens:
<p>This link text is in Chinese: <a href="/">汉语/漢語</a></p>
Veilige lijstbereiken worden opgegeven als Unicode-codegrafieken, niet als talen. De Unicode-standaard bevat een lijst met codegrafieken die u kunt gebruiken om de grafiek te vinden die uw tekens bevat. Elke encoder (HTML, JavaScript, URL) moet afzonderlijk worden geconfigureerd.
Opmerking
Aanpassing van de veilige lijst is alleen van invloed op coderingsprogramma's die zijn afkomstig via afhankelijkheidsinjectie.
Als u rechtstreeks toegang hebt tot een encoder via System.Text.Encodings.Web.*Encoder.Default, wordt alleen de standaard veilige lijst gebruikt, Basic Latin.
Bepalen wanneer en waar moet worden gecodeerd
Over het algemeen is de geaccepteerde praktijk dat codering plaatsvindt op het punt van uitvoer en gecodeerde waarden nooit in een database mogen worden opgeslagen.
Met codering op het uitvoerpunt kunt u het gebruik van gegevens wijzigen. Wijzig bijvoorbeeld van HTML in een querytekenreekswaarde. Met deze methode kunt u eenvoudig in uw gegevens zoeken zonder waarden te hoeven coderen voordat u zoekt. Hiermee kunt u ook profiteren van wijzigingen of bugfixes die zijn aangebracht in coderingsprogramma's.
Validatie gebruiken als een XSS-preventietechniek
Validatie kan een handig hulpmiddel zijn bij het beperken van XSS-aanvallen. Een numerieke tekenreeks met alleen de tekens 0-9 activeert bijvoorbeeld geen XSS-aanval.
Validatie is ingewikkelder wanneer HTML wordt geaccepteerd in gebruikersinvoer. Het parseren van HTML-invoer kan moeilijk en soms onmogelijk zijn. Markdown, in combinatie met een parser waarmee ingesloten HTML wordt gestript, is een veiligere optie voor het accepteren van uitgebreide invoer.
Vertrouw nooit alleen op validatie. Codeer altijd niet-vertrouwde invoer vóór uitvoer, ongeacht welke validatie of opschoning wordt uitgevoerd.