wie Verweiser in einem MVC oder Web API Ajax Anruf zu überprüfen

8

Meine MVC-App hat gemeinsame Ajax-Methoden (in Web-API und regulären Controller). Ich möchte diese Anrufe basierend auf dem Bereich (Ansicht) meiner App autorisieren, von dem der Anruf kommt. Das Problem, dem ich gegenüberstehe, ist, wie man den Ursprung des Ajax-Anrufs verifiziert.

Mir ist klar, dass dies nicht so einfach möglich ist, da Ajax-Aufrufe leicht zu parodieren sind, aber da ich die volle Kontrolle darüber habe, wie die Ansicht gerendert wird (ganzseitige Quelle), gibt es vielleicht eine Möglichkeit, Anti-Fälschungs-Tokens einzubetten später zu einem URL-Referrer verifiziert werden.

Die Authentifizierung wird bereits durchgeführt, und ich kann die Identität des Anrufs sicher überprüfen. Das einzige Problem besteht darin, zu überprüfen, von welcher URL (MVC-Route) der Anruf kam. Genauer gesagt wird verhindert, dass der Benutzer den Ursprung des Ajax-Anrufs manipulieren kann.

Ich habe versucht, einen benutzerdefinierten Berechtigungsheader zu erstellen und ihn zwischen Ansichtsrendern und Ajaxaufrufen zu übergeben, und das funktioniert, aber immer noch leicht zu fälschen (da ein Benutzer die Header von einem anderen Teil der Site aus schnüffeln und diese wiederverwenden könnte). Am Ende bin ich mir nicht sicher, wie sicher zu überprüfen ist, dass der Header nicht gefälscht wurde. Die einzige Sache, die einem einfällt, ist, einige Informationen über den ursprünglichen Kontext innerhalb des Tokens zu kodieren und sie irgendwie gegen den eingehenden Anrufkontext zu validieren (der, der das Token in einem Ajax-Aufruf weiterleitet).

Ich sehe, dass MVC AntiForgen-Token-Fähigkeiten hat, aber ich bin mir nicht sicher, ob das mein Problem lösen kann. Wenn ja, würde ich gerne wissen, wie es verwendet werden könnte, um zu überprüfen, ob /api/common/update von /home/index vs /user/setup aufgerufen wurde (beide Aufrufe sind gültig).

Auch hier möchte ich herausfinden, von welcher Seite ein Ajax-Anruf kommt, und die Benutzeridentität ist nicht das Problem.

update

nach @Sarathy empfohlen Ich habe versucht, Anti-Fälschungs-Token zu implementieren. Soweit ich das beurteilen kann, funktioniert das, indem auf jeder Seite ein verstecktes Feld mit Token hinzugefügt und mit einem Token in einem Cookie verglichen wird. Hier ist meine Implementierung des benutzerdefinierten Aktionsfilterattributs, das die Tokenvalidierung durchführt:

%Vor%

dann sieht mein zusätzlicher Anti-Fälschungs-Datenanbieter wie folgt aus:

%Vor%

Das funktioniert, da ich die korrekten Seiten sehen kann, die im Provider geloggt sind, und Anti-Fälschung bricht mit den Tokens ab.

Aber wenn ich nicht etwas falsch gemacht habe, scheint das trivial zu sein. beispielsweise Wenn ich zu pageA gehe und das Token-Formular pageB (nur das Form-Token, nicht einmal das Cookie-Token) kopiere, ist das immer noch erfolgreich, und in meinen Protokollen sehe ich pageB während der Ausführung der ajax-Methode von pageA

hat bestätigt, dass dies leicht zu spoofieren ist .

Ich verwende csrf, um ajax-Tokens wie folgt zu generieren:

%Vor%

Ich gebe dann das Formular-Token mit jedem Ajax-Aufruf zurück und habe ein benutzerdefiniertes Aktionsfilterattribut, wo ich es zusammen mit dem Cookie-Token lese / validiere

%Vor%

Das alles funktioniert (wenn Sie etwas über das Token ändern, löst die korrekte Ausnahme aus), dann kann ich in meinem IAntiForgeryAdditionalDataProvider sehen, was es denkt, dass es verarbeitet.

Sobald ich das csrf-Token von einer anderen Ansicht aus überschreibe, denkt es, dass es diese Ansicht ist. Ich muss nicht einmal den UrlReferrer manipulieren, um das zu brechen: /

Eine Möglichkeit, wie das funktionieren könnte, wenn ich den Cookie zwingen könnte, bei jedem Laden der Seite anders zu sein

    
Sonic Soul 11.02.2015, 23:24
quelle

4 Antworten

1

Sie haben in Ihrer Frage erwähnt, dass Sie nach Anti-Fälschungs-Token-Funktionen suchen.

Daher denke ich, dass Sie nach einer Anti-CSRF-Lösung fragen (CSRF = Cross Site Request Forgery).

Eine Möglichkeit besteht darin, eine echte Zufallszahl (ein einmaliges Token) in Ihre Seite einzufügen und sie dann bei jeder Anfrage weiterzugeben. Dies kann durch Hinzufügen eines Schlüssels / Werts erfolgen Pairing mit dem Header der Anfrage und dann am Backend (dh in Ihrem Controller) überprüft. Dies ist ein Challenge-Response Ansatz.

Wie Sie bereits erwähnt haben, können Sie im serverseitigen Code

verwenden %Vor%

um es von der anfragenden Seite zu bekommen.

Um es von jeder Client-AJAX-Anfrage der Seite weiterzugeben, können Sie

verwenden %Vor%

oder Sie können es für jede Anfrage mit

festlegen %Vor%

Beachten Sie, dass tokenValue die Zufallszahl enthalten muss, die vom Webserver beim Senden der Webseite an den Client gerendert wurde.

Ich würde dafür keine Cookies verwenden, da Cookies Sie nicht gegen CSRF schützen - Sie müssen sicherstellen, dass die Seite, die angefordert wird, mit der Seite übereinstimmt, die gerendert wurde (und daher vom Webserver erstellt wurde). . Eine Seite, die sich auf einer anderen Registerkarte im selben Browserfenster befindet, könnte ebenfalls den Cookie verwenden.

Details finden Sie auf der Seite OWASP-Projekt im Überraschungspool für CSRF-Prävention .

    
Matt 24.02.2015 12:19
quelle
1

Meine schnelle Übergangslösung bestand darin, benutzerdefinierte Token zu verwenden, die bei jedem Laden der Seite erstellt wurden (die ich in meinem Token-Cache verfolge), die als Header in allen Ajax-Aufrufen übergeben werden. Zusätzlich erstelle ich einen originalen URL-Hash und kombiniere ihn in das benutzerdefinierte Authentifizierungs-Token. In meinen Ajax-Methoden extrahiere ich dann den Hash und vergleiche ihn mit UrlReferrer-Hash, um sicherzustellen, dass nicht manipuliert wurde. Da das benutzerdefinierte Token immer anders ist, ist es weniger offensichtlich zu erraten, was passiert, da das Token bei jedem Laden der Seite unterschiedlich aussieht. Dies ist jedoch nicht sicher, da mit genügend Aufwand der URL-Hash aufgedeckt werden kann. Die Exposition ist etwas eingeschränkt, da die Benutzeridentität nicht das Problem ist. Im schlimmsten Fall würde ein gegebener Benutzer Schreibzugriff auf einen anderen Abschnitt der Site erhalten, aber nur als er selbst. Meine Site ist intern und ich überprüfe jede Bewegung, so dass alle Temperamentsversuche schnell erfasst werden.

Ich verwende sowohl jQuery als auch angular so anhängende Tokens mit allen Anfragen wie folgt:

%Vor%

update

Der Nachteil dieses Ansatzes besteht darin, dass benutzerdefinierte Token über eine Webfarm hinweg beibehalten werden müssen oder dass die App neu gestartet wird. Basierend auf der Idee von @ Sarathy versuche ich dies durch die Nutzung von MVC Anti-Fälschungs-Framework zu unterstützen. Im Grunde add / remove meine "Salz" und lassen Sie das Framework die tatsächliche Token-Validierung verwalten. So ist es etwas weniger für mich. Werde mehr Details posten, sobald ich verifiziere, dass das funktioniert.

    
Sonic Soul 13.02.2015 03:13
quelle
0

Das wird also eine der "Du machst es falsch" -Antworten, die ich nicht mag, und so entschuldige ich mich im Voraus. Auf jeden Fall werde ich Ihnen aus der Frage und den Kommentaren vorschlagen, dass Sie das Problem anders angehen. Anstatt darüber nachzudenken, woher die Anfrage kam, denke darüber nach, was die Anfrage zu tun versucht. Sie müssen feststellen, ob der Benutzer das tun kann.

Meine Vermutung, warum das in Ihrem Fall schwer ist, glaube ich, dass Sie Ihre API-Schnittstelle zu generisch gemacht haben. Von Ihrem Beispiel api "api / common / update" Ich vermute, Sie haben eine generische Update-API, die alles aktualisieren kann, und Sie wollen Updatedaten X von einer Seite schützen, die nur auf Daten Y zugreifen soll. Wenn ich es bin Von der Basis ignorierst du mich dann. :)

Meine Antwort wäre also: Tu das nicht. Ändern Sie Ihre API so, dass sie mit den Daten beginnt, mit denen Sie arbeiten möchten: api / dataX api / dataY. Verwenden Sie dann Benutzerrollen, um diese API-Methoden angemessen zu schützen. Hinter den Kulissen können Sie immer noch eine gemeinsame Update-Routine haben, wenn Sie das mögen und es für Sie funktioniert, aber behalten Sie die API-Schnittstelle konkreter.

Wenn Sie wirklich keine API für jede Tabelle haben wollen, und wenn es für Sie geeignet ist, können Sie vielleicht wenigstens eine API für geschützte / Admin-Tabellen und eine separate API für die Standardtabellen haben. Eine Menge "wenn" s, aber vielleicht würde das für Ihre Situation funktionieren.

Wenn Ihr Benutzer außerdem einige dataX, aber keine anderen dataX aktualisieren kann, müssen Sie eine Überprüfung Ihrer Daten vornehmen, idealerweise mit einem root-Objekt und ob Ihr Benutzer berechtigt ist, dieses root-Objekt zu sehen / zu benutzen .

Um zusammenzufassen, vermeiden Sie eine übermäßig generische API-Schnittstelle. Indem Sie konkreter werden, können Sie die vorhandenen Sicherheitstools verwenden, um Ihnen zu helfen.

Und viel Glück!

    
eol 20.02.2015 17:53
quelle
0

Ich gehe davon aus, dass Sie hierfür IAntiForgeryAdditionalDataProvider verwenden können.

%Vor%

Registrieren Sie den Provider wie unten beschrieben in App_Start.

%Vor%

Ссылка

Ich hoffe, dies hilft in Ihrem Szenario.

    
Sarathy 23.02.2015 09:13
quelle