Freigeben über


Verhindern von Cross-Site Request Forgery (CSRF)-Angriffen in einer ASP.NET MVC-Anwendung

Cross-Site Request Forgery (CSRF) ist ein Angriff, bei dem eine böswillige Website eine Anforderung an eine anfällige Website sendet, auf der der Benutzer derzeit angemeldet ist.

Hier ist ein Beispiel für einen CSRF-Angriff:

  1. Ein Benutzer meldet sich bei www.example.com mit Formularauthentifizierung an.

  2. Der Server authentifiziert den Benutzer. Die Antwort vom Server enthält ein Authentifizierungs-Cookie.

  3. Ohne Abmelden besucht der Benutzer eine bösartige Website. Diese bösartige Website enthält das folgende HTML-Formular:

    <h1>You Are a Winner!</h1>
      <form action="http://example.com/api/account" method="post">
        <input type="hidden" name="Transaction" value="withdraw" />
        <input type="hidden" name="Amount" value="1000000" />
      <input type="submit" value="Click Me"/>
    </form>
    

    Beachten Sie, dass die Formularaktion auf der anfälligen Website und nicht auf der bösartigen Website veröffentlicht wird. Dies ist der websiteübergreifende Teil von CSRF.

  4. Der Benutzer klickt auf die Schaltfläche "Absenden". Der Browser sendet das Authentifizierungs-Cookie mit der Anfrage.

  5. Die Anforderung wird auf dem Server mit dem Authentifizierungskontext des Benutzers ausgeführt und kann alles tun, was ein authentifizierter Benutzer tun darf.

Obwohl in diesem Beispiel der Benutzer auf die Formularschaltfläche klickt, kann die schädliche Seite genauso einfach ein Skript ausführen, das das Formular automatisch sendet. Darüber hinaus verhindert die Verwendung von SSL keinen CSRF-Angriff, da die bösartige Website eine "https://"-Anforderung senden kann.

In der Regel sind CSRF-Angriffe gegen Websites möglich, die Cookies für die Authentifizierung verwenden, da Browser alle relevanten Cookies an die Zielwebsite senden. CSRF-Angriffe sind jedoch nicht auf das Ausnutzen von Cookies beschränkt. Beispielsweise sind auch die Basic- und Digest-Authentifizierung anfällig. Nachdem sich ein Benutzer mit der Basic- oder Digest-Authentifizierung angemeldet hat. Der Browser sendet die Anmeldeinformationen automatisch, bis die Sitzung endet.

Anti-Fälschungs-Token

Um CSRF-Angriffe zu verhindern, verwendet ASP.NET MVC Anti-Fälschungstoken, auch als Anforderungsüberprüfungstoken bezeichnet.

  1. Der Client fordert eine HTML-Seite an, die ein Formular enthält.
  2. Der Server enthält zwei Token in der Antwort. Ein Token wird als Cookie gesendet. Die andere wird in einem ausgeblendeten Formularfeld platziert. Die Token werden zufällig generiert, sodass ein Angreifer die Werte nicht erraten kann.
  3. Wenn der Client das Formular sendet, muss er beide Token zurück an den Server senden. Der Client sendet das Cookie-Token als Cookie und sendet das Formulartoken innerhalb der Formulardaten. (Ein Browserclient führt dies automatisch aus, wenn der Benutzer das Formular sendet.)
  4. Wenn eine Anforderung nicht beide Token enthält, lässt der Server die Anforderung nicht zu.

Hier ist ein Beispiel für ein HTML-Formular mit einem ausgeblendeten Formulartoken:

<form action="/Home/Test" method="post">
    <input name="__RequestVerificationToken" type="hidden"   
           value="6fGBtLZmVBZ59oUad1Fr33BuPxANKY9q3Srr5y[...]" />    
    <input type="submit" value="Submit" />
</form>

Tokens zur Verhinderung von Fälschung funktionieren, da die bösartige Seite die Tokens des Benutzers aufgrund von Same-Origin-Richtlinien nicht lesen kann. (Richtlinien für den gleichen Ursprung verhindern, dass Dokumente, die auf zwei verschiedenen Websites gehostet werden, auf die Inhalte der anderen zugreifen. Im vorherigen Beispiel kann die bösartige Seite Anforderungen an example.com senden, aber sie kann die Antwort nicht lesen.)

Um CSRF-Angriffe zu verhindern, verwenden Sie Anti-Fälschungstoken mit jedem Authentifizierungsprotokoll, bei dem der Browser im Hintergrund Anmeldeinformationen sendet, nachdem sich der Benutzer angemeldet hat. Dazu gehören cookiebasierte Authentifizierungsprotokolle, z. B. Formularauthentifizierung, sowie Protokolle wie Standard- und Digestauthentifizierung.

Sie sollten Anti-Fälschungstoken für alle nicht sicheren Methoden (POST, PUT, DELETE) benötigen. Stellen Sie außerdem sicher, dass sichere Methoden (GET, HEAD) keine Nebenwirkungen haben. Wenn Sie außerdem domänenübergreifende Unterstützung aktivieren, z. B. CORS oder JSONP, sind sogar sichere Methoden wie GET potenziell anfällig für CSRF-Angriffe, sodass der Angreifer potenziell vertrauliche Daten lesen kann.

Anti-Fälschungstoken in ASP.NET MVC

Um die Anti-Fälschungstoken zu einer Razor-Seite hinzuzufügen, verwenden Sie die HtmlHelper.AntiForgeryToken-Hilfsmethode :

@using (Html.BeginForm("Manage", "Account")) {
    @Html.AntiForgeryToken()
}

Diese Methode fügt das ausgeblendete Formularfeld hinzu und legt auch das Cookie-Token fest.

Anti-CSRF und AJAX

Das Formulartoken kann ein Problem für AJAX-Anforderungen sein, da eine AJAX-Anforderung JSON-Daten und keine HTML-Formulardaten senden kann. Eine Lösung besteht darin, die Token in einem benutzerdefinierten HTTP-Header zu senden. Der folgende Code verwendet Razor-Syntax, um die Token zu generieren, und fügt dann die Token zu einer AJAX-Anforderung hinzu. Die Token werden auf dem Server durch Aufrufen von AntiForgery.GetTokens generiert.

<script>
    @functions{
        public string TokenHeaderValue()
        {
            string cookieToken, formToken;
            AntiForgery.GetTokens(null, out cookieToken, out formToken);
            return cookieToken + ":" + formToken;                
        }
    }

    $.ajax("api/values", {
        type: "post",
        contentType: "application/json",
        data: {  }, // JSON data goes here
        dataType: "json",
        headers: {
            'RequestVerificationToken': '@TokenHeaderValue()'
        }
    });
</script>

Wenn Sie die Anforderung verarbeiten, extrahieren Sie die Token aus dem Anforderungsheader. Rufen Sie dann die AntiForgery.Validate-Methode auf, um die Token zu überprüfen. Die Validate-Methode löst eine Ausnahme aus, wenn die Token ungültig sind.

void ValidateRequestHeader(HttpRequestMessage request)
{
    string cookieToken = "";
    string formToken = "";

    IEnumerable<string> tokenHeaders;
    if (request.Headers.TryGetValues("RequestVerificationToken", out tokenHeaders))
    {
        string[] tokens = tokenHeaders.First().Split(':');
        if (tokens.Length == 2)
        {
            cookieToken = tokens[0].Trim();
            formToken = tokens[1].Trim();
        }
    }
    AntiForgery.Validate(cookieToken, formToken);
}