Ich entwickle eine REST-API, die eine Authentifizierung erfordert. Da die Authentifizierung selbst über einen externen Webservice über HTTP erfolgt, habe ich argumentiert, dass wir Token ausgeben würden, um zu vermeiden, dass der Authentifizierungsdienst wiederholt aufgerufen wird. Was mich ordentlich zu meiner ersten Frage bringt:
Ist dies wirklich besser, als nur von Clients zu verlangen, dass sie bei jeder Anforderung HTTP Basic Auth verwenden und Aufrufe an den serverseitigen Authentifizierungsdienst zwischenspeichern?
Die Basic Auth-Lösung bietet den Vorteil, dass kein vollständiger Roundtrip zum Server erforderlich ist, bevor mit der Anforderung von Inhalten begonnen werden kann. Tokens können möglicherweise flexibler sein (dh nur Rechte für bestimmte Ressourcen oder Aktionen gewähren), aber dies scheint für den OAuth-Kontext angemessener zu sein als mein einfacherer Anwendungsfall.
Derzeit werden Token wie folgt erworben:
curl -X POST localhost/token --data "api_key=81169d80...
&verifier=2f5ae51a...
×tamp=1234567
&user=foo
&pass=bar"
Die api_key
, timestamp
und verifier
werden von allen Anfragen erforderlich. Der "Verifizierer" wird zurückgegeben von:
sha1(timestamp + api_key + shared_secret)
Meine Absicht ist es, nur Anrufe von bekannten Teilnehmern zuzulassen und zu verhindern, dass Anrufe wörtlich wiederverwendet werden.
Ist das gut genug Underkill? Overkill?
Mit einem Token in der Hand können Kunden Ressourcen erwerben:
curl localhost/posts?api_key=81169d80...
&verifier=81169d80...
&token=9fUyas64...
×tamp=1234567
Für den einfachsten möglichen Anruf scheint dies schrecklich ausführlich zu sein. Wenn man bedenkt, dass der shared_secret
Wille in (mindestens) eine iOS-Anwendung eingebettet wird, von der ich annehmen würde, dass sie extrahiert werden kann, bietet dies überhaupt etwas, das über ein falsches Sicherheitsgefühl hinausgeht?
quelle
Antworten:
Lassen Sie mich alles trennen und jedes Problem isoliert angehen:
Authentifizierung
Für die Authentifizierung hat baseauth den Vorteil, dass es sich um eine ausgereifte Lösung auf Protokollebene handelt. Das bedeutet viel Probleme, die später auftreten könnten, bereits für Sie gelöst sind. Mit BaseAuth wissen Benutzeragenten beispielsweise, dass das Kennwort ein Kennwort ist, sodass sie es nicht zwischenspeichern.
Auth Server laden
Wenn Sie dem Benutzer ein Token ausgeben, anstatt die Authentifizierung auf Ihrem Server zwischenzuspeichern, gehen Sie immer noch genauso vor: Zwischenspeichern von Authentifizierungsinformationen. Der einzige Unterschied besteht darin, dass Sie die Verantwortung für das Caching dem Benutzer übertragen. Dies scheint für den Benutzer unnötige Arbeit ohne Gewinne zu sein. Ich empfehle daher, dies auf Ihrem Server transparent zu handhaben, wie Sie vorgeschlagen haben.
Übertragungssicherheit
Wenn eine SSL-Verbindung verwendet werden kann, ist die Verbindung sicher *. Um eine versehentliche Mehrfachausführung zu verhindern, können Sie mehrere URLs filtern oder Benutzer auffordern, eine zufällige Komponente ("nonce") in die URL aufzunehmen.
Wenn dies nicht möglich ist und die übertragenen Informationen nicht geheim sind, empfehle ich, die Anforderung mit einem Hash zu sichern, wie Sie im Token-Ansatz vorgeschlagen haben. Da der Hash die Sicherheit bietet, können Sie Ihre Benutzer anweisen, den Hash als Baseauth-Passwort anzugeben. Um die Robustheit zu verbessern, empfehle ich, anstelle des Zeitstempels eine zufällige Zeichenfolge als "Nonce" zu verwenden, um Wiederholungsangriffe zu verhindern (zwei legitime Anforderungen können in derselben Sekunde gestellt werden). Anstatt separate Felder "Shared Secret" und "API-Schlüssel" bereitzustellen, können Sie einfach den API-Schlüssel als gemeinsames Geheimnis verwenden und dann ein Salz verwenden, das sich nicht ändert, um Angriffe auf Regenbogentabellen zu verhindern. Das Feld für den Benutzernamen scheint auch ein guter Ort zu sein, um das Nonce zu platzieren, da es Teil der Authentifizierung ist. Jetzt haben Sie einen sauberen Anruf wie folgt:
Es ist wahr, dass dies ein bisschen mühsam ist. Dies liegt daran, dass Sie keine Lösung auf Protokollebene (wie SSL) verwenden. Daher ist es möglicherweise eine gute Idee, Benutzern eine Art SDK bereitzustellen, damit sie es zumindest nicht selbst durchgehen müssen. Wenn Sie es auf diese Weise tun müssen, finde ich die Sicherheitsstufe angemessen (genau richtig töten).
Sichere geheime Aufbewahrung
Es kommt darauf an, wen Sie vereiteln wollen. Wenn Sie verhindern, dass Personen mit Zugriff auf das Telefon des Benutzers Ihren REST-Service im Namen des Benutzers verwenden, ist es eine gute Idee, eine Art Schlüsselring-API auf dem Zielbetriebssystem zu finden und das SDK (oder den Implementierer) das zu speichern Schlüssel dort. Wenn dies nicht möglich ist, können Sie es zumindest etwas schwieriger machen, das Geheimnis zu erlangen, indem Sie es verschlüsseln und die verschlüsselten Daten und den Verschlüsselungsschlüssel an verschiedenen Orten speichern.
Wenn Sie versuchen, andere Softwareanbieter davon abzuhalten, Ihren API-Schlüssel zu erhalten, um die Entwicklung alternativer Clients zu verhindern, wird fast nur der Ansatz zum separaten Verschlüsseln und Speichern verwendet funktioniert . Dies ist Whitebox-Krypto, und bis heute hat niemand eine wirklich sichere Lösung für Probleme dieser Klasse gefunden. Das Mindeste, was Sie tun können, ist, für jeden Benutzer einen einzelnen Schlüssel auszugeben, damit Sie missbrauchte Schlüssel verbieten können.
(*) BEARBEITEN: SSL-Verbindungen sollten nicht mehr als sicher angesehen werden, ohne dass zusätzliche Schritte zur Überprüfung erforderlich sind.
quelle
Eine reine RESTful-API sollte die zugrunde liegenden Protokollstandardfunktionen verwenden:
Für HTTP sollte die RESTful-API den vorhandenen HTTP-Standardheadern entsprechen. Das Hinzufügen eines neuen HTTP-Headers verstößt gegen die REST-Prinzipien. Erfinden Sie das Rad nicht neu, sondern verwenden Sie alle Standardfunktionen in HTTP / 1.1-Standards - einschließlich Statusantwortcodes, Headern usw. RESTFul-Webdienste sollten die HTTP-Standards nutzen und sich darauf verlassen.
RESTful Services müssen zustandslos sein. Alle Tricks, wie die tokenbasierte Authentifizierung, die versucht, sich den Status früherer REST-Anforderungen auf dem Server zu merken, verstoßen gegen die REST-Prinzipien. Auch dies ist ein MUSS; Wenn Ihr Webserver kontextbezogene Informationen zu Anforderungen und Antworten auf dem Server speichert, um eine Sitzung auf dem Server einzurichten, ist Ihr Webdienst NICHT zustandslos. Und wenn es NICHT staatenlos ist, ist es NICHT RESTFul.
Fazit: Für Authentifizierungs- / Autorisierungszwecke sollten Sie den HTTP-Standardautorisierungsheader verwenden. Das heißt, Sie sollten den HTTP-Autorisierungs- / Authentifizierungsheader in jeder nachfolgenden Anforderung hinzufügen, die authentifiziert werden muss. Die REST-API sollte den Standards des HTTP-Authentifizierungsschemas entsprechen. Die Einzelheiten zur Formatierung dieses Headers sind in den RFC 2616 HTTP 1.1-Standards - Abschnitt 14.8 Autorisierung von RFC 2616 und in der RFC 2617 HTTP-Authentifizierung: Standard- und Digest-Zugriffsauthentifizierung definiert .
Ich habe einen RESTful-Service für die Cisco Prime Performance Manager-Anwendung entwickelt. Google - Suche für das REST - API Dokument , dass ich für diese Anwendung , um weitere Informationen über RESTful API Compliance schrieb hier . In dieser Implementierung habe ich mich für das HTTP-Autorisierungsschema "Basic" entschieden. - Überprüfen Sie Version 1.5 oder höher dieses REST-API-Dokuments und suchen Sie im Dokument nach Autorisierung.
quelle
Im Web basiert ein Stateful-Protokoll darauf, dass bei jeder Anforderung ein temporäres Token zwischen einem Browser und einem Server (über Cookie-Header oder URI-Umschreibung) ausgetauscht wird. Dieses Token wird normalerweise auf der Serverseite erstellt. Es handelt sich um undurchsichtige Daten mit einer bestimmten Lebensdauer und dem alleinigen Zweck, einen bestimmten Webbenutzeragenten zu identifizieren. Das heißt, das Token ist temporär und wird zu einem STAAT, den der Webserver während der Dauer dieser Konversation im Auftrag eines Client-Benutzeragenten verwalten muss. Daher ist die Kommunikation unter Verwendung eines Tokens auf diese Weise STATEFUL. Und wenn die Konversation zwischen Client und Server STATEFUL ist, ist sie nicht RESTful.
Der Benutzername / das Kennwort (gesendet im Authorization-Header) wird normalerweise in der Datenbank gespeichert, um einen Benutzer zu identifizieren. Manchmal kann der Benutzer eine andere Anwendung bedeuten. Der Benutzername / das Passwort lautet jedoch NIEMALS einen bestimmten Web - Client - User - Agenten identifizieren soll. Die Konversation zwischen einem Webagenten und einem Server basierend auf der Verwendung des Benutzernamens / Kennworts im Autorisierungsheader (nach der HTTP-Basisautorisierung) ist STATELESS, da das Webserver-Frontend keine STATE- Informationen erstellt oder verwaltet für einen bestimmten Web-Client-Benutzeragenten. Und basierend auf meinem Verständnis von REST besagt das Protokoll eindeutig, dass die Konversation zwischen Clients und Server STATELESS sein sollte. Wenn wir also einen echten RESTful-Service haben möchten, sollten wir im Authorization-Header für jeden einzelnen Aufruf den Benutzernamen / das Passwort (siehe RFC, der in meinem vorherigen Beitrag erwähnt wurde) verwenden, NICHT eine Art Sension-Token (z. B. Sitzungstoken, die auf Webservern erstellt wurden , OAuth-Token, die auf Autorisierungsservern erstellt wurden usw.).
Ich verstehe, dass mehrere angerufene REST-Anbieter Token wie OAuth1- oder OAuth2-Akzeptiertoken verwenden, die in HTTP-Headern als "Authorization: Bearer" übergeben werden. Es scheint mir jedoch, dass die Verwendung dieser Token für RESTful-Dienste die wahre STATELESS-Bedeutung verletzen würde, die REST umfasst. weil diese Token nur vorübergehend sind Daten sind, die auf der Serverseite erstellt / verwaltet werden, um einen bestimmten Webclient-Benutzeragenten für die gültige Dauer einer Webclient / Server-Konversation zu identifizieren. Daher sollte jeder Dienst, der diese OAuth1 / 2-Token verwendet, nicht als REST bezeichnet werden, wenn wir uns an die TRUE-Bedeutung eines STATELESS-Protokolls halten möchten.
Rubens
quelle