Veel problemen met de websitebeveiliging komen van het te veel vertrouwen van de gebruiker. De meeste gebruikers van uw webtoepassing doen alleen wat ze moeten doen, een nieuwsgierige of kwaadwillende gebruiker wil vaak de grenzen van de toegang verleggen. Aan die randen verschijnen beveiligingsgaten vaak in uw toepassing. Ik heb eerder geschreven over het voorkomen van twee veelvoorkomende soorten kwetsbaarheden, SQL Injection en Cross Site Request Forgery in ASP.NET-apps. Dit artikel gaat over het voorkomen van Cross Site Scripting, een derde veelvoorkomende vorm van kwetsbaarheid in websites.
Hoewel een modern framework deze aanvallen moeilijker maakt, vind ik dat we eerst een goed begrip moeten hebben van de manier waarop een app werkt is kwetsbaar voor een aanval. Laten we eerst eens kijken naar wat Cross Site Scripting is en hoe het kan worden uitgebuit.
Cross Site Scripting (vaak afgekort als XSS) maakt het mogelijk om kwaadwillende scripts in een anderszins vertrouwde website te injecteren. Deze injectie gebeurt zonder medeweten van de gebruiker. Het geïnjecteerde script wordt uitgevoerd alsof het afkomstig is van de originele website. Het schadelijke script kan dus toegang krijgen tot alle bronnen van de gehoste website waartoe de gebruiker toegang zou hebben, zoals cookies of sessietokens.
De opening voor een cross-site scripting-aanval komt wanneer een webtoepassing invoer van gebruikers of externe bronnen weergeeft zonder deze correct te valideren of te coderen. Bij de meeste cross-site scripting-aanvallen probeert de aanvaller JavaScript in de webpagina van een vertrouwde server te injecteren. De aanvaller kan ook proberen HTML, Flash of iets anders te injecteren dat de browser zal uitvoeren. Ongeacht het script blijft het doel om de browser code te laten uitvoeren van de keuze van de aanvaller.
Er zijn drie categorieën cross-site scripting-aanvallen, gedeeld door de injectiemethode en methode om de aanval te voorkomen. Bij het eerste type aanval wordt het script permanent opgeslagen op de doelserver en wordt het daarom een aanhoudende cross-site scripting-aanval genoemd. Deze aanval probeert het schadelijke script in te bedden in iets als een forumbericht dat in een database is opgeslagen of een schijnbaar goedaardig veld, zoals de startpagina van een gebruiker van de database. Omdat het script bleef bestaan, werd elke bezoeker van de site die het bericht, bericht of ander aangetast item bekijkt, een mogelijk slachtoffer van de aanval.
Aanvallers die dit type aanval proberen, richten zich over het algemeen op opmerkingenvelden, forums, sociale media en andere velden waar enigszins willekeurige invoer van eindgebruikers wordt verwacht en een normaal onderdeel van de toepassing is. De aanvaller kan het script opnemen in een forumpost in een anderszins geldig deel van een gesprek. Telkens wanneer iemand de post bekijkt, wordt het script uitgevoerd.
In het tweede type cross-site scripting-aanval, bekend als gereflecteerde cross-site scripting, levert de aanvaller het geïnjecteerde script aan de kwetsbare site, zodat deze onmiddellijk wordt teruggestuurd naar de gebruiker. Gebruikelijke methoden om dit te doen, richten op pagina's waar gebruikersinvoer onderdeel wordt van de uitvoer van een pagina. Een zoekpagina kan de zoektermen weergeven aan de gebruiker en een uitweg bieden voor deze aanval. Het geïnjecteerde script in de invoer van een gebruiker mag nooit worden opgeslagen door de webtoepassing.
De derde cross-site scripting-aanval gebeurt volledig in de browser. De aanval functioneert door het manipuleren van het interne model van de webpagina binnen de browser die bekend staat als de DOM en worden DOM-gebaseerde aanvallen genoemd. Laat de aanvaller deze opnieuw kwaadaardige code uitvoeren, maar de door de server geretourneerde code wordt door de webpagina gemanipuleerd in uitvoerbaar JavaScript..
Uiteindelijk is een cross-site scriptingaanval een cross-site scripting-aanval, ongeacht hoe deze wordt afgeleverd. Aangezien de geïnjecteerde code afkomstig is van een anderszins vertrouwde server, kan deze vaak worden uitgevoerd onder de machtigingen van de site. Het kan daarom handelen alsof het native code op de website is.
Een geslaagde cross-site scripting-aanval kan toegang tot cookies op een webpagina mogelijk maken. Deze cookies kunnen gevoelige informatie bevatten, inclusief sessie-id's waarmee de aanvaller de aangevallen gebruiker zou kunnen nabootsen. De aanval kan ook HTML-inhoud op een pagina wijzigen om een nep-aanmeldingsformulier weer te geven en de aanmeldingsreferenties van de gebruiker te stelen. De aanvaller kan alle inhoud van de pagina bekijken en verzenden, waardoor gevoelige informatie zoals rekeningnummers kunnen worden vastgelegd. Een geavanceerdere aanval kan in feite een key-logger installeren om informatie die op de webpagina is ingevoerd naar een aanvaller te sturen.
Voor het verzachten van cross-site scripting is het niet nodig om enige invoer van een gebruiker of een andere externe bron te vertrouwen. De webtoepassing moet deze gegevens als mogelijk gevaarlijk beschouwen, ongeacht de bron. Laten we een paar methoden bekijken die specifiek zijn voor ASP.NET om deze aanvallen te voorkomen met behulp van componenten die in het framework zijn ingebouwd en vrij beschikbare bibliotheken.
De webtoepassing moet alle invoer in de toepassing valideren voordat deze wordt gebruikt. Net als bij andere injectieaanvallen zoals SQL Injection. De toepassing valideert bij voorkeur deze invoer tegen een witte lijst met aanvaardbare waarden. De validatie verwijdert of vervangt onverwachte componenten van de invoer met een gecodeerde waarde. Een zwarte lijstmethode, die alleen een lijst met bekende ongewenste tekens verwijdert, kan worden gebruikt, maar is kwetsbaarder voor nieuwe aanvalsmethoden.
Als we weten dat een waarde altijd een geheel getal moet zijn, kunt u de invoer valideren met behulp van code zoals:
int memberId; if (! int.TryParse (externalValue, out memberId)) return RedirectToAction ("InputError");
Als het framework de eerder opgehaalde frames niet kan ontleden externalValue
als een geheel getal leidt de code om naar een pagina die een fout zou weergeven. Anders weten we dat Gebruikers ID
bevat een geheel getal. Dit proces werkt ook met andere basistypen. Enkele meer algemene typen bieden ook methoden om de informatie te valideren. Het net Uri
klasse bevat een methode IsWellFormedUriString
die een URL kan valideren. Dit zou validatie toelaten dat het startpagina-item van een gebruiker een geldige URL bevat voor weergave.
var userHomePage = userRecord ["startpagina"]; if (! Uri.IsWellFormedUriString (newUrl, UriKind.Absolute)) Model.homepage = "none"; else Model.homepage = Html.Encode (userHomePage);
Andere en meer complexe gegevenstypen hebben meer complexe validatie nodig. Validatie van een veld met creditcardnummers kan tekens in de reeks verwijderen die geen cijfers zijn. Validatie van complexere reeksen kan reguliere expressies vereisen. Validatie van een klasse kan ook complexere controles vereisen.
ASP.NET biedt effectieve bescherming tegen gereflecteerde aanvallen met validatie van aanvragen. Als ASP.NET opmaak of code in een aanvraag detecteert, wordt de uitzondering "potentieel gevaarlijke waarde gedetecteerd" gegenereerd en wordt de verwerking van de aanvraag gestopt.
Hoewel het waardevol is, zijn er tijden dat u deze waarden in een verzoek moet toestaan. Een veelvoorkomend voorbeeld is het toestaan van het invoeren van rich text in een formulier. In deze gevallen is de validatie van aanvragen helaas te vaak uitgeschakeld voor de hele site. Een betere oplossing schakelt deze validatie alleen uit als dat nodig is. In eerdere versies van ASP.NET, toevoegen validateRequest = "false"
naar de Pagina
richtlijn in Webforms de validatie voor een pagina zou uitschakelen. In ASP.NET MVC voegt u de [ValidateInput (false)]
attribuut aan een controlleractie zet validatie voor die actie uit, terwijl het toevoegen van de [AllowHtml]
kenmerk schakelt validatie voor een veld uit.
ASP.NET 4.0 heeft aanvraagvalidatie op verschillende manieren gewijzigd. Deze en latere versies van het framework doen al vroeg in het HTTP-verzoek validatie. De validatie is ook van toepassing op alle ASP.NET-aanvragen en niet alleen .aspx
paginaverzoeken. Dit omvat ook aangepaste HTTP-modules. Pagina's die afhankelijk zijn van het oorspronkelijke gedrag, kunnen terugkeren naar de oudere methode door de requestValidationMode
attribuut in de web.config
bestand naar versie 2.0
.
Nog beter is om dit alleen voor pagina's waar nodig uit te schakelen, met behulp van de syntaxis in de web.config
het dossier:
ASP.NET 4.5 heeft de mogelijkheid toegevoegd om validatie uit te stellen totdat de gegevens zijn opgevraagd. Het instellen van requestValidationMode
attribuut in uw web.config
bestand naar versie 4.5
activeert dit nieuwe gedrag.
ASP.NET 4.5 heeft ook het HttpRequest.Unvalidated
eigendom. Als u deze eigenschap gebruikt, krijgt u waar nodig gemakkelijker toegang tot de niet-gevalideerde formulierwaarde. Door het combineren van vertraagde validatie en de niet gevalideerde
eigenschap, hebt u toegang tot de niet-gevalideerde waarden wanneer dat nodig is, maar beschermt u andere invoer van formulieren.
Voordat u externe gegevens op een webpagina weergeeft, moet uw HTML gecodeerd zijn zodat deze niet door de browser wordt verwerkt. Neem als voorbeeld een ASP.NET-pagina op zodat een bericht kan worden doorgegeven voor weergave, zoals een statusupdate. Een toepassing kan deze pagina gebruiken om de gebruiker te laten zien dat zijn account zonder fouten is gemaakt. De URL voor deze pagina lijkt normaal gesproken op http: // appname / placeorder / Account + Gemaakt
. De resulterende pagina toont het bericht aan de gebruiker met een veld, zoals:
<%= Html.Label("Message", Model.message) %>
... en wordt weergegeven als:
Als we de URL-aanroep wijzigen naar http: / appname / placeorder /
, we krijgen nu iets anders.
Het script kan natuurlijk iets zijn en niet alleen het ongevaarlijke waarschuwingsvenster dat hier verschijnt. Verzoekvalidatie zou de bovenstaande voorbeelden vangen en een uitzondering retourneren voordat deze wordt weergegeven. Als het echter is uitgeschakeld, wordt de attack door het coderen van de uitvoer voorkomen.
ASP.NET maakt het gemakkelijk om gegevens te coderen om aanvallen te voorkomen. Vroege versies van MVC met de syntaxis van Webform bevatten vaak code zoals deze die geen HTML codeerde.
<%= status >
U moest de uitvoer handmatig coderen zodat elke HTML zou worden geconverteerd naar een weergave-indeling. Dus de <
teken wordt de tekenreeks <
. De Html.Encode
functie biedt deze conversie. De veiligere vorm van code wordt dus:
<%= Html.Encode(status) >
ASP.NET MVC introduceerde later een syntaxis om dit in één stap te doen door te vervangen <=
met <:
dus de code kan worden ingekort tot:
<%: status >
Met behulp van de Razor View Engine is alle uitvoer HTML-gecodeerd, tenzij u specifiek een methode gebruikt om deze niet te coderen. In Razor wordt de code gelijk aan het bovenstaande:
@status
Razor verwerkt automatisch HTML-codering ongeacht de reeks staat
bevat. In een geval waarin u de onbewerkte gegevens moet weergeven, kunt u de HTML.Raw ()
methode. Om het resultaat zonder codering weer te geven, kunnen we gebruik maken van:
@ Html.Raw (status)
In dit voorbeeld zou de bovenstaande code onze applicatie kwetsbaar maken nog een keer. Er zijn dus een aantal omstandigheden waarbij u de uitvoer niet zou moeten coderen. Als u deze functie in een veld uitschakelt, moet u extra voorzichtig zijn om ervoor te zorgen dat de gegevens worden ontsmet voordat ze worden weergegeven. Gelukkig is er een bibliotheek die hierbij helpt, terwijl je ook meer doet om je applicatie te beschermen tegen cross-site scripting.
Als u een ASP.NET-toepassing schrijft, moet u de AntiXSS-bibliotheek voor ASP.NET gebruiken. Vanaf de projectwebsite biedt "AntiXSS een groot aantal coderingsfuncties voor gebruikersinvoer, inclusief HTML, HTML-kenmerken, XML, CSS en JavaScript."
De bibliotheek bevat methoden die zijn gericht op het opschonen van externe gegevens op basis van het beoogde gebruik van die gegevens. Deze methoden maken gebruik van de op de witte lijst gebaseerde benadering die de voorkeur heeft. Dit betekent dat gecodeerde gegevens, bedoeld voor een HTML-kenmerk, kunnen worden gedesinfecteerd om alleen geldige gegevens voor een HTML-kenmerk te bevatten. Het traditionele ASP.NET HtmlEncode
methoden gebruiken de zwarte lijstbenadering die alleen bepaalde, potentieel gevaarlijke tekens codeert.
Microsoft begon met het opnemen van kernroutines uit deze bibliotheek in ASP.NET 4.5 in een nieuwe System.Web.Security.AntiXss
namespace. U kunt ook het framework instellen om deze AntiXSS-methoden te gebruiken in plaats van de ingebouwde coderingsroutines. U doet dit door de encoderType
kenmerk van httpRuntime
in de web.config
bestand voor de toepassing:
Als uw toepassing een aanzienlijke hoeveelheid externe gegevens weergeeft, dan zal het gebruik van AntiXSS uw aanvraag sterk tegen cross-site scripting beschermen. Als u ASP.NET 4.5 gebruikt, biedt het wijzigen van uw toepassing om de nieuwe AntiXSS-methoden voor standaardcodering te gebruiken nog meer bescherming voor uw webtoepassing..
Het voorkomen van cross-site scripting is moeilijker dan het in eerste instantie lijkt. OWASP somt meer dan 80 vectoren op die kunnen worden getarget met behulp van cross-site scripting-aanvallen. Die organisatie noemt deze kwetsbaarheden ook als derde in hun 2013 lijst van top tien webkwetsbaarheden.
Als u er niet voor zorgt dat alle externe gegevens die in uw toepassing worden binnengebracht op de juiste manier zijn geëscaped of de invoer niet valideren voordat u deze op een uitvoerpagina plaatst, laat u uw webtoepassing kwetsbaar voor cross-site scripting. In ASP.NET kan dit worden gedaan door: