Najlepsze podejście do generowania klucza API

89

Tak więc z wieloma różnymi usługami, API Google, API Twittera, API Facebooka itp.

Każda usługa ma klucz API, taki jak:

AIzaSyClzfrOzB818x55FASHvX4JuGQciR9lv7q

Wszystkie klucze różnią się długością i znakami, które zawierają, zastanawiam się, jakie jest najlepsze podejście do generowania klucza API?

Nie pytam o konkretny język, tylko o ogólne podejście do tworzenia kluczy, czy powinny to być szyfrowanie szczegółów aplikacji użytkownika, hash, czy hash losowego ciągu itp. Czy powinniśmy się martwić o algorytm skrótu (MSD, SHA1, bcrypt) itp.?

Edycja: rozmawiałem z kilkoma przyjaciółmi (e-mail / twitter) i zalecili po prostu użycie identyfikatora GUID z usuniętymi myślnikami.

Wydaje mi się to jednak trochę niezrozumiałe, mając nadzieję na więcej pomysłów.

Phill
źródło
Odpowiedziałem bardziej szczegółowo tutaj .. generowanie kluczy i używanie go jako hmac auth
Anshu Kumar

Odpowiedzi:

58

Użyj generatora liczb losowych przeznaczonego do kryptografii. Następnie base-64 zakoduje liczbę.

To jest przykład w C #:

var key = new byte[32];
using (var generator = RandomNumberGenerator.Create())
    generator.GetBytes(key);
string apiKey = Convert.ToBase64String(key);
Edward Brey
źródło
2
Nie jest to zbyt bezpieczne, osoba atakująca, która uzyska dostęp do bazy danych, może uzyskać klucz. Lepiej byłoby wygenerować klucz jako skrót czegoś unikalnego dla użytkownika (np. Sól), w połączeniu z sekretem serwera.
James Wierzba
13
Przechowywanie losowo wygenerowanego klucza API ma te same cechy bezpieczeństwa, co przechowywanie zaszyfrowanego hasła. W większości przypadków jest w porządku. Jak sugerujesz, losowo wygenerowaną liczbę można traktować jako sól i haszować ją z sekretem serwera; jednakże robiąc to, ponosisz koszty mieszania przy każdej walidacji. Nie ma również sposobu, aby unieważnić sekret serwera bez unieważnienia wszystkich kluczy API.
Edward Brey,
Niezłe rozwiązanie, ale prawdopodobnie potrzebujesz słowa kluczowego var przed apiKey :) var apiKey = Convert.ToBase64String (klucz);
Dawid Ohia
@ JohnM2 Right. Zostawiłem to bezterminowe, ponieważ apiKeymożna było to zadeklarować gdzie indziej. Dla jasności dodałem ten typ.
Edward Brey
4
@JamesWierzba jeśli atakowany jest już w Twojej bazie danych, to niezabezpieczony dostęp do Twojego API jest prawdopodobnie najmniejszym z Twoich zmartwień ...
Jon Story
29

Klucze API muszą mieć te właściwości, które:

  • jednoznacznie identyfikować autoryzowanego użytkownika API - część „klucza” w „kluczu API”
  • uwierzytelnij tego użytkownika - nie można go odgadnąć / sfałszować
  • mogą zostać odwołane, jeśli użytkownik źle się zachowuje - zazwyczaj wpisuje klucz do bazy danych, z której można usunąć rekord.

Zwykle będziesz mieć tysiące lub miliony kluczy API, a nie miliardy, więc nie muszą:

  • Niezawodnie przechowuj informacje o użytkowniku API, ponieważ można je przechowywać w bazie danych.

W związku z tym jednym ze sposobów wygenerowania klucza API jest pobranie dwóch informacji:

  1. numer seryjny gwarantujący niepowtarzalność
  2. wystarczająco dużo losowych bitów, aby wyrzucić klucz

i podpisz je za pomocą prywatnego sekretu.

Licznik gwarantuje, że jednoznacznie identyfikuje użytkownika, a podpisywanie zapobiega fałszerstwom. Odwołanie wymaga sprawdzenia, czy klucz jest nadal ważny w bazie danych, zanim zrobisz cokolwiek, co wymaga autoryzacji klucza API.

Dobry generator GUID jest całkiem dobrym przybliżeniem licznika zwiększanego, jeśli musisz generować klucze z wielu centrów danych lub nie masz innego dobrego rozproszonego sposobu przypisywania numerów seryjnych.


lub skrót losowego ciągu

Haszowanie nie zapobiega fałszowaniu. Podpisanie gwarantuje, że klucz pochodzi od Ciebie.

Mike Samuel
źródło
3
Czy etap podpisywania algorytmu jest konieczny, jeśli klucz API przedstawiony przez klienta jest sprawdzany z bazą danych już zarejestrowanych kluczy API na serwerze udostępniającym API? Wydaje się, że podpisywanie byłoby tutaj zbędne, gdyby serwer dostarczał klucze.
sappenin
3
@sappenin, Yes. Jeśli przechowujesz na serwerze niemożliwy do odgadnięcia klucz, nie musisz zapobiegać fałszowaniu. Często wnioski API są obsługiwane przez jednego z farmy maszyn - serwer jest jednym z wielu serwerów. Sprawdzanie podpisów można przeprowadzić na dowolnej maszynie bez konieczności podróżowania w obie strony do bazy danych, co w niektórych przypadkach pozwala uniknąć warunków wyścigu.
Mike Samuel
1
@MikeSamuel, jeśli klucz API jest podpisany i nie wykonujesz podróży w obie strony do bazy danych, co się dzieje, gdy klucz jest unieważniany, ale nadal jest używany do uzyskiwania dostępu do API?
Abhyudit Jain
@AbhyuditJain, W każdym systemie rozproszonym potrzebna jest spójna kolejność komunikatów (odwołania mają miejsce przed kolejnym użyciem odwołanych danych uwierzytelniających) lub inne sposoby ograniczenia niejednoznaczności. Niektóre systemy nie działają w obie strony przy każdym żądaniu - jeśli węzeł buforuje fakt, że klucz był w bazie danych przez 10 minut, jest to tylko 10 minut. okno, w którym osoba atakująca może nadużyć odwołanych poświadczeń. Może to jednak spowodować zamieszanie: użytkownik unieważnia poświadczenie, a następnie testuje, czy zostało ono unieważnione, i jest zaskoczony, ponieważ sesje nieprzylepne powodują, że dwa żądania są kierowane do różnych węzłów.
Mike Samuel
5

Używam identyfikatorów UUID, zapisanych małymi literami bez myślników.

Generowanie jest łatwe, ponieważ większość języków ma to wbudowane.

Klucze API mogą zostać naruszone, w takim przypadku użytkownik może chcieć anulować swój klucz API i wygenerować nowy, więc Twoja metoda generowania klucza musi być w stanie spełnić to wymaganie.

Adam Ralph
źródło
15
Nie zakładaj, że identyfikatory UUID są trudne do odgadnięcia; nie powinny być używane jako funkcje bezpieczeństwa (specyfikacja UUID RFC4122 sekcja 6 ). Klucz API wymaga bezpiecznej liczby losowej, ale identyfikatorów UUID nie da się bezpiecznie odgadnąć .
Edward Brey
3
@EdwardBrey A co UUID uuid = UUID.randomUUID();z Javą? Czy mówisz, że losowość nie jest wystarczająco dobra?
Micro,
8
@MicroR Losowy identyfikator UUID jest bezpieczny tylko wtedy, gdy generator liczb losowych użyty do jego utworzenia jest bezpieczny kryptograficznie i wystarczy 128 bitów. Chociaż UUID RFC nie wymaga bezpiecznego generatora liczb losowych, dana implementacja może go używać. W przypadku randomUUID , dokumentacja API wyraźnie stwierdza, że ​​używa „silnego kryptograficznie generatora liczb pseudolosowych”. Tak więc ta konkretna implementacja jest bezpieczna dla 128-bitowego klucza API.
Edward Brey,
4

Jeśli potrzebujesz klucza API zawierającego tylko znaki alfanumeryczne, możesz użyć wariantu podejścia losowego base64 , używając zamiast tego tylko kodowania base-62. Podstawa koder-62 opiera się na tym .

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
źródło
1

Klucz API powinien mieć jakąś losową wartość. Na tyle losowe, że nie można tego przewidzieć. Nie powinien zawierać żadnych szczegółów użytkownika ani konta, dla którego jest przeznaczony. Używanie identyfikatorów UUID to dobry pomysł, jeśli masz pewność, że utworzone identyfikatory są losowe.

Na przykład wcześniejsze wersje systemu Windows generowały przewidywalne identyfikatory GUID, ale to już stara historia.

Dave Van den Eynde
źródło
4
Windows 2000 przełączył się na identyfikatory GUID przy użyciu liczb losowych . Jednak nie ma gwarancji, że liczb losowych nie da się przewidzieć. Na przykład, jeśli napastnik utworzy dla siebie kilka kluczy API, może być możliwe określenie przyszłej liczby losowej używanej do generowania klucza API innego użytkownika. Ogólnie rzecz biorąc, nie traktuj identyfikatorów UUID jako całkowicie niemożliwych do odgadnięcia .
Edward Brey