2015-03-07 6 views
34

Ich habe eine Spring REST-Anwendung, die zunächst mit Basic-Authentifizierung gesichert wurde.Ist das Sichern einer REST-Anwendung mit JWT- und Basic-Authentifizierung sinnvoll?

Dann habe ich einen Login-Controller hinzugefügt, der ein JWT JSON Web Token erstellt, das in nachfolgenden Anfragen verwendet wird.

Könnte ich den folgenden Code aus dem Login-Controller und in den Sicherheitsfilter verschieben? Dann würde ich den Login-Controller nicht mehr brauchen.

tokenAuthenticationService.addTokenToResponseHeader(responseHeaders, credentialsResource.getEmail()); 

Oder könnte ich die Standardauthentifizierung entfernen?

Ist es ein gutes Design, um die Standardauthentifizierung mit einem JWT zu kombinieren?

Obwohl alles gut funktioniert, bin ich hier ein wenig im Dunkeln, um diese Sicherheit am besten zu gestalten.

+0

Wie wird das Token in nachfolgenden Anfragen an den Server gesendet? (HTTP Header? Cookie?). Verwenden Sie auch TLS (SSL)? –

+0

Hallo Les, schön dich wiederzusehen! Ja, das Token wird als X-Auth-Token-Header gesendet. Ich benutze auch TLS. Ist TLS bei Verwendung eines JWT obligatorisch? – Stephane

+0

Hallo Stephane! :) Wenn der JWT eine verifizierte Identität darstellt, würde ich TLS als zwingend betrachten, ansonsten ist es (viel) einfacher für MITM-Angriffe. –

Antwort

66

Angenommen, 100% TLS für die gesamte Kommunikation - sowohl während als auch zu jeder Zeit nach der Anmeldung - ist die Authentifizierung mit Benutzername/Passwort über die Standardauthentifizierung und das Empfangen einer JWT im Austausch ein gültiger Anwendungsfall. Dies ist fast genau wie einer der OAuth 2's fließt ("Passwort gewähren").

Die Idee ist, dass der Endbenutzer über einen Endpunkt authentifiziert wird, z. /login/token Verwenden Sie den gewünschten Mechanismus, und die Antwort sollte die JWT enthalten, die bei allen nachfolgenden Anforderungen zurückgesendet werden soll. Der JWT sollte ein JWS (d. H. Ein kryptografisch signierter JWT) mit einem geeigneten JWT-Ablaufdatum (exp) -Feld sein: Dies stellt sicher, dass der Client den JWT nicht manipulieren oder länger leben kann, als er sollte.

Sie benötigen einen nicht X-Auth-Token Header entweder: das HTTP-Authentifizierung Bearer Schema für diesen genauen Anwendungsfall erstellt wurde: im Grunde jede Menge an Informationen, die den Bearer Schema Namen Trails ist ‚Träger‘ Informationen, die validiert werden sollen. Sie setzen einfach den Authorization Header:

Authorization: Bearer <JWT value here> 

Aber, was gesagt wird, wenn Ihr REST-Client ‚nicht vertrauenswürdigen‘ (zB JavaScript-fähigen Browser) ist, würde ich nicht einmal das tun: einen beliebigen Wert in der HTTP-Antwort das über JavaScript zugänglich ist - im Prinzip jeder Header-Wert oder Response-Body-Wert - könnte über MITS XSS-Attacken abgefangen und abgefangen werden.

Es ist besser, den JWT-Wert in einem sicheren Nur-HTTP-Cookie zu speichern (Cookie-Konfiguration: setSecure (true), setHttpOnly (true)). Dies garantiert, dass der Browser:

  1. immer nur das Cookie über eine TLS-Verbindung übertragen und
  2. nie den Cookie-Wert zu JavaScript-Code zur Verfügung stellen.

Dieser Ansatz ist fast alles, was Sie für Best Practices Sicherheit tun müssen. Als letztes müssen Sie sicherstellen, dass Sie bei jeder HTTP-Anforderung CSRF-Schutz haben, um sicherzustellen, dass externe Domänen, die Anforderungen an Ihre Site initiieren, nicht funktionieren können.

Der einfachste Weg, dies zu tun, ist eine sichere nur (aber nicht http nur) Cookie mit einem zufälligen Wert, z. eine UUID

Stellen Sie dann bei jeder Anfrage in Ihrem Server sicher, dass Ihr eigener JavaScript-Code den Cookie-Wert liest und in einer benutzerdefinierten Kopfzeile, z. X-CSRF-Token und überprüfen Sie diesen Wert bei jeder Anfrage auf dem Server. Externe Domänenclients können keine benutzerdefinierten Header für Anforderungen an Ihre Domäne festlegen, es sei denn, der externe Client erhält die Autorisierung über eine HTTP-Optionsanforderung, so dass jeder Versuch eines CSRF-Angriffs (z. B. in einem IFrame) fehlschlägt.

Dies ist die beste Sicherheitsleistung für nicht vertrauenswürdige JavaScript-Clients im Internet, die wir kennen. Stormpath schrieb einen Artikel auf these techniques auch wenn Sie neugierig sind.

Schließlich ist die Stormpath Java Servlet Pluginbereits tut alles für Dich (und viel mehr coole Sachen, einschließlich zusätzlichen automatisierten Sicherheitskontrollen), so dass Sie immer noch nicht schreiben müssen - oder noch schlimmer - sie selbst halten. Sehen Sie sich das HTTP Request Authentication section und das Form/Ajax-Beispiel an, um zu sehen, wie Sie es verwenden können. HTH!

+1

Schöne Antwort Les und danke verwenden. Ich erinnere mich, dass ich den Login-Controller später in der App-Entwicklung hinzugefügt habe, als ich die JWT-Token-Authentifizierung in der App gelernt und implementiert habe. In der Tat konnte ich nicht herausfinden, wie man das Token aus dem Basic Auth Spring Security Filter erstellt. Wenn ich Ihre Lösung lese, sehe ich, dass ich es so machen kann und sollte, und entferne den Login-Controller ganz, da es unnötig wird ... – Stephane

+0

Hallo Les, ich wollte den X-Auth-Token-Header durch die Standardautorisierung ersetzen Header mit dem Bearer-Präfix. Das war, als ich auf eine Antwort stolperte, die besagt, dass ich keinen Standard-Header verwenden und stattdessen einen benutzerdefinierten verwenden sollte. Sein Punkt ist, dass dieser Standardheader der Standardauthentifizierung überlassen werden sollte. Siehe http://stackoverflow.com/questions/12086041/basic-authentication-with-a-guid-token-for-rest-api-instead-of-username-password Puzzled ... – Stephane

+0

@StephaneEybert Ich habe eine Antwort hinzugefügt dieser Thread. Der Header 'Authorization' unterstützt viele _schemes_. Sie können jedes beliebige Schema verwenden. 'Basic' repräsentiert einen Algorithmus. 'Bearer' ist nur was auch immer Text folgt (kein Algorithmus). Andere Schemata (wie "Digest") verwenden einen anderen Algorithmus. Du könntest sogar dein eigenes Schema erfinden. Der Punkt ist der Header ist der gleiche, aber Schema Namen und ihre nachfolgenden Textwerte spiegeln das genaue Verhalten wider. Ich erweitere diese [hier] (http://stackoverflow.com/a/14046557/407170) –