Qual é a melhor abordagem para gerar uma nova chave de API?

92

Assim, com muitos serviços diferentes agora, APIs do Google, API do Twitter, API do Facebook, etc. etc.

Cada serviço possui uma chave de API, como:

AIzaSyClzfrOzB818x55FASHvX4JuGQciR9lv7q

Todas as chaves variam em comprimento e os caracteres que contêm. Estou me perguntando qual é a melhor abordagem para gerar uma chave de API?

Não estou pedindo uma linguagem específica, apenas a abordagem geral para a criação de chaves, caso sejam uma criptografia de detalhes do aplicativo do usuário, ou um hash, ou um hash de uma string aleatória, etc. Devemos nos preocupar com o algoritmo de hash (MSD, SHA1, bcrypt) etc?

Edit: Falei com alguns amigos (e-mail / twitter) e eles recomendaram apenas o uso de um GUID sem os traços.

No entanto, isso parece um pouco estranho para mim, na esperança de obter mais algumas idéias.

Phill
fonte
Eu respondi com mais detalhes aqui .. gerando chaves e usando-as como hmac auth
Anshu Kumar

Respostas:

59

Use um gerador de números aleatórios projetado para criptografia. Então, a base 64 codifica o número.

Este é um exemplo C #:

var key = new byte[32];
using (var generator = RandomNumberGenerator.Create())
    generator.GetBytes(key);
string apiKey = Convert.ToBase64String(key);
Edward Brey
fonte
2
Isso não é muito seguro; um invasor que obtenha acesso ao seu banco de dados pode obter a chave. Seria melhor gerar a chave como um hash de algo exclusivo do usuário (como um sal), combinado com um segredo do servidor.
James Wierzba
14
Armazenar uma chave de API gerada aleatoriamente tem as mesmas características de segurança que armazenar uma senha com hash. Na maioria dos casos, tudo bem. Como você sugere, é possível considerar o número gerado aleatoriamente como um sal e fazer o hash com um segredo do servidor; entretanto, ao fazer isso, você incorre na sobrecarga de hash em cada validação. Também não há como invalidar o segredo do servidor sem invalidar todas as chaves de API.
Edward Brey
Boa solução, mas você provavelmente precisa da palavra-chave var antes de apiKey :) var apiKey = Convert.ToBase64String (key);
Dawid Ohia
@ JohnM2 Certo. Eu estava deixando em aberto, já que apiKeypoderia ser declarado em outro lugar. Eu adicionei o tipo para maior clareza.
Edward Brey
4
@JamesWierzba se o atacado já estiver em seu banco de dados, então ele ter acesso não seguro à sua API é provavelmente a menor de suas preocupações ...
Jon Story
30

As chaves de API precisam ter as propriedades que:

  • identificar exclusivamente um usuário de API autorizado - a parte "chave" da "chave de API"
  • autenticar esse usuário - não pode ser adivinhado / forjado
  • pode ser revogada se um usuário se comportar mal - normalmente, eles inserem em um banco de dados que pode ter um registro excluído.

Normalmente, você terá milhares ou milhões de chaves de API, não bilhões, portanto, elas não precisam:

  • Armazene informações de forma confiável sobre o usuário da API, pois isso pode ser armazenado em seu banco de dados.

Assim, uma maneira de gerar uma chave de API é pegar duas informações:

  1. um número de série para garantir exclusividade
  2. bits aleatórios suficientes para preencher a chave

e assine-os usando um segredo privado.

O contador garante que eles identifiquem o usuário de forma exclusiva e a assinatura evita falsificações. A revogabilidade exige a verificação de que a chave ainda é válida no banco de dados antes de fazer qualquer coisa que exija a autorização da chave API.

Um bom gerador de GUID é uma boa aproximação de um contador incrementado se você precisar gerar chaves de vários datacenters ou não tiver de outra forma uma boa maneira distribuída de atribuir números de série.


ou um hash de uma string aleatória

O hash não impede a falsificação. A assinatura é o que garante que a chave veio de você.

Mike Samuel
fonte
3
A etapa de assinatura do seu algoritmo é necessária se a chave de API apresentada por um cliente for verificada em um banco de dados de chaves de API já registradas no servidor que fornece a API? Parece que a assinatura seria redundante aqui se o servidor for quem fornece as chaves.
Sappenin
3
@sappenin, sim. Se você armazenar uma chave impossível de adivinhar no servidor, não será necessário evitar a falsificação. Freqüentemente, as solicitações de API são tratadas por qualquer um de um conjunto de máquinas - o servidor é um de muitos servidores. A verificação da assinatura pode ser feita em qualquer máquina sem uma viagem de ida e volta para um banco de dados, o que pode evitar condições de corrida em alguns casos.
Mike Samuel
1
@MikeSamuel se a chave API for assinada e você não fizer uma viagem de ida e volta ao banco de dados, o que acontecerá quando a chave for revogada, mas ainda for usada para acessar a API?
Abhyudit Jain
@AbhyuditJain, em qualquer sistema distribuído, você precisa de uma ordem de mensagem consistente (revogações acontecem antes do uso subsequente de credenciais revogadas) ou outras maneiras de limitar a ambigüidade. Alguns sistemas não funcionam em todas as solicitações - se um nó armazena em cache o fato de que uma chave estava no banco de dados por 10 minutos, há apenas 10 minutos. janela na qual um invasor pode abusar de uma credencial revogada. No entanto, pode ocorrer uma possível confusão: o usuário revoga uma credencial, a seguir testa se ela foi revogada e fica surpreso porque as sessões não aderentes fazem com que as duas solicitações vão para nós diferentes.
Mike Samuel
5

Eu uso UUIDs, formatados em letras minúsculas sem travessões.

A geração é fácil, pois a maioria das linguagens já vem incorporada.

As chaves de API podem ser comprometidas e, nesse caso, um usuário pode querer cancelar sua chave de API e gerar uma nova, portanto, seu método de geração de chave deve ser capaz de atender a esse requisito.

Adam Ralph
fonte
15
Não presuma que UUIDs são difíceis de adivinhar; eles não devem ser usados ​​como recursos de segurança (UUID spec RFC4122 seção 6 ). Uma chave de API precisa de um número aleatório seguro, mas os UUIDs não são impossíveis de adivinhar com segurança .
Edward Brey
3
@EdwardBrey e UUID uuid = UUID.randomUUID();em Java? Você está dizendo que aleatório não é bom o suficiente?
Micro de
8
@MicroR Um UUID aleatório é seguro apenas se o gerador de número aleatório usado para torná-lo criptograficamente seguro e 128 bits forem suficientes. Embora o UUID RFC não exija um gerador de números aleatórios seguro, uma determinada implementação é livre para usar um. No caso de randomUUID , os documentos da API afirmam especificamente que ele usa um "gerador de números pseudoaleatórios criptograficamente forte". Portanto, essa implementação específica é segura para uma chave de API de 128 bits.
Edward Brey
4

Se você deseja uma chave de API apenas com caracteres alfanuméricos, pode usar uma variante da abordagem base64-aleatória , usando apenas uma codificação base-62. O codificador de base 62 é baseado nisso .

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
fonte
1

Uma chave de API deve ser algum valor aleatório. Aleatório o suficiente para que não possa ser previsto. Ele não deve conter detalhes do usuário ou da conta a que se destina. Usar UUIDs é uma boa ideia, se você tiver certeza de que os IDs criados são aleatórios.

As versões anteriores do Windows produziam GUIDs previsíveis, por exemplo, mas essa é uma história antiga.

Dave Van den Eynde
fonte
4
O Windows 2000 mudou para GUIDs usando números aleatórios . No entanto, não há garantia de que os números aleatórios não possam ser previstos. Por exemplo, se um invasor criar várias chaves de API para si mesmo, pode ser possível determinar um número aleatório futuro usado para gerar a chave de API de outro usuário. Em geral, não considere UUIDs como seguramente indizíveis .
Edward Brey