Как лучше всего создать новый ключ API?

Итак, сейчас есть множество различных сервисов, Google API, Twitter API, Facebook API и т. Д. И т. Д.

У каждой службы есть API-ключ, например:

AIzaSyClzfrOzB818x55FASHvX4JuGQciR9lv7q

Все ключи различаются по длине и символам, которые они содержат. Мне интересно, как лучше всего создать ключ API?

Я не прошу конкретный язык, просто общий подход к созданию ключей, должны ли они быть шифрованием деталей пользовательского приложения, или хешем, или хешем случайной строки и т. Д. Стоит ли нам беспокоиться о хеш-алгоритме (MSD, SHA1, bcrypt) и т. Д.?

Изменить: я поговорил с несколькими друзьями (электронная почта / твиттер), и они рекомендовали просто использовать GUID с удаленными дефисами.

Мне это кажется немного взломанным, я надеюсь получить еще несколько идей.


person Phill    schedule 19.01.2013    source источник
comment
Я ответил более подробно здесь .. генерировать ключи и использовать их как hmac auth   -  person Anshu Kumar    schedule 19.04.2020


Ответы (5)


Используйте генератор случайных чисел, предназначенный для криптографии. Затем кодируйте число по системе base-64.

Это пример C #:

var key = new byte[32];
using (var generator = RandomNumberGenerator.Create())
    generator.GetBytes(key);
string apiKey = Convert.ToBase64String(key);
person Edward Brey    schedule 11.09.2013
comment
Это не очень безопасно, злоумышленник, получивший доступ к вашей базе данных, может получить ключ. Было бы лучше сгенерировать ключ как хэш чего-то уникального для пользователя (например, соль) в сочетании с секретом сервера. - person James Wierzba; 24.02.2017
comment
Хранение случайно сгенерированного ключа API имеет те же характеристики безопасности, что и хранение хешированного пароля. В большинстве случаев это нормально. Как вы предлагаете, можно рассматривать случайно сгенерированное число как соль и хешировать его с секретом сервера; однако, поступая так, вы несете накладные расходы на хэш при каждой проверке. Также нет способа сделать недействительным секрет сервера без аннулирования всех ключей API. - person Edward Brey; 24.02.2017
comment
Хорошее решение, но вам, вероятно, нужно ключевое слово var перед apiKey :) var apiKey = Convert.ToBase64String (key); - person Dawid Ohia; 01.03.2018
comment
@ JohnM2 Верно. Я оставил это открытым, поскольку apiKey можно было объявить где-то еще. Я добавил тип для наглядности. - person Edward Brey; 01.03.2018
comment
Надеюсь, это разумный вопрос: рекомендуете ли вы хранить односторонний хэш сгенерированного apiKey в базе данных, как это делается для паролей, вводимых пользователем? Тогда злоумышленник, который читает базу данных, по-прежнему не может легко выдать себя за фактического пользователя AFAIK. - person chrisinmtown; 18.07.2018
comment
@JamesWierzba, если атакованный уже находится в вашей базе данных, то их незащищенный доступ к вашему API, вероятно, меньше всего вас беспокоит ... - person Jon Story; 27.04.2020
comment
@EdwardBrey не совсем такие характеристики. Кто-то, кто читает базу данных с ключом API в ней, теперь имеет действующий ключ API. Тот, кто читает хешированный пароль, не может использовать этот хеш в качестве пароля. - person Rob Grant; 19.05.2020
comment
@RobGrant Вы можете использовать хешированный пароль, написав поддельное приложение, которое притворяется настоящим приложением. В то время как настоящее приложение хеширует пароль пользователя, поддельное приложение просто использует предварительно хешированный пароль. - person Edward Brey; 20.05.2020

Ключи API должны иметь следующие свойства:

  • однозначно идентифицировать авторизованного пользователя API - «ключевую» часть «API-ключа»
  • аутентифицировать этого пользователя - невозможно угадать / подделать
  • могут быть отозваны, если пользователь плохо себя ведет - обычно они вводят ключ в базу данных, из которой можно удалить запись.

Обычно у вас есть тысячи или миллионы ключей API, а не миллиарды, поэтому им не нужно:

  • Надежно храните информацию о пользователе API, потому что она может храниться в вашей базе данных.

Таким образом, один из способов сгенерировать ключ API - это взять две части информации:

  1. серийный номер для гарантии уникальности
  2. достаточно случайных битов, чтобы заполнить ключ

и подписать их, используя личный секрет.

Счетчик гарантирует, что они однозначно идентифицируют пользователя, а подпись предотвращает подделку. Возможность отзыва требует проверки того, что ключ все еще действителен в базе данных, прежде чем делать что-либо, требующее авторизации ключа API.

Хороший генератор GUID - это довольно хорошее приближение к инкрементному счетчику, если вам нужно сгенерировать ключи из нескольких центров обработки данных или нет другого хорошего распределенного способа присвоения серийных номеров.


или хеш случайной строки

Хеширование не предотвращает подделку. Подписание - это гарантия того, что ключ был получен от вас.

person Mike Samuel    schedule 23.06.2014
comment
Требуется ли этап подписания вашего алгоритма, если ключ API, представленный клиентом, проверяется по базе данных уже зарегистрированных ключей API на сервере, предоставляющем API? Похоже, что подпись здесь будет лишней, если ключи предоставляет сервер. - person sappenin; 27.02.2015
comment
@sappenin, да. Если вы храните на сервере нераспознаваемый ключ, то вам не нужно предотвращать подделку. Часто запросы API обрабатываются одной из нескольких машин - сервер является одним из многих серверов. Проверка подписи может выполняться на любом компьютере без обращения к базе данных и обратно, что в некоторых случаях позволяет избежать состояния гонки. - person Mike Samuel; 28.02.2015
comment
@MikeSamuel, если ключ API подписан, и вы не совершаете круговой обход базы данных, что произойдет, если ключ отозван, но все еще используется для доступа к API? - person Abhyudit Jain; 01.02.2017
comment
@AbhyuditJain, в любой распределенной системе вам нужен согласованный порядок сообщений (аннулирование происходит до последующего использования отозванных учетных данных) или другие способы ограничения неоднозначности. Некоторые системы не обрабатывают каждый запрос и обратно - если узел кэширует тот факт, что ключ находился в базе данных в течение 10 минут, остается только 10 минут. окно, в котором злоумышленник может злоупотребить отозванными учетными данными. Однако возможная путаница может возникнуть: пользователь отменяет учетные данные, затем проверяет, что они отозваны, и удивляется, потому что незакрепленные сеансы заставляют два запроса переходить на разные узлы. - person Mike Samuel; 01.02.2017

Если вам нужен ключ API, содержащий только буквенно-цифровые символы, вы можете использовать вариант подхода base64-random, только используя вместо этого используется кодировка base-62. Кодировщик base-62 основан на this.

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();
}
person Edward Brey    schedule 20.06.2018

Я использую UUID в нижнем регистре без тире.

Генерация проста, поскольку она встроена в большинство языков.

Ключи API могут быть скомпрометированы, и в этом случае пользователь может захотеть отменить свой ключ API и сгенерировать новый, поэтому ваш метод генерации ключей должен соответствовать этому требованию.

person Adam Ralph    schedule 20.01.2013
comment
Не думайте, что UUID трудно угадать; они не должны использоваться в качестве средств безопасности (спецификация UUID RFC4122, раздел 6). Ключ API требует безопасного случайного числа, но UUID нельзя надежно определить. - person Edward Brey; 23.06.2014
comment
@EdwardBrey, а как насчет UUID uuid = UUID.randomUUID(); в Java? Вы хотите сказать, что случайного выбора недостаточно? - person Micro; 07.02.2016
comment
@MicroR Случайный UUID является безопасным только в том случае, если генератор случайных чисел, используемый для его создания, является криптографически безопасным и достаточно 128 бит. Хотя UUID RFC не требует безопасного генератора случайных чисел, в данной реализации его можно использовать бесплатно. В случае randomUUID, в документации API конкретно указано, что он использует криптографически стойкий генератор псевдослучайных чисел. Так что эта конкретная реализация безопасна для 128-битного ключа API. - person Edward Brey; 08.02.2016

Ключ API должен быть случайным значением. Достаточно случайный, чтобы его нельзя было предсказать. Он не должен содержать никаких сведений о пользователе или учетной записи, для которых он предназначен. Использование UUID - хорошая идея, если вы уверены, что созданные идентификаторы случайны.

Например, более ранние версии Windows выдавали предсказуемые идентификаторы GUID, но это уже старая история.

person Dave Van den Eynde    schedule 20.01.2013
comment
Windows 2000 перешла на GUID с использованием случайных чисел. Однако нет никакой гарантии, что случайные числа невозможно предсказать. Например, если злоумышленник создает для себя несколько ключей API, можно определить будущее случайное число, которое будет использоваться для генерации ключа API другого пользователя. Как правило, не считают UUID надежно недоступными. - person Edward Brey; 23.06.2014