Forstå Forsøk på forfalskning på tvers av nettsteder i .NET

Du kan bare produsere sikre webapplikasjoner ved å ta sikkerhet i betraktning, fra starten. Dette krever å tenke på de mulige måtene noen kan angripe nettstedet ditt når du lager hver side, skjema og handling. Det krever også å forstå de vanligste typene sikkerhetsproblemer og hvordan de skal adresseres.

Den vanligste typen sikkerhetshull i en nettside tillater en angriper å utføre kommandoer på vegne av en bruker, men ukjent for brukeren. Forfalskningsangrep på tvers av nettstedet utnytter tilliten et nettsted allerede har etablert med en brukers nettleser.

I denne opplæringen diskuterer vi hva en overfallsforespørselsforfalskningsangrep er, og hvordan den utføres. Da skal vi bygge et enkelt ASP.NET MVC-program som er sårbart for dette angrepet, og fikser programmet for å forhindre at det skjer igjen.


Hva er Cross-Site Request Forgery?

Forfalskningsangrep på tvers av nettstedet forutsetter at offeret allerede er godkjent på et målwebområde, for eksempel et banksted, Paypal eller et annet nettsted som skal angripes. Denne autentiseringen må lagres på en måte, slik at hvis brukeren forlater nettstedet og returnerer, er de fortsatt sett som innlogget av målwebområdet. Angriperen må da få offeret til å få tilgang til en side eller lenke som vil utføre en forespørsel eller post til målwebområdet. Hvis angrepet fungerer, vil målwebsiden se en forespørsel fra offeret og utføre forespørselen som den brukeren. Dette tillater faktisk at angriperen utfører enhver handling som er ønsket på den målrettede nettsiden som offeret. Det potensielle resultatet kan overføre penger, tilbakestille et passord, eller endre en e-postadresse på det målrettede nettstedet.

Hvordan angrepet fungerer

Handlingen om å få offeret til å bruke en lenke krever ikke at de klikker på en lenke. En enkel bildekobling kan være nok:

Inkludert en lenke som dette på en ellers tilsynelatende uskyldig forumpost, bloggkommentar eller sosiale medier kan få en bruker uvitende. Mer komplekse eksempler bruker JavaScript til å bygge en komplett HTTP-postforespørsel og sende den til målwebsiden.


Bygg et sårbart webprogram i ASP.NET MVC

La oss lage et enkelt ASP.NET MVC-program og la det være sårbart for dette angrepet. Jeg bruker Visual Studio 2012 for disse eksemplene, men dette vil også fungere i Visual Studio 2010 eller Visual Web Developer 2010 vil fungere hvis du har installert støtte for MVC 4 som kan lastes ned og installeres fra Microsoft.


Begynn med å opprette et nytt prosjekt og velg å bruke Internett-prosjekt mal. Enten View Engine vil fungere, men her bruker jeg ASPX-visningsmotoren.

Vi legger til ett felt i UserProfile-tabellen for å lagre en e-postadresse. Under Server Explorer utvide Datatilkoblinger. Du bør se Standard tilkobling opprettet med informasjon for pålogginger og medlemskap. Høyreklikk på Brukerprofil bord og klikk Åpne tabelldefinisjon. På den tomme linjen under Brukernavn tabell, legger vi til en ny kolonne for e-posten. Navn kolonnen epostadresse, gi den typen nvarchar (MAX), og sjekk Tillat nuller alternativ. Klikk nå Oppdater for å lagre den nye versjonen av tabellen.

Dette gir oss en grunnleggende mal for et webprogram, med påloggingsstøtte, som ligner på hva mange forfattere ville starte med å prøve å lage et program. Hvis du kjører appen nå, vil du se at den viser og er funksjonell. trykk F5 eller bruk DEBUG -> Start feilsøking fra menyen for å hente opp nettsiden.


