Over Cross-Site Request Forgery in .NET

U kunt vanaf het begin alleen beveiligde webtoepassingen produceren door rekening te houden met de beveiliging. Dit vereist het nadenken over de mogelijke manieren waarop iemand uw site kan aanvallen terwijl u elke pagina, formulier en actie aanmaakt. Het vereist ook inzicht in de meest voorkomende soorten beveiligingsproblemen en hoe deze aan te pakken.

Het meest voorkomende type gat in een beveiligingspagina op een webpagina stelt een aanvaller in staat om opdrachten uit te voeren namens een gebruiker, maar is onbekend voor de gebruiker. De cross-site request forgery attack maakt gebruik van het vertrouwen dat een website al heeft opgebouwd met de webbrowser van een gebruiker.

In deze zelfstudie bespreken we wat een cross-site aanvraag van een vervalsingsaanval is en hoe deze wordt uitgevoerd. Vervolgens bouwen we een eenvoudige ASP.NET MVC-applicatie die kwetsbaar is voor deze aanval en repareert de applicatie om te voorkomen dat deze opnieuw optreedt.


Wat is cross-site aanvraag vervalsing?

De cross-site-verzoekvervalsingsaanval eerst veronderstelt dat het slachtoffer al is geverifieerd op een doelwebsite, zoals een banksite, Paypal of een andere site die moet worden aangevallen. Deze verificatie moet op een manier worden opgeslagen dat als de gebruiker de site verlaat en retourneert, deze nog steeds wordt gezien als aangemeld door de doelwebsite. De aanvaller moet het slachtoffer vervolgens toegang geven tot een pagina of koppeling die een verzoek zal uitvoeren of berichten zal plaatsen op de doelwebsite. Als de aanval werkt, ziet de doelwebsite een verzoek van het slachtoffer en voert het verzoek uit als die gebruiker. Hierdoor kan de aanvaller in feite elke gewenste actie uitvoeren op de getargete website als slachtoffer. Het mogelijke resultaat kan geld overmaken, een wachtwoord opnieuw instellen of een e-mailadres wijzigen op de betreffende website.

Hoe de aanval werkt

Om het slachtoffer een link te laten gebruiken, hoeven ze niet op een link te klikken. Een eenvoudige afbeeldingslink kan voldoende zijn:

Het opnemen van een link zoals deze op een anders ogenschijnlijk onschuldige forumpost, blogcommentaar of sociale mediasite kan een gebruiker niet op de hoogte brengen. Meer complexe voorbeelden gebruiken JavaScript om een ​​volledig HTTP-postverzoek te maken en dit bij de doelwebsite in te dienen.


Een kwetsbare webtoepassing bouwen in ASP.NET MVC

Laten we een eenvoudige ASP.NET MVC-applicatie maken en deze kwetsbaar laten voor deze aanval. Ik zal Visual Studio 2012 gebruiken voor deze voorbeelden, maar dit zal ook werken in Visual Studio 2010 of Visual Web Developer 2010 zal werken als je ondersteuning voor MVC 4 hebt geïnstalleerd die kan worden gedownload en geïnstalleerd vanuit Microsoft.


Begin met het maken van een nieuw project en kies ervoor om het te gebruiken Internet project sjabloon. Ofwel View Engine werkt, maar hier gebruik ik de ASPX-viewmachine.

We voegen één veld toe aan de UserProfile-tabel om een ​​e-mailadres op te slaan. Onder Server Explorer uitbreiden Gegevensverbindingen. Je zou het moeten zien Standaardverbinding gemaakt met de informatie voor de aanmeldingen en lidmaatschappen. Klik met de rechtermuisknop op de Gebruikersprofiel tabel en klik Open tafeldefinitie. Op de lege regel onder UserName tabel, we voegen een nieuwe kolom toe voor de e-mail. Geef de kolom een ​​naam e-mailadres, geef het het type nvarchar (MAX), en controleer de Sta Nulls toe keuze. Klik nu Bijwerken om de nieuwe versie van de tabel op te slaan.

Dit geeft ons een basissjabloon van een webtoepassing, met ondersteuning voor inloggen, die sterk lijkt op wat veel schrijvers zouden beginnen met het maken van een applicatie. Als u de app nu uitvoert, ziet u dat deze wordt weergegeven en functioneert. druk op F5 of gebruik DEBUG -> Start Debugging van het menu om de website te openen.


Laten we een testaccount maken dat we voor dit voorbeeld kunnen gebruiken. Klik op de Registreren maak een link en maak een account aan met elke gewenste gebruikersnaam en wachtwoord. Hier ga ik een account gebruiken genaamd testuser. Na het maken ziet u dat ik nu als testgebruiker is aangemeld. Nadat je dit hebt gedaan, sluit je af en laten we een pagina toevoegen aan deze applicatie zodat de gebruiker zijn e-mail kan wijzigen.


Voordat we die pagina maken om het e-mailadres te wijzigen, moeten we eerst één wijziging aanbrengen in de toepassing, zodat de code op de hoogte is van de nieuwe kolom die we zojuist hebben toegevoegd. Open de AccountModels.cs bestand onder de modellen map en werk het Gebruikersprofiel klasse die overeenkomt met het volgende. Dit vertelt de klas over onze nieuwe kolom waarin we het e-mailadres voor het account opslaan.

[Tabel ("UserProfile")] public class UserProfile [Key] [DatabaseGeneratedAttribute (DatabaseGeneratedOption.Identity)] public int UserId get; vast te stellen;  public string UserName get; vast te stellen;  openbare string EmailAddress get; vast te stellen; 

Open de AccountController.cs het dossier. Na de RemoveExternalLogins functie voeg de volgende code toe om een ​​nieuwe actie te maken. Hiermee wordt de huidige e-mail voor de ingelogde gebruiker opgehaald en doorgegeven aan de weergave voor de actie.

public ActionResult ChangeEmail () // Verkrijg de ingelogde gebruikersnaamstring gebruikersnaam = WebSecurity.CurrentUserName; string currentEmail; using (UsersContext db = new UsersContext ()) UserProfile user = db.UserProfiles.FirstOrDefault (u => u.UserName.ToLower () == gebruikersnaam); currentEmail = user.EmailAddress;  return View (currentEmail); 

We moeten ook de bijbehorende weergave voor deze actie toevoegen. Dit moet een bestand met de naam zijn ChangeEmail.aspx onder de Bekeken \ Account map:

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage"%>  Verander e-mailadres   

Verander e-mailadres

Huidig ​​e-mailadres: <%= Model ?? "Geen huidige e-mail"%>

<% using(Html.BeginForm()) %> <% %>

Dit geeft ons een nieuwe pagina die we kunnen gebruiken om het e-mailadres van de momenteel aangemelde gebruiker te wijzigen.


Als we deze pagina uitvoeren en naar de / Account / ChangeEmail actie, we zien nu dat we momenteel geen e-mail hebben. Maar we hebben wel een tekstvak en een knop die we kunnen gebruiken om dat te corrigeren. Eerst moeten we echter de actie maken die wordt uitgevoerd, wanneer het formulier op deze pagina wordt ingediend.

[HttpPost] public ActionResult ChangeEmail (ChangeEmailModel-model) string gebruikersnaam = WebSecurity.CurrentUserName; using (UsersContext db = new UsersContext ()) UserProfile user = db.UserProfiles.FirstOrDefault (u => u.UserName.ToLower () == gebruikersnaam); user.EmailAddress = model.NewEmail; db.SaveChanges ();  // En om de wijziging te bevestigen, ontvang de e-mail van het profiel ChangeEmailModel newModel = new ChangeEmailModel (); using (UsersContext db = new UsersContext ()) UserProfile user = db.UserProfiles.FirstOrDefault (u => u.UserName.ToLower () == gebruikersnaam); newModel.CurrentEmail = user.EmailAddress;  return View (newModel); 

Nadat u deze wijziging hebt aangebracht, voert u de website uit en gaat u opnieuw naar de / Account / ChangeEmail actie die we zojuist hebben gemaakt. U kunt nu een nieuw e-mailadres invoeren en op de. Klikken E-mail wijzigen knop en zie dat het e-mailadres zal worden bijgewerkt.


De site aanvallen

Zoals geschreven, is onze applicatie kwetsbaar voor een cross-site aanvraag voor vervalsingsaanval. Laten we een webpagina toevoegen om deze aanval in actie te zien. We gaan een pagina toevoegen binnen de website die de e-mail naar een andere waarde zal veranderen. In de HomeController.cs bestand zullen we een nieuwe actie toevoegen met de naam AttackForm.

public ActionResult AttackForm () return View (); 

We voegen ook een weergave voor deze naam toe AttackForm.aspx onder de / Bekeken / Home map. Het zou er zo uit moeten zien:

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage"%>  Aanvalformulier   

Aanvalformulier

Deze pagina heeft een verborgen formulier, om u aan te vallen, door uw e-mailadres te wijzigen:

Onze pagina meldt behulpzaam zijn kwade bedoelingen, wat natuurlijk een echte aanval niet zou doen. Deze pagina bevat een verborgen formulier dat niet zichtbaar is voor de gebruiker. Vervolgens wordt Javascript gebruikt om dit formulier automatisch in te dienen wanneer de pagina is geladen.


Als u de site opnieuw uitvoert en naar de / Home / AttackForm pagina, je zult zien dat het prima laadt, maar zonder uiterlijke indicatie dat er iets is gebeurd. Als je nu naar de / Account / ChangeEmail pagina hoewel, u zult zien dat uw e-mail is gewijzigd in [email protected]. Hier maken we dit natuurlijk bewust, maar bij een echte aanval merk je misschien niet dat je e-mail is aangepast.


Verzachtende cross-site aanvraagvervalsing

Er zijn twee primaire manieren om dit type aanval te verminderen. Ten eerste kunnen we de verwijzing controleren waar het webverzoek vandaan komt. Dit zou de toepassing moeten vertellen wanneer een formulierinzending niet afkomstig is van onze server. Dit heeft echter twee problemen. Veel proxyservers verwijderen deze verwijzingsinformatie, hetzij opzettelijk om de privacy te beschermen of als bijwerking, wat betekent dat een legitiem verzoek deze informatie niet zou kunnen bevatten. Het is ook mogelijk voor een aanvaller om de verwijzing te vervalsen, hoewel dit de complexiteit van de aanval vergroot.

De meest effectieve methode is om te vereisen dat voor elke formulierinzending een voor de gebruiker specifieke token bestaat. De waarde van deze token moet willekeurig worden gegenereerd elke keer dat het formulier wordt gemaakt en het formulier wordt alleen geaccepteerd als het token is opgenomen. Als het token ontbreekt of een andere waarde is opgenomen, staat het verzenden van het formulier niet toe. Deze waarde kan worden opgeslagen in de sessiestatus van de gebruiker of in een cookie, zodat we de waarde kunnen verifiëren wanneer het formulier wordt verzonden.

ASP.NET maakt dit proces eenvoudig, omdat de CSRF-ondersteuning is ingebouwd. Om het te gebruiken, hoeven we slechts twee wijzigingen aan te brengen aan onze website.


Het probleem oplossen

Ten eerste moeten we het unieke token aan het formulier toevoegen om het e-mailadres van de gebruiker te wijzigen wanneer we het weergeven. Werk het formulier bij in de ChangeEmail.aspx bekijk onder / Account / ChangeForm:

<% using(Html.BeginForm())  %> <%: Html.AntiForgeryToken() %> <%: Html.TextBoxFor(t=>t.NewEmail)%>  <%  %>

Deze nieuwe regel: <%: Html.AntiForgeryToken() %> vertelt ASP.NET om een ​​token te genereren en deze als een verborgen veld in het formulier te plaatsen. Daarnaast kan het framework het op een andere locatie plaatsen waar de toepassing er later toegang toe heeft om het te verifiëren.

Als we nu de pagina laden en naar de bron kijken, zien we deze nieuwe regel, in de vorm, weergegeven aan de browser. Dit is ons token:

We moeten ook een wijziging aanbrengen in onze actie om te laten weten dat we dit token hebben toegevoegd en dat het token moet worden geverifieerd voordat het geposte formulier wordt geaccepteerd.

Nogmaals, dit is eenvoudig in ASP.NET MVC. Bovenaan de actie die we hebben gemaakt om het geposte formulier te verwerken, is degene met de [HttpPost] attribuut toegevoegd, voegen we een ander attribuut toe met de naam [ValidateAntiForgeryToken]. Hierdoor ziet het begin van onze actie er nu als volgt uit:

 [HttpPost] [ValidateAntiForgeryToken] public ActionResult ChangeEmail (ChangeEmailModel-model) string gebruikersnaam = WebSecurity.CurrentUserName; * Rest van functie weggelaten *

Laten we dit uittesten. Ga eerst naar de / Account / ChangeEmail pagina en herstel de e-mail voor uw account naar een bekende waarde. Dan kunnen we terugkeren naar de / Home / AttackForm pagina en opnieuw probeert de aanvalscode onze e-mail te veranderen. Als u terugkeert naar de / Account / ChangeEmail pagina opnieuw, deze keer ziet u dat uw eerder ingevoerde e-mail nog steeds veilig en intact is. De wijzigingen die we hebben aangebracht in onze vorm en actie hebben deze pagina beschermd tegen de aanval.

Als je het aanvalsformulier rechtstreeks zou bekijken (eenvoudig gedaan door het verwijderen van de