Was ist der beste Ansatz zum Generieren eines neuen API-Schlüssels?

90

Mit vielen verschiedenen Diensten, Google APIs, Twitter API, Facebook API usw. usw.

Jeder Dienst verfügt über einen API-Schlüssel wie:

AIzaSyClzfrOzB818x55FASHvX4JuGQciR9lv7q

Alle Schlüssel variieren in der Länge und den darin enthaltenen Zeichen. Ich frage mich, wie man am besten einen API-Schlüssel generiert.

Ich frage nicht nach einer bestimmten Sprache, sondern nur nach dem allgemeinen Ansatz zum Erstellen von Schlüsseln, falls es sich um eine Verschlüsselung von Details der Benutzer-App oder um einen Hash oder einen Hash einer zufälligen Zeichenfolge usw. handelt. Sollten wir uns über den Hash-Algorithmus Gedanken machen? (MSD, SHA1, bcrypt) usw.?

Bearbeiten: Ich habe mit einigen Freunden (E-Mail / Twitter) gesprochen und sie haben empfohlen, nur eine GUID mit den Strichen zu verwenden.

Das scheint mir allerdings ein wenig hackig zu sein, in der Hoffnung, weitere Ideen zu bekommen.

Phill
quelle
Ich habe hier ausführlicher geantwortet. Schlüssel generieren und als hmac auth verwenden
Anshu Kumar

Antworten:

58

Verwenden Sie einen Zufallszahlengenerator für die Kryptografie. Dann codiert Base-64 die Nummer.

Dies ist ein C # -Beispiel:

var key = new byte[32];
using (var generator = RandomNumberGenerator.Create())
    generator.GetBytes(key);
string apiKey = Convert.ToBase64String(key);
Edward Brey
quelle
2
Dies ist nicht sehr sicher. Ein Angreifer, der Zugriff auf Ihre Datenbank erhält, kann den Schlüssel erhalten. Es wäre besser, den Schlüssel als Hash von etwas zu generieren, das für den Benutzer einzigartig ist (wie ein Salt), kombiniert mit einem Servergeheimnis.
James Wierzba
13
Das Speichern eines zufällig generierten API-Schlüssels weist dieselben Sicherheitsmerkmale auf wie das Speichern eines Hash-Kennworts. In den meisten Fällen ist es in Ordnung. Wie Sie vorschlagen, ist es möglich, die zufällig generierte Zahl als Salz zu betrachten und sie mit einem Servergeheimnis zu versehen. Auf diese Weise entsteht jedoch bei jeder Validierung der Hash-Overhead. Es gibt auch keine Möglichkeit, das Servergeheimnis ungültig zu machen, ohne alle API-Schlüssel ungültig zu machen.
Edward Brey
Gute Lösung, aber Sie benötigen wahrscheinlich das Schlüsselwort var vor apiKey :) var apiKey = Convert.ToBase64String (Schlüssel);
Dawid Ohia
@ JohnM2 Richtig. Ich hatte es offen gelassen, da apiKeyes anderswo deklariert werden konnte. Ich habe den Typ der Klarheit halber hinzugefügt.
Edward Brey
4
@JamesWierzba Wenn sich der Angegriffene bereits in Ihrer Datenbank befindet, ist der wahrscheinlich ungesicherte Zugriff auf Ihre API wahrscheinlich das geringste
Jon Story
30

API-Schlüssel müssen die folgenden Eigenschaften haben:

  • Identifizieren Sie einen autorisierten API-Benutzer eindeutig - den "Schlüssel" -Teil von "API-Schlüssel".
  • Authentifizieren Sie diesen Benutzer - kann nicht erraten / gefälscht werden
  • kann widerrufen werden, wenn sich ein Benutzer schlecht verhält - normalerweise geben sie eine Datenbank ein, in der ein Datensatz gelöscht werden kann.

Normalerweise haben Sie Tausende oder Millionen von API-Schlüsseln, nicht Milliarden, daher müssen sie nicht:

  • Speichern Sie zuverlässig Informationen über den API-Benutzer, da diese in Ihrer Datenbank gespeichert werden können.

Eine Möglichkeit, einen API-Schlüssel zu generieren, besteht darin, zwei Informationen zu verwenden:

  1. eine Seriennummer, um die Eindeutigkeit zu gewährleisten
  2. genug zufällige Bits, um den Schlüssel aufzufüllen

und unterschreiben Sie sie mit einem privaten Geheimnis.

Der Zähler garantiert, dass sie den Benutzer eindeutig identifizieren, und die Signatur verhindert Fälschungen. Für die Sperrbarkeit muss überprüft werden, ob der Schlüssel in der Datenbank noch gültig ist, bevor Maßnahmen ergriffen werden, für die eine API-Schlüsselautorisierung erforderlich ist.

Ein guter GUID-Generator ist eine ziemlich gute Annäherung an einen inkrementierten Zähler, wenn Sie Schlüssel aus mehreren Rechenzentren generieren müssen oder auf andere Weise keine gut verteilte Möglichkeit haben, Seriennummern zuzuweisen.


oder ein Hash einer zufälligen Zeichenfolge

Das Hashing verhindert keine Fälschung. Durch das Signieren wird garantiert, dass der Schlüssel von Ihnen stammt.

Mike Samuel
quelle
3
Ist der Signaturschritt Ihres Algorithmus erforderlich, wenn der von einem Client präsentierte API-Schlüssel mit einer Datenbank bereits registrierter API-Schlüssel auf dem Server verglichen wird, der die API bereitstellt? Es scheint, als wäre das Signieren hier redundant, wenn der Server die Schlüssel bereitstellt.
Sappenin
3
@sappenin, ja. Wenn Sie einen nicht erratenen Schlüssel auf dem Server speichern, müssen Sie Fälschungen nicht verhindern. Häufig werden API-Anforderungen von einer beliebigen Farm von Computern verarbeitet - der Server ist einer von vielen Servern. Die Signaturprüfung kann auf jeder Maschine ohne einen Roundtrip zu einer Datenbank durchgeführt werden, wodurch in einigen Fällen Rennbedingungen vermieden werden können.
Mike Samuel
1
@MikeSamuel Wenn der API-Schlüssel signiert ist und Sie keinen Roundtrip zur Datenbank durchführen, was passiert dann, wenn der Schlüssel widerrufen wird, aber dennoch für den Zugriff auf die API verwendet wird?
Abhyudit Jain
@AbhyuditJain, In jedem verteilten System benötigen Sie eine konsistente Nachrichtenreihenfolge (Widerrufe erfolgen - vor der späteren Verwendung widerrufener Anmeldeinformationen) oder andere Methoden, um Mehrdeutigkeiten zu binden. Einige Systeme führen nicht bei jeder Anforderung einen Roundtrip durch. Wenn ein Knoten die Tatsache zwischenspeichert, dass sich ein Schlüssel 10 Minuten lang in der Datenbank befand, sind es nur 10 Minuten. Fenster, in dem ein Angreifer einen widerrufenen Berechtigungsnachweis missbrauchen kann. Mögliche Verwirrung kann jedoch dazu führen: Der Benutzer widerruft einen Berechtigungsnachweis, testet dann, dass er widerrufen wurde, und ist überrascht, weil nicht klebrige Sitzungen dazu führen, dass die beiden Anforderungen an unterschiedliche Knoten gesendet werden.
Mike Samuel
5

Ich verwende UUIDs, die ohne Bindestriche in Kleinbuchstaben formatiert sind.

Die Generierung ist einfach, da die meisten Sprachen sie eingebaut haben.

API-Schlüssel können kompromittiert werden. In diesem Fall möchte ein Benutzer möglicherweise seinen API-Schlüssel abbrechen und einen neuen generieren. Daher muss Ihre Schlüsselgenerierungsmethode diese Anforderung erfüllen können.

Adam Ralph
quelle
15
Gehen Sie nicht davon aus, dass UUIDs schwer zu erraten sind. Sie sollten nicht als Sicherheitsfunktionen verwendet werden (UUID-Spezifikation RFC4122, Abschnitt 6 ). Ein API-Schlüssel benötigt eine sichere Zufallszahl, aber UUIDs sind nicht sicher nicht zu ermitteln .
Edward Brey
3
@ EdwardBrey was ist mit UUID uuid = UUID.randomUUID();in Java? Wollen Sie damit sagen, dass Zufall nicht gut genug ist?
Micro
8
@MicroR Eine zufällige UUID ist nur dann sicher, wenn der Zufallszahlengenerator, mit dem sie erstellt wurde, kryptografisch sicher ist und 128 Bit ausreichen. Obwohl der UUID-RFC keinen sicheren Zufallszahlengenerator benötigt, kann eine bestimmte Implementierung einen verwenden. Im Fall von randomUUID wird in den API-Dokumenten ausdrücklich angegeben, dass ein "kryptografisch starker Pseudozufallszahlengenerator" verwendet wird. Diese bestimmte Implementierung ist also für einen 128-Bit-API-Schlüssel sicher.
Edward Brey
4

Wenn Sie einen API-Schlüssel mit nur alphanumerischen Zeichen möchten, können Sie eine Variante des base64-Random- Ansatzes verwenden und stattdessen nur eine Base-62-Codierung verwenden. Der Base-62-Encoder basiert darauf .

public static string CreateApiKey()
{
    var bytes = new byte[256 / 8];
    using (var random = RandomNumberGenerator.Create())
        random.GetBytes(bytes);
    return ToBase62String(bytes);
}

static string ToBase62String(byte[] toConvert)
{
    const string alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    BigInteger dividend = new BigInteger(toConvert);
    var builder = new StringBuilder();
    while (dividend != 0) {
        dividend = BigInteger.DivRem(dividend, alphabet.Length, out BigInteger remainder);
        builder.Insert(0, alphabet[Math.Abs(((int)remainder))]);
    }
    return builder.ToString();
}
Edward Brey
quelle
1

Ein API-Schlüssel sollte ein zufälliger Wert sein. Zufällig genug, dass es nicht vorhergesagt werden kann. Es sollte keine Details des Benutzers oder Kontos enthalten, für das es bestimmt ist. Die Verwendung von UUIDs ist eine gute Idee, wenn Sie sicher sind, dass die erstellten IDs zufällig sind.

Frühere Versionen von Windows haben beispielsweise vorhersehbare GUIDs erstellt, aber dies ist eine alte Geschichte.

Dave Van den Eynde
quelle
4
Windows 2000 wechselte mit Zufallszahlen zu GUIDs . Es gibt jedoch keine Garantie dafür, dass die Zufallszahlen nicht vorhergesagt werden können. Wenn ein Angreifer beispielsweise mehrere API-Schlüssel für sich selbst erstellt, kann möglicherweise eine zukünftige Zufallszahl ermittelt werden, die zum Generieren des API-Schlüssels eines anderen Benutzers verwendet wird. Betrachten Sie UUIDs im Allgemeinen nicht als sicher nicht erratbar .
Edward Brey