La oss lage en testkonto som vi kan bruke til dette eksempelet. Klikk på Registrere lenke og opprett en konto med hvilket som helst brukernavn og passord du vil ha. Her skal jeg bruke en konto som heter testuser. Etter opprettelsen ser du at jeg nå er logget inn som testbruker. Når du har gjort dette, må du avslutte og la oss legge til en side i dette programmet, slik at brukeren kan endre e-posten sin.


Før vi lager den siden for å endre e-postadressen, må vi først gjøre en endring til programmet slik at koden er klar over den nye kolonnen som vi nettopp har lagt til. Åpne AccountModels.cs fil under modeller mappe og oppdatere Brukerprofil klasse for å matche følgende. Dette forteller klassen om vår nye kolonne hvor vi lagrer e-postadressen for kontoen.

[Tabell ("UserProfile")] offentlig klasse UserProfile [Nøkkel] [DatabaseGeneratedAttribute (DatabaseGeneratedOption.Identity)] public int UserId get; sett;  offentlig streng Brukernavn get; sett;  offentlig streng EmailAddress get; sett; 

Åpne AccountController.cs fil. Etter RemoveExternalLogins funksjon legg til følgende kode for å opprette en ny handling. Dette vil få den nåværende e-posten for den innloggede brukeren og sende den til visningen for handlingen.

offentlig ActionResult ChangeEmail () // Få det loggede brukernavnet brukernavn = WebSecurity.CurrentUserName; string currentEmail; bruker (UsersContext db = new UsersContext ()) UserProfile user = db.UserProfiles.FirstOrDefault (u => u.UserName.ToLower () == brukernavn); currentEmail = user.EmailAddress;  returvisning (currentEmail); 

Vi må også legge til tilsvarende visning for denne handlingen. Dette bør være en fil som heter ChangeEmail.aspx under Visninger \ konto mappe:

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

Endre epostadresse

Nåværende E-postadresse: <%= Model ?? "Ingen nåværende e-post"%>

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

Dette gir oss en ny side vi kan bruke til å endre e-postadressen for den innloggede brukeren.


Hvis vi kjører denne siden og går til / Konto / ChangeEmail handling, vi ser nå at vi for øyeblikket ikke har en e-post. Men vi har en tekstboks og en knapp som vi kan bruke til å korrigere det. Først skjønt må vi opprette handlingen som skal utføres når skjemaet på denne siden er sendt inn.

[HttpPost] offentlig ActionResult ChangeEmail (ChangeEmailModel-modell) string brukernavn = WebSecurity.CurrentUserName; bruker (UsersContext db = new UsersContext ()) UserProfile user = db.UserProfiles.FirstOrDefault (u => u.UserName.ToLower () == brukernavn); user.EmailAddress = model.NewEmail; db.SaveChanges ();  // Og for å bekrefte endringen, få eposten fra profilen ChangeEmailModel newModel = new ChangeEmailModel (); bruker (UsersContext db = new UsersContext ()) UserProfile user = db.UserProfiles.FirstOrDefault (u => u.UserName.ToLower () == brukernavn); newModel.CurrentEmail = user.EmailAddress;  returvisning (newModel); 

Etter å ha gjort denne endringen, kjør nettstedet og gå igjen til / Konto / ChangeEmail handling som vi nettopp har opprettet. Du kan nå skrive inn en ny e-postadresse og klikke på Endre e-post knappen og se at e-postadressen vil bli oppdatert.


Angre nettstedet

Som skrevet, er søknaden vår sårbar for en overfallsforespørsel. La oss legge til en nettside for å se dette angrepet i aksjon. Vi skal legge til en side på nettsiden som vil endre e-posten til en annen verdi. I HomeController.cs fil legger vi til en ny handling kalt AttackForm.

offentlig ActionResult AttackForm () return View (); 

Vi legger også til en visning for dette navnet AttackForm.aspx under / Views / Home mappe. Det skal se slik ut:

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

Attack Form

Denne siden har skjult form for å angripe deg ved å endre e-postadressen din:

Vår side kunngjør hjelpsomt sin dårlige hensikt, som selvsagt et ekte angrep ikke ville gjøre. Denne siden inneholder en skjult form som ikke vil være synlig for brukeren. Deretter bruker den Javascript for å automatisk sende inn dette skjemaet når siden er lastet inn.


Hvis du kjører siden igjen og går til / Home / AttackForm siden, ser du at det laster opp helt fint, men uten utsyn på at noe har skjedd. Hvis du nå går til / Konto / ChangeEmail siden skjønner du at e-postadressen din er endret til [email protected]. Her gjør vi selvfølgelig det opplagt, men i et reelt angrep merker du kanskje ikke at e-posten din er endret.


Mitigating Cross-Site Request Forgery

Det er to primære måter å redusere denne type angrep. Først kan vi sjekke henvisningen som webforespørselen kommer fra. Dette bør fortelle søknaden når et skjemainnlegg ikke kommer fra vår server. Dette har imidlertid to problemer. Mange proxy-servere fjerner denne henvisningsinformasjonen, enten med vilje til å beskytte personvernet eller som en bivirkning, noe som betyr at en legitim forespørsel ikke kunne inneholde denne informasjonen. Det er også mulig for en angriper å fake henvisningen, selv om det øker kompleksiteten av angrepet.

Den mest effektive metoden er å kreve at det finnes et brukerspesifikt token for hver formularinnlevering. Denne tokenes verdi skal genereres tilfeldig, hver gang skjemaet opprettes, og skjemaet aksepteres bare hvis token er inkludert. Hvis token mangler eller en annen verdi er inkludert, tillater vi ikke skjemainnsendelsen. Denne verdien kan lagres enten i brukerens økttilstand eller i en informasjonskapsel slik at vi kan verifisere verdien når skjemaet er sendt inn.

ASP.NET gjør denne prosessen enkel, ettersom CSRF-støtte er innebygd. For å bruke den trenger vi bare å gjøre to endringer på vår nettside.


Å fikse problemet

Først må vi legge til det unike token til skjemaet for å endre brukerens e-post når vi viser det. Oppdater skjemaet i ChangeEmail.aspx se under / Konto / ChangeForm:

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

Denne nye linjen: <%: Html.AntiForgeryToken() %> forteller ASP.NET å generere et token og plassere det som et skjult felt i skjemaet. I tillegg håndterer rammen plassering på et annet sted der søknaden kan få tilgang til den senere for å bekrefte den.

Hvis vi laster opp siden nå og ser på kilden, ser vi denne nye linjen, i skjemaet, gjengitt til nettleseren. Dette er vårt token:

Vi må også gjøre en endring i handlingen vår for å gi den beskjed om at vi har lagt til dette symbolet og at det bør verifisere token før vi aksepterer den utgitte skjemaet.

Igjen er dette enkelt i ASP.NET MVC. På toppen av handlingen som vi opprettet for å håndtere utgitt skjema, den ene med [HttpPost] attributtet lagt til, legger vi til et annet attributt som heter [ValidateAntiForgeryToken]. Dette gjør starten på vår handling nå som følgende:

 [HttpPost] [ValidateAntiForgeryToken] offentlig ActionResult ChangeEmail (ChangeEmailModel modell) string brukernavn = WebSecurity.CurrentUserName; * Resten av funksjonen utelatt *

La oss teste dette ut. Først gå til / Konto / ChangeEmail side og gjenopprett e-posten for kontoen din til en kjent verdi. Så kan vi gå tilbake til / Home / AttackForm Siden og igjen forsøker angrepskoden å endre e-posten vår. Hvis du kommer tilbake til / Konto / ChangeEmail siden igjen, denne gangen vil du se at din tidligere innmeldte e-post er fortsatt trygg og intakt. Endringene vi har gjort i vårt skjema og handling har beskyttet denne siden fra angrepet.

Hvis du skulle se på angrepsformularen direkte (enkelt gjort ved å fjerne