Вопрос или проблема
Хранение секретного ключа сервера в rawId пользовательского ключа доступа
Я хочу внедрить поддержку паролей для полного замещения паролей, но у меня есть состояние на стороне сервера, которое все еще необходимо зашифровать для конкретного пользователя так, чтобы оно не могло быть расшифровано или воспроизведено на стороне сервера без сеанса пользователя. Внешний вид системы таков: когда пользователь входит в систему, мы генерируем симметричный ключ шифрования с его паролем, используем его для расшифровки закрытого ключа и используем этот закрытый ключ для шифрования/расшифровки дальнейших ключей шифрования, специфичных для данных.
Цели этой системы:
- Исключить пароли
- Иметь сильную связь между данными, зашифрованными на сервере (которые никогда не доступны пользователю напрямую), и их паролем
- Обеспечить некоторую нерепудицию для использования ключа, никогда не сохраняя ключи на стороне сервера. По сути, должно быть невозможно расшифровать или воспроизвести любое действие пользователя без его присутствия.
- Обеспечить бесполезность данных, зашифрованных на сервере, без наличия пароля пользователя. (Случай утечки данных)
Угрозы:
- Утечка данных на стороне сервера
- Пользователь, пытающийся заявить, что он не выполнял действие, когда на самом деле выполнял
- Нападающий, получивший доступ к учетным данным пользователя, таким образом, что он мог бы расшифровать асимметричный ключ пользователя и использовать его в сочетании с утечкой данных
- Работающее серверное программное обеспечение не считается угрозой
Идея заключается в использовании rawId, связанного с паролем, для хранения симметричного ключа, который будет функционально аналогичен паролю пользователя в описанном выше потоке (но не будет использоваться для аутентификации, просто используйте подписи WebAuthn для этого). Этот ключ никогда не будет доступен пользователю (вместо этого отображается удобный для пользователя идентификатор) и индексируется доверенной стороной, поэтому он не должен передаваться организации, которая не нуждается в нем. Процесс будет генерировать 256-битный ключ, который будет зашифрован с помощью серверного ключа на случай, если в экосистеме WebAuthn произошло заболевание, которое в результате повлечет случайное раскрытие этого ключа ненадлежащей доверенной стороне (пользователь сам по себе не считается угрозой в модели безопасности). Этот ключ и 64-битный идентификатор сервера будут упакованы в rawId пароля и сохранены с пользователем. Система будет использовать открываемые идентификаторы для входа пользователя и доступа к этому идентификатору.
На стороне сервера процесс аутентификации будет выглядеть так:
- Использовать обнаружение пароля для выполнения сессии аутентификации, что приведет к подписи вызова и rawID.
- Использовать идентификатор контекста из rawID для поиска записи криптоконтекста и расшифровки симметричной части ключа rawID с помощью серверного ключа из начального этапа.
- Использовать серверную секретную информацию для HMAC rawID в идентификатор пользователя для поиска открытого ключа пользователя. Существует параллельное отображение от этого идентификатора к реальному идентификатору пользователя в системе хранения пользователей.
- Завершить аутентификацию в соответствии со стандартом WebAuthn с открытым ключом пользователя.
- Расшифровать закрытый ключ пользователя из базы данных с помощью симметричного ключа, упомянутого выше, и отбросить этот ключ. Поместить асимметричный ключ в зашифрованный и временно ограниченный сеансовый cookie пользователя для его дальнейшего использования. (Сеансы шифруются с использованием ключа, который находится в памяти сервера и который автоматически меняется ежедневно и никогда не сохраняется)
Восстановление пароля будет использовать случайно сгенерированный код, который в конечном итоге будет оборачивать асимметричный ключ так же, как это делает код, относящийся к паролю. Если пользователь потеряет этот код, то ему не повезло.
Это плохая идея? Есть ли что-то, что я упускаю и что ставит под угрозу безопасность этой системы?
Ответ или решение
Ваша концепция по замене паролей на механизмы, основанные на passkey (например, WebAuthn), является интересной и, в целом, обоснованной. Тем не менее, необходимо учитывать несколько важных аспектов и потенциальных уязвимостей для обеспечения желаемого уровня безопасности. Давайте внимательно рассмотрим предложенный вами подход.
Общая структура решения
Вы предложили использовать rawId
, чтобы хранить симметричный ключ, который обеспечит привязку серверных зашифрованных данных к passkey пользователя. Основные цели вашей системы включают:
- Устранение паролей.
- Обеспечение надежной привязки между серверными данными и passkey.
- Отказ от возможности репутации (неопровержимости) действий пользователей через сервер.
- Защита зашифрованных данных в случае утечки серверной информации.
Угрозы и уязвимости
При анализе вашей схемы стоит учитывать следующие угрозы и потенциальные уязвимости:
-
Утечка данных на стороне сервера: Если происходит утечка данных, злоумышленник получил доступ к зашифрованным данным, но без доступа к
rawId
и соответствующему ключу, данные останутся бесполезными. Однако, если злоумышленник сможет реконструироватьrawId
, используя альтернативные методы, это может привести к проблемам. -
Неопровержимость действий пользователя: Ваша реализация HMAC для связывания данных пользователей с их действиями может защитить от некоторых видов атак, но важно проверить, что все ключевые операции действительно записываются в защищенные журналы и что нет возможности для манипуляций с этими записями.
- Проникновение злоумышленника: Предположим, что злоумышленник получил доступ к пользовательским средствам аутентификации и может использовать
rawId
. В этом случае вы обеспечите, чтобыrawId
использовался только в контексте аутентификации, а не для дальнейшего использования или доступа к производимым пользователем операциям.
Рекомендации по улучшению безопасности
-
Шифрование и защита
rawId
: Дополнительно к шифрованию симметричного ключа, давайте применим дополнительный уровень защиты. Возможно, стоит рассмотреть использование ключевого шифрования (KEK), которое обеспечивает дополнительные уровни безопасности при хранении ключей. -
Тайм-ауты и сессии: Рассмотрите внедрение временных меток и ограничение на действия — например, ограничение по времени на использование сессий после аутентификации. Это поможет предотвратить длительное использование учетных данных в случае компрометации.
-
Многофакторная аутентификация (MFA): Даже с использованием passkey, рассмотрите возможность добавления второго фактора аутентификации для повышения уровня защиты, особенно для критически важных операций (например, тех, которые влекут за собой финансовые последствия).
-
Регулярные аудиты безопасности: Настройте постоянный процесс аудита и тестирования безопасности системы для выявления уязвимостей и обеспечения их устранения.
- План восстановления: Разработайте четкий и надежный процесс аварийного восстановления, чтобы пользователи могли безопасно получить доступ к своим данным в случае потери
rawId
или других учетных данных.
Заключение
Ваше предложение об использовании rawId
для обеспечения привязки данных к пользователю через механизм passkey имеет значительный потенциал. Однако важно учитывать предложенные улучшения и рекомендации для минимизации потенциальных рисков. Убедитесь, что ваша система тщательно протестирована и готова к различным сценариям атаки, чтобы обеспечить безопасность пользователей и их данных.