Использование HMAC-SHA1 для аутентификации API - как надежно хранить пароль клиента? - PullRequest
30 голосов
/ 30 марта 2011

В RESTful API, который использует S3-style аутентификация, клиент API подписывает запрос своим секретным ключом, используя HMAC-SHA1, поэтому секретный ключ никогда не передается по проводам. Затем сервер аутентифицирует клиента, используя секретный ключ этого клиента, чтобы повторить сам процесс подписи и сравнить результат с подписью, переданной клиентом.

Это все хорошо и хорошо, но это означает, что серверу требуется доступ к открытому тексту общего секрета клиента. Это противоречит всем советам против хранения пользовательских паролей в открытом виде в вашей базе данных. Насколько я могу судить, хранение только соленого хэша пароля - не вариант, потому что тогда я не могу проверить подпись клиента.

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

Одним из необязательных решений является шифрование всех пользовательских паролей с использованием некоторого алгоритма симметричного ключа. Однако сервер должен хранить ключ для этого шифрования где-нибудь , легко доступный , например. внутри исходного кода. Это лучше, чем ничего, но не оптимальное решение (как упомянул @Rook в своем ответе, оно нарушает CWE-257).

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

Я что-то упускаю здесь очевидное? Многие уважаемые провайдеры внедрили такую ​​схему аутентификации - они не могут нарушать общие принципы безопасности, не так ли? Если нет, есть ли какие-нибудь лучшие практики, которыми вы можете поделиться?

Ответы [ 3 ]

34 голосов
/ 31 марта 2011

Это обратная сторона аутентификации в стиле «запрос-ответ с симметричным ключом» - вы не помещаете секрет в провод, но вам нужно хранить секрет на обоих концах. (HMAC - это симметричные ключевые системы).

Обратите внимание, что это не пароль - это общий секрет . Здесь есть принципиальное отличие: пароль обычно выбирается пользователем, тогда как общий секрет генерируется случайным образом и предоставляется пользователю (в этом контексте их часто называют «ключами API»).

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

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

11 голосов
/ 30 марта 2011

В идеале, после того, как пользователь войдет в систему, вы дадите ему криптографический одноразовый номер, который используется в качестве секретного ключа HMAC K на весь срок жизни этого сеанса.Это безопасный подход, но он не является RESTful, потому что REST не имеет состояния.Эта идея кода аутентификации сообщения, выдаваемого для каждого логина, технически является формой состояния.

Шифрование паролей и их сохранение в базе данных является нарушением CWE-257 .

2 голосов
/ 05 апреля 2013

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

...