Speicherort eines API-Schlüssels: Ein benutzerdefinierter HTTP-Header im Vergleich zum Authorization-Header mit einem benutzerdefinierten Schema

17

Ich entwerfe eine REST-API mit Autorisierung / Authentifizierung über einen API-Schlüssel.

Ich habe versucht, herauszufinden, was der beste Ort dafür ist, und habe herausgefunden, dass viele Leute die Verwendung eines benutzerdefinierten HTTP-Headers vorschlagen, wie zum ProjectName-Api-KeyBeispiel:

ProjectName-Api-Key: abcde

es ist aber auch möglich und ideologisch korrekt, den AuthorizationHeader mit einem benutzerdefinierten Schema zu verwenden, zB:

Authorization: ApiKey abcde

Andererseits stellte ich fest, dass ein benutzerdefiniertes Autorisierungsschema von einigen Clients unerwartet und nicht unterstützt werden kann und ohnehin zu benutzerdefiniertem Code führt. Daher ist es besser, einen benutzerdefinierten Header zu verwenden, da Clients keine Erwartungen daran haben.

Auf welche Weise möchten Sie einen API-Schlüssel senden?

RomanG
quelle
Die Projekte unter meiner Anleitung verwenden Authorization: Bearer <token>Header und es gab nie ein einziges Problem damit. Die Token sind JWTs .
Andy
1
@ DavidPacker Soweit ich weiß, wird BearerSchema ausschließlich mit oAuth2 verwendet. Wenn Sie es getrennt von oAuth anwenden, wird es als missbräuchlich angesehen. Warum ist es richtig, dieses Schema zu verwenden, wenn es kein oAuth gibt? Übrigens hatte ich Probleme mit der Auswahl eines Autorisierungstyps für meine API. Die API wird nur für einen vertrauenswürdigen Dienst verfügbar sein. Daher habe ich den Clientanmeldeinformationsfluss von oAuth2 untersucht und in meinem Fall keinen Vorteil im Vergleich zu ApiKey festgestellt.
RomanG
@DavidPacker Dann habe ich verstanden, dass die ApiKey-Autorisierung als gültige oAuth-Implementierung angesehen werden kann, wenn sie ohne Ablaufzeit ApiKeyumbenannt und als Access Tokendem Client gewährt interpretiert wird. Das ist eine Art philosophischer Aspekt. Ich habe mich entschieden, keine komplexen Definitionen mitzubringen, wenn sich mein Fall in einfachen Worten beschreiben lässt, und habe mich dafür entschieden, ihn einfach "ApiKey" zu nennen. Wenn Ihr Protokoll den oAuth-Standard implementiert, kann ich der Verwendung zustimmen Bearer, aber ich denke, dass dieses Schema nicht angewendet werden kann.
RomanG
2
Sie beschränken sich zu sehr. Es könnte den API-Konsumenten gleichgültig machen, ob Sie OAuth implementiert haben oder nicht. Was sie interessiert, ist die Tokensicherheit, dass die Tokenausgabe funktioniert und dass sie ordnungsgemäß authentifiziert werden können. Sie empfehlen, Bearer direkt in der JWT-Dokumentation zu verwenden . JWT passt perfekt zum Bearer-Schema und ich kann JWTs nicht mehr empfehlen. Sie eignen sich perfekt für REST-Anwendungen, da Sie einen Benutzer auch dann authentifizieren können, wenn Sie nicht auf die Datenbank zugreifen müssen - es sei denn, Sie benötigen eine Token-Sperrfunktion.
Andy
1
(Vorbeifahren) ... beachten Sie bitte, dass API-Schlüssel gemeinsame Geheimnisse sind, die normalerweise von einer konfigurierten vertrauenden Partei und einem Authentifizierer geteilt werden, um Identität oder Autorisierung nicht zu kommunizieren. Anders ausgedrückt, sie sollen nur einen Sicherheits-Handshake auslösen und kein Authentifizierungsergebnis darstellen. Der API-Schlüssel teilt Ihrer Autorität mit, sich gegenüber dem vertrauenswürdigen Authentifikator des Systems zu identifizieren. Die Verwendung des Schlüssels als Token zur Kontrolle des sicheren Ressourcenzugriffs ist eine schlechte Sache
K. Alan Bates

Antworten:

11

Wenn Sie die Autorisierung verwenden, müssen Sie konsistent sein

Einige werden argumentieren, dass das Folgende unnötig ist ( und vor nicht allzu langer Zeit hätte ich dem zugestimmt ), aber heutzutage sollten wir, wenn wir den AuthorizationHeader verwenden, den Typ des Tokens mitteilen , da API-Schlüssel per se nicht selbstbeschreibend sind 1 .

Warum halte ich es für notwendig und warum halte ich es für wichtig? Weil heutzutage die Unterstützung verschiedener Authentifizierungs- / Autorisierungsprotokolle ein Muss ist. Wenn wir den AuthorizationHeader für alle diese Protokolle verwenden möchten, müssen wir unseren Authentifizierungsservice konsistent machen. Die Art und Weise zu kommunizieren, welche Art von Token wir senden und welches Autorisierungsprotokoll angewendet werden soll, sollte ebenfalls im Header stehen.

Authorization: Basic xxxx
Authorization: Digest xxxx
Authorization: Bearer xxxx
Authorization: ApiKey-v1 xxxx
Authorization: ApiKey-v2 xxxx

Früher war mir das egal, aber nachdem ich mit App-Client-Apps gearbeitet hatte, deren Updates nicht garantiert waren (hauptsächlich Handys und Sensoren), fing ich an. Bei der Implementierung von Sicherheit habe ich mich vorsichtiger verhalten, damit ich sie erweitern kann, ohne dass sich Kunden damit herumschlagen und ohne dass der Server zu viel Arbeit leistet.

Bedenken

Die Probleme, mit denen ich bei der Implementierung meiner eigenen Systeme konfrontiert war, ähnelten denen, die ich kommentiert habe.

Andererseits stellte ich fest, dass ein benutzerdefiniertes Autorisierungsschema von einigen Clients unerwartet und nicht unterstützt werden kann und ohnehin zu benutzerdefiniertem Code führt

Sagen Sie Clients , sagen Sie Bibliotheken, Frameworks, Reverse-Proxys .

Vorteile

Ein wichtiger Vorteil ist der Cache. Shared Caches werden den Header nicht zwischenspeichern (und das ist natürlich gut so), es sei denn, Sie sagen etwas anderes.

Also Autorisierung oder benutzerdefinierter Header?

Meiner Erfahrung nach hat die Implementierung meines eigenen AuthorizationSchemas genau so viel Arbeit (oder mehr) gekostet als die Implementierung benutzerdefinierter Autorisierungsheader, mit dem kleinen Unterschied, dass ich mehr Gestaltungsfreiheit und mehr Kontrolle über den Cache habe, wenn ich benutzerdefinierte Header verwendet habe. Der Grund ist ziemlich dumm, die meiste Zeit habe ich Cache-controlauf no-cacheoder gesetzt no-store, was es mir ermöglicht, die Anrufe an den Server deterministischer zu machen (dies ist wichtig, wenn es um das Verfolgen und Testen geht), unabhängig von der Topologie des Netzwerks.


1: Ich finde diese Antwort in Bezug auf API-Schlüssel sehr klar

Laiv
quelle
4
Die Verwendung von X-ist ab 2012 veraltet: stackoverflow.com/a/3561399/923720
Darkhogg
1
ops! Ich wusste es nicht. Bearbeitet und behoben.
Laiv
Vor dieser Frage dachte ich, dass fast jeder den API-Schlüssel in die URL eingibt, aber HTTPS verwendet, um ihn auszublenden. Gut, einige Alternativen zu sehen. Beispielsweise ermöglicht Contentful Autorisierungs- oder Abfrageparameter: contentful.com/developers/docs/references/content-delivery-api/…
user949300
1
@ user949300 ... die Verwendung eines verschlüsselten gemeinsamen Geheimnisses (z. B. eines API-Schlüssels in URI über SSL) ist offensichtlich sicherer als gar nichts, lässt sich jedoch leicht fälschen, wenn es abgefangen wird und keine Granularität über Identitäten bietet. Ich habe api_keys nie für etwas anderes als für die Kommunikation von Maschine zu Maschine verwendet, bei der ich das gemeinsame Geheimnis zwischen vertrauenden Parteien und die in der Whitelist aufgeführten Maschinenidentitäten abgleiche, die befugt sind, mit diesem gemeinsamen Geheimnis zu handeln. Nachdem die Verbindung von Maschine zu Maschine hergestellt wurde, authentifiziert sich der Bediener auf andere Weise.
K. Alan Bates
@K. Alan Bates Die meisten meiner API-Interaktionen waren für relativ "unwichtige" Dinge wie freie Geokodierungsebenen, Wetterberichte und dergleichen bestimmt, bei denen der API-Schlüssel eher zur Beschränkung der Rate als für ernsthafte Benutzergeheimnisse gedacht ist. Also, wie für OP, hängt davon ab, welche Sicherheitsstufe benötigt wird.
user949300