Wie sichere ich REST-API-Aufrufe?

91

Ich entwickle die erholsame Web-App, die beispielsweise ein beliebtes Web-Framework im Backend verwendet (Rails, Sinatra, Flask, Express.js). Idealerweise möchte ich die Client-Seite mit Backbone.js entwickeln. Wie lasse ich nur meine Javascript-Clientseite mit diesen API-Aufrufen interagieren? Ich möchte nicht, dass diese API-Aufrufe öffentlich sind und von curloder einfach durch Eingabe des Links im Browser aufgerufen werden .

knd
quelle
Haben alle Ihre API-Aufrufe ein Token erfordert, das an den Client übergeben wird, wenn Ihre Seite bereitgestellt wird?
Hajpoj
Amazon AWS Javascript SDK verwendet vorsignierte
rjha94

Antworten:

90

Wenn Ihre API von Ihrem JS-Client verwendet wird, müssen Sie zunächst davon ausgehen, dass sie öffentlich ist: Ein einfacher JS-Debugger versetzt einen Angreifer in die Lage, eine byteweise identische Anforderung von a zu senden Werkzeug seiner Wahl.

Wenn ich Ihre Frage jedoch richtig lese, ist dies nicht das, was Sie vermeiden möchten: Was Sie wirklich nicht wollen, ist, dass Ihre API (regelmäßig) verwendet wird, ohne dass Ihr JS-Client beteiligt ist. Hier sind einige Ideen, wie Sie, wenn Sie dies nicht durchsetzen, zumindest die Verwendung Ihres Kunden fördern können:

  • Ich bin sicher, Ihre API verfügt über eine Art Authentifizierungsfeld (z. B. auf dem Client berechneter Hash). Wenn nicht, werfen Sie einen Blick auf diese SO-Frage . Stellen Sie sicher, dass Sie einen Salt (oder sogar einen API-Schlüssel) verwenden, der Ihrem JS-Client auf Sitzungsbasis übergeben wird (nicht fest codiert). Auf diese Weise wird ein nicht autorisierter Benutzer Ihrer API zu viel mehr Arbeit gezwungen.

  • Denken Sie beim Laden des JS-Clients an einige HTTP-Header (der Benutzeragent fällt mir ein) und die IP-Adresse und fordern Sie bei Änderungen eine erneute Authentifizierung an. Verwenden Sie dabei Blacklists für die üblichen Verdächtigen. Dies zwingt einen Angreifer, seine Hausaufgaben noch einmal gründlicher zu machen.

  • Denken Sie auf der Serverseite an die letzten API-Aufrufe und prüfen Sie vor dem Zulassen eines weiteren Aufrufs, ob die Geschäftslogik den neuen zulässt: Dies verweigert einem Angreifer die Möglichkeit, viele seiner Sitzungen auf eine Sitzung mit Ihrem Server zu konzentrieren: In In Kombination mit den anderen Maßnahmen ist ein Missbraucher leicht erkennbar.

Ich hätte das vielleicht nicht mit der nötigen Klarheit gesagt: Ich halte es für unmöglich , es einem Missbraucher völlig unmöglich zu machen, Ihren Dienst zu konsumieren, aber Sie können es so schwer machen, dass es den Aufwand möglicherweise nicht wert ist.

Eugen Rieck
quelle
Dies ist eine hilfreiche Information, aber was ist, wenn ich eine Authentifizierung von meiner Backend-API zu einer anderen API-App wie einem separaten Server vornehmen möchte, um meine Frage zu vereinfachen? Ich möchte, dass mein Backend, auch bekannt als node.js, eine Abrufanforderung an ein anderes Backend sendet. Endserver, der mein eigener ist, aus bestimmten Gründen ist dies erforderlich, aber ich möchte die API-Aufrufe sichern, da er auf vertrauliche Daten zugreifen kann und ich keine Sitzungen oder JWT verwenden kann, weil ich sie nicht tatsächlich im Browser speichern kann.
Die Pyramide
@Thepyramid Es spielt keine Rolle, was der API-Aufruf auf der Serverseite bewirkt, insbesondere wenn die Serverseite einen weiteren API-Aufruf der zweiten Ebene ausführt. Der wichtige Teil besteht darin, Ihren Server nicht als Proxy, sondern als Anwendung zu behandeln.
Eugen Rieck
Können Sie mehr erklären, wie man als Antrag nicht als Proxy macht
Die Pyramide
1
Was ich meine ist: Um ein angemessenes Maß an Sicherheit zu erhalten, müssen Sie alle Tools verwenden, die eine Webanwendung hat: Sitzungen, eine Authentifizierungsdatenbank, eine Geschäftslogik. Wenn Sie dies nicht tun und Ihren Server nur als eine Möglichkeit behandeln, Anforderungen an einen anderen Server weiterzuleiten, verwenden Sie ihn lediglich als Proxy für diesen anderen Server und sind durch die Sicherheit, die der andere Server bietet, eingeschränkt.
Eugen Rieck
1
@PirateApp Ein Angreifer kann die CSRF-Header einfach ignorieren. Sie funktionieren nur, wenn das Endgerät ein nicht gepatchter Browser ist
Eugen Rieck
12

Sie sollten eine Art Authentifizierungssystem implementieren. Eine gute Möglichkeit, damit umzugehen, besteht darin, einige erwartete Header-Variablen zu definieren. Beispielsweise können Sie einen Auth / Login-API-Aufruf haben, der ein Sitzungstoken zurückgibt. Bei nachfolgenden Aufrufen Ihrer API wird erwartet, dass ein Sitzungstoken in einer HTTP-Headervariablen mit einem bestimmten Namen wie "your-api-token" festgelegt wird.

Alternativ erstellen viele Systeme Zugriffstoken oder Schlüssel, die erwartet werden (wie YouTube, Facebook oder Twitter), mithilfe eines API-Kontosystems. In diesen Fällen müsste Ihr Client diese auf irgendeine Weise im Client speichern.

Dann müssen Sie lediglich eine Prüfung für die Sitzung in Ihr REST-Framework einfügen und eine Ausnahme auslösen. Wenn möglich, wäre der Statuscode (um sich zu erholen) ein 401-Fehler.

gview
quelle
8
Obwohl nichts sie davon abhält, auf die Überschriften zu schauen und sie zu reproduzieren.
CDMckay
1
@cdmckay - Ein Token muss mit einem in einer Sitzung gespeicherten Token übereinstimmen. Das einfache Reproduzieren des Headers führt zu einer "nicht autorisierten" Antwort, wenn er aus einer anderen Sitzung stammt.
Andrei Volgin
3
Sie können immer noch dieselbe Sitzung verwenden und die Anforderungen ändern, bevor sie an die API gesendet werden ... oder sogar zur Laufzeit über die Konsole einen Aufruf mit passenden Headern / Feldern generieren, die nur die Teile ändern, die Sie benötigen ...
Potter Rafed
2
@PotterRafed: Wenn ein Benutzer auf seine eigene gültige Sitzung zugreift, wird diese über eine App aufgerufen, ohne sie anzugreifen. Der Zweck der Authentifizierung besteht darin, den Zugriff auf die Sitzungen / Daten anderer Benutzer zu verhindern .
Andrei Volgin
@ AndreiVolgin ja fair genug, aber es ist immer noch eine Sicherheitslücke
Potter Rafed
9

Es gibt jetzt einen offenen Standard namens "JSON Web Token".

Siehe https://jwt.io/ & https://en.wikipedia.org/wiki/JSON_Web_Token

JSON Web Token (JWT) ist ein JSON-basierter offener Standard (RFC 7519) zum Erstellen von Token, die eine bestimmte Anzahl von Ansprüchen geltend machen. Ein Server könnte beispielsweise ein Token mit dem Anspruch "Als Administrator angemeldet" generieren und dieses einem Client zur Verfügung stellen. Der Client könnte dieses Token dann verwenden, um zu beweisen, dass er als Administrator angemeldet ist. Die Token werden vom Serverschlüssel signiert, sodass der Server überprüfen kann, ob das Token legitim ist. Die Token sind kompakt, URL-sicher und können insbesondere im SSO-Kontext (Single Sign-On) des Webbrowsers verwendet werden. JWT-Ansprüche können normalerweise verwendet werden, um die Identität authentifizierter Benutzer zwischen einem Identitätsanbieter und einem Dienstanbieter oder eine andere Art von Ansprüchen zu übertragen, die für Geschäftsprozesse erforderlich sind. [1] [2] Die Token können auch authentifiziert und verschlüsselt werden. [3] [4]

bbozo
quelle
Was würde einen Benutzer daran hindern, sein Token zu kopieren und in einer anderen Antwort zu verwenden?
Ulad Kasach
1
@UladKasach um ehrlich zu sein, ich habe mich nie wirklich mit ihnen befasst, aber afaik sie sind ablauffähig, einzigartig für Ihren Benutzer und mit SSL verschlüsselt (was Sie natürlich üben), es ist genau die gleiche Idee hinter oauth afaik
bbozo
3

Entschuldigen Sie @MarkAmery und Eugene, aber das ist falsch.

Ihre im Browser ausgeführte js + html (Client) -App kann so eingerichtet werden, dass nicht autorisierte direkte Aufrufe der API wie folgt ausgeschlossen werden:

  1. Erster Schritt: Richten Sie die API so ein, dass eine Authentifizierung erforderlich ist. Der Client muss sich zuerst über den Server (oder einen anderen Sicherheitsserver) authentifizieren und beispielsweise den menschlichen Benutzer auffordern, das richtige Kennwort anzugeben.

Vor der Authentifizierung werden die Aufrufe der API nicht akzeptiert.

Während der Authentifizierung wird ein "Token" zurückgegeben.

Nach der Authentifizierung werden nur API-Aufrufe mit dem Authentifizierungstoken akzeptiert.

Zu diesem Zeitpunkt können natürlich nur autorisierte Benutzer mit dem Kennwort auf die API zugreifen. Wenn sie jedoch Programmierer sind, die die App debuggen, können sie zu Testzwecken direkt darauf zugreifen.

  1. Zweiter Schritt: Richten Sie nun eine zusätzliche Sicherheits-API ein, die innerhalb kurzer Zeit aufgerufen werden soll, nachdem die Client-App js + html ursprünglich vom Server angefordert wurde. Dieser "Rückruf" teilt dem Server mit, dass der Client erfolgreich heruntergeladen wurde. Beschränken Sie die Funktion Ihrer REST-API-Aufrufe nur, wenn der Client kürzlich und erfolgreich angefordert wurde.

Um Ihre API verwenden zu können, müssen sie zuerst den Client herunterladen und ihn tatsächlich in einem Browser ausführen. Erst nach erfolgreichem Empfang des Rückrufs und anschließender Benutzereingabe innerhalb kurzer Zeit akzeptiert die API Anrufe.

Sie müssen sich also keine Sorgen machen, dass dies ein nicht autorisierter Benutzer ohne Anmeldeinformationen ist.

(Der Titel der Frage "Wie sichere ich REST-API-Aufrufe?" Und nach den meisten Ihrer Aussagen ist dies Ihr Hauptanliegen und nicht die wörtliche Frage, wie Ihre API aufgerufen wird, sondern von wem, richtig? )

pashute
quelle
5
Der zweite Punkt macht keinen Sinn. Wenn ein Angreifer Ihre App laden muss, wird er dies tun (Ihr Rückruf ist sichtbar). Und dann angreifen.
Andrei Volgin
Punkt 2 ist zusätzlich zu Punkt 1. Der Angreifer benötigt noch eine Authentifizierung. Punkt 2 fügt nur hinzu, dass die HTML-App tatsächlich heruntergeladen werden muss, um autorisiert zu werden. Ein direkter Aufruf der APIs ohne die App (vermutlich erst nach Authentifizierung aufgerufen und heruntergeladen) ist daher nicht möglich. Welches ist etwas, das in dieser Frage angefordert wurde.
Pashute
Sie können einfach nur Anfragen von Ihrer Domain zulassen.
Andrei Volgin
Das beschränkt die Aufrufe nur auf das Innere der Domäne. Daher müssen sich die Benutzer der Javascript-Browser-App jetzt innerhalb der Domäne befinden (wahrscheinlich nicht gewollt), und diese Benutzer können die API weiterhin direkt über Curl aufrufen.
Pashute
2
Was Sie zu übersehen scheinen, ist, dass, WAS auch immer Sie den Browser Ihres Benutzers dazu auffordern, von einem Angreifer repliziert werden kann - damit der Browser dies tut, muss er lesbar sein.
Eugen Rieck
1
  1. Legen Sie eine SESSION-Variable auf dem Server fest, wenn der Client Ihre index.html(oder backbone.jsusw.) zum ersten Mal lädt .

  2. Überprüfen Sie diese Variable auf der Serverseite bei jedem API-Aufruf.

PS das ist keine "Sicherheits" -Lösung !!! Dies dient nur dazu, die Belastung Ihres Servers zu verringern, damit die Benutzer ihn nicht missbrauchen oder Ihre API von anderen Websites und Apps aus "verlinken".

Alex
quelle
0

Folgendes mache ich:

  1. Sichern Sie die API mit einem HTTP-Header mit Aufrufen wie X-APITOKEN:

  2. Verwenden Sie Sitzungsvariablen in PHP. Verfügen Sie über ein Anmeldesystem und speichern Sie das Benutzertoken in Sitzungsvariablen.

  3. Rufen Sie JS-Code mit Ajax zu PHP auf und verwenden Sie die Sitzungsvariable mit curl, um die API aufzurufen. Auf diese Weise wird die Sitzungsvariable nicht aufgerufen, wenn sie nicht festgelegt ist, und der PHP-Code enthält das Zugriffstoken für die API.

Pavneet Singh
quelle