Verhindern von CsrF-Angriffen (Cross-Site Request Forgery) in ASP.NET MVC-Anwendung
Cross-Site Request Forgery (CSRF) ist ein Angriff, bei dem eine böswillige Website eine Anforderung an einen anfälligen Standort sendet, auf dem der Benutzer derzeit angemeldet ist.
Hier sehen Sie ein Beispiel für einen CSRF-Angriff:
Ein Benutzer meldet sich mit der Formularauthentifizierung an
www.example.com
.Der Server authentifiziert den Benutzer. Die Antwort vom Server enthält ein Authentifizierungscookies.
Ohne Sich abmelden, besucht der Benutzer eine böswillige Website. Diese böswillige 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 Beiträge auf der anfälligen Website und nicht auf der böswilligen Website sendet. Dies ist der "websiteübergreifende" Teil von CSRF.
Der Benutzer klickt auf die Schaltfläche Senden. Der Browser enthält das Authentifizierungscookies mit der Anforderung.
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 klicken muss, kann die böswillige Seite genauso einfach ein Skript ausführen, das das Formular automatisch übermittelt. Darüber hinaus verhindert die Verwendung von SSL keinen CSRF-Angriff, da die böswillige Website eine "https://"-Anforderung senden kann.
In der Regel sind CSRF-Angriffe auf 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 die Standard- und Digestauthentifizierung ebenfalls anfällig. Nachdem sich ein Benutzer mit der Standard- oder Digestauthentifizierung angemeldet hat. Der Browser sendet die Anmeldeinformationen automatisch bis zum Ende der Sitzung.
Antifälschungstoken
Um CSRF-Angriffe zu verhindern, verwendet ASP.NET MVC Antifälschungstoken, die auch als Anforderungsüberprüfungstoken bezeichnet werden.
- Der Client fordert eine HTML-Seite an, die ein Formular enthält.
- 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.
- Wenn der Client das Formular übermittelt, muss er beide Token zurück an den Server senden. Der Client sendet das Cookietoken als Cookie und das Formulartoken in den Formulardaten. (Ein Browserclient führt dies automatisch durch, wenn der Benutzer das Formular übermittelt.)
- Wenn eine Anforderung nicht beide Token enthält, lässt der Server die Anforderung nicht zu.
Hier sehen Sie 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>
Antifälschungstoken funktionieren, weil die böswillige Seite die Token des Benutzers aufgrund von Richtlinien desselben Ursprungs nicht lesen kann. (Richtlinien mit gleichem Ursprung verhindern, dass Dokumente, die auf zwei verschiedenen Websites gehostet werden, auf die Inhalte des jeweils anderen zugreifen. Im vorherigen Beispiel kann die böswillige Seite Also Anforderungen an example.com senden, aber sie kann die Antwort nicht lesen.)
Um CSRF-Angriffe zu verhindern, verwenden Sie Antifälschungstoken mit jedem Authentifizierungsprotokoll, an das der Browser anmeldet, nachdem sich der Benutzer angemeldet hat. Dies umfasst cookiebasierte Authentifizierungsprotokolle, z. B. Formularauthentifizierung, sowie Protokolle wie Die Standard- und Digestauthentifizierung.
Sie sollten Antifälschungstoken für alle unsicheren 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 wie CORS oder JSONP aktivieren, sind auch sichere Methoden wie GET potenziell anfällig für CSRF-Angriffe, sodass der Angreifer potenziell vertrauliche Daten lesen kann.
Antifälschungstoken in ASP.NET MVC
Um die Antifä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 Cookietoken fest.
Anti-CSRF und AJAX
Das Formulartoken kann für AJAX-Anforderungen ein Problem darstellen, da eine AJAX-Anforderung unter Umständen JSON-Daten und keine HTML-Formulardaten sendet. Eine Lösung besteht darin, die Token in einem benutzerdefinierten HTTP-Header zu senden. Im folgenden Code wird Razor-Syntax zum Generieren der Token verwendet, und anschließend werden die Token einer AJAX-Anforderung hinzugefügt. Die Token werden auf dem Server generiert, indem AntiForgery.GetTokens aufgerufen wird.
<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>
Extrahieren Sie die Token beim Verarbeiten der Anforderung 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);
}