Рейтинг:1

Техника генерации ключей API

флаг jp

Я разрабатываю веб-API, которому необходимо предоставить доступ к различным клиентским приложениям с помощью ключа API, отправленного в виде заголовка http. Я знаю, не совсем так, как это должно быть сделано, но я не контролирую эту часть.

Мой текущий дизайн для ключа API: 16 байтов для идентификатора приложения (guid) в базе данных + 16 байтов, сгенерированных случайным образом (keybytes). Из-за политики компании меня попросили не хранить ключи API в базе данных, поэтому я храню хэш sha256 (clientid + keybytes + соль) и соль в базе данных.

Всякий раз, когда приходит запрос, я разбиваю ключ API на (id, keybytes), ищу клиента в базе данных по id, затем вычисляю sha256 (id + keybytes + salt-from-db) и проверяю, соответствует ли он хэшу, хранящемуся в базе данных. . Требования группы корпоративной безопасности заключались в том, чтобы не хранить ключ API в базе данных, а хранить его хэш (точно так же, как пароль пользователя). Я также рассматривал PBKDF2 (я использую .net 5), но он может быть слишком медленным для выполнения этого при каждом входящем запросе (он должен запускаться для каждого запроса, потому что я не могу изменить клиентские приложения для входа через медленный вызов, а затем отправить токен, они должны просто отправлять ключ с каждым запросом).

По сути, это похоже на хранение sha256 (пароль + соль) в базе данных для пользователя, поэтому я действительно не уверен, что это «достаточно хорошо» (учитывая, что пароль представляет собой случайные 16 байтов, а идентификатор пользователя - еще один случайный 16 байтов - приложение guid и БД теоретически не доступный).

В качестве альтернативы для ключей API у меня есть AES-GCM: сгенерировать случайный одноразовый номер (iv) и зашифровать идентификатор приложения (guid) с помощью секретного ключа (хранится только в настройках webapi, а не в db) и использовать байты (nonce , зашифрованный идентификатор, тег) в качестве ключа API. Это означало бы отсутствие поиска в базе данных в случае неверных ключей API. Я, однако, не уверен, насколько безопасно это решение (в конце концов, я шифрую только один 128-битный блок данных — appid guid — с помощью ключа среди всех клиентов).

Какой из них «приемлем» (если это оба, я возьму первый, поскольку он уже реализован) в случае «нарушения безопасности (например, база данных украдена)?

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

Рейтинг:2
флаг in

Всякий раз, когда приходит запрос, я разбиваю ключ API на (id, keybytes), ищу клиента в базе данных по id, затем вычисляю sha256 (id + keybytes + salt-from-db) и проверяю, соответствует ли он хэшу, хранящемуся в базе данных. . Требования группы корпоративной безопасности заключались в том, чтобы не хранить ключ API в базе данных, а хранить его хэш (точно так же, как пароль пользователя). Я также рассматривал PBKDF2 (я использую .net 5), но он может быть слишком медленным для выполнения этого при каждом входящем запросе (он должен запускаться для каждого запроса, потому что я не могу изменить клиентские приложения для входа через медленный вызов, а затем отправить токен, они должны просто отправлять ключ с каждым запросом).

Если ключ остается секретным и состоит из 16 полностью рандомизированных байтов, то в PBKDF2 нет необходимости; безопасный хеш — это уже один из способов, а подобрать 128-битный ключ невозможно. Другие случайные 16 байтов в UID добавляют глазури на торт, поскольку это позволяет избежать проблемы дня рождения.

По сути, это похоже на хранение sha256 (пароль + соль) в базе данных для пользователя, поэтому я действительно не уверен, что это «достаточно хорошо» (учитывая, что пароль представляет собой случайные 16 байтов, а идентификатор пользователя - еще один случайный 16 байтов - app guid и БД теоретически недоступны).

При использовании 128-битного ключа не имеет значения, сколько там другой случайной информации. Возможно, лучше использовать настоящую KBKDF (функция получения ключа на основе ключа) или HMAC, хотя там ключ используется в качестве входного ключевого материала. Вы также должны убедиться, что входные данные находятся в канонической кодировке, но если все поля имеют предопределенные размеры, вы можете просто объединить их.

В качестве альтернативы для ключей API у меня есть AES-GCM: сгенерировать случайный одноразовый номер (iv) и зашифровать идентификатор приложения (guid) с помощью секретного ключа (хранится только в настройках webapi, а не в db) и использовать байты (nonce , зашифрованный идентификатор, тег) в качестве ключа API. Это означало бы отсутствие поиска в базе данных в случае неверных ключей API. Я, однако, не уверен, насколько безопасно это решение (в конце концов, я шифрую только один 128-битный блок данных — appid guid — с помощью ключа среди всех клиентов).

Здесь не нужна конфиденциальность, достаточно проверки ввода. Таким образом, шифрование кажется ненужным усложнением. Однако у меня есть более насущный вопрос: как вы защищаете ключ и как вы защищаете от повторных атак?

Довольно часто вы можете просто сохранить случайный UID в качестве токена и позволить TLS обрабатывать все остальное. Кажется, это то, что делает большинство людей, но я не знаком с вашим вариантом использования. Это также означает, что вы должны относиться ко всему этому совету с недоверием. Я бы порекомендовал обратиться к специалисту по безопасности, чтобы посмотреть на это и начать с определения того, что вам нужно, а также от кого и от чего вам нужно защищаться.

флаг jp
Мой вариант использования — настольное приложение (установленное локально), вызывающее API через https.Как приложение защищено, это не моя проблема. :) Я бы просто использовал случайную последовательность байтов в качестве токена, но я получил дополнительное требование не хранить ее в БД как есть, отсюда и идея рассматривать случайную последовательность байтов как пароль и хешировать ее. Мне нравится, что решение aes-gcm не требует хранения чего-либо, однако мне не нравится дополнительная сложность (плюс, если главный ключ скомпрометирован, все ключи API).

Ответить или комментировать

Большинство людей не понимают, что склонность к познанию нового открывает путь к обучению и улучшает межличностные связи. В исследованиях Элисон, например, хотя люди могли точно вспомнить, сколько вопросов было задано в их разговорах, они не чувствовали интуитивно связи между вопросами и симпатиями. В четырех исследованиях, в которых участники сами участвовали в разговорах или читали стенограммы чужих разговоров, люди, как правило, не осознавали, что задаваемый вопрос повлияет — или повлиял — на уровень дружбы между собеседниками.