(создан из этого потока, поскольку это действительно вопрос отдельный, а не специфический для NodeJS и т. д.)
Я реализую сервер REST API с аутентификацией, и я успешно реализовал обработку токена JWT, чтобы пользователь мог войти в систему через конечную точку / login с именем пользователя / паролем, после чего токен JWT создается из секрета сервера и возвращается в клиент. Затем токен передается от клиента к серверу в каждом аутентифицированном запросе API, после чего секрет сервера используется для проверки токена.
Тем не менее, я пытаюсь понять передовой опыт того, как именно и в какой степени токен следует проверять, чтобы создать действительно безопасную систему. Что именно должно быть задействовано для «проверки» токена? Достаточно ли того, что подпись может быть проверена с использованием секрета сервера, или я должен также перепроверить токен и / или полезную нагрузку токена с некоторыми данными, хранящимися на сервере?
Система аутентификации на основе токенов будет настолько безопасной, насколько безопасна передача имени пользователя и пароля в каждом запросе при условии, что получить токен так же или сложнее, чем получить пароль пользователя. Однако в примерах, которые я видел, единственная информация, необходимая для создания токена, - это имя пользователя и секрет на стороне сервера. Разве это не означает, что если предположить на минуту, что злоумышленник узнает секрет сервера, он теперь может производить токены от имени любого пользователя, тем самым имея доступ не только к одному данному пользователю, как это было бы, если бы пароль был получается, а по сути для всех учетных записей пользователей?
Это подводит меня к вопросам:
1) Должна ли проверка токена JWT ограничиваться проверкой подписи самого токена, полагаясь только на целостность секрета сервера, или с отдельным механизмом проверки?
В некоторых случаях я видел совместное использование токенов и сеансов сервера, когда после успешного входа в систему через конечную точку / login устанавливается сеанс. Запросы API проверяют токен, а также сравнивают декодированные данные, найденные в токене, с некоторыми данными, хранящимися в сеансе. Однако использование сеансов означает использование файлов cookie и в некотором смысле противоречит цели использования подхода на основе токенов. Это также может вызвать проблемы у некоторых клиентов.
Можно представить себе, что сервер хранит все токены, которые в настоящее время используются в кэше памяти или аналогичном, чтобы гарантировать, что даже если секрет сервера будет скомпрометирован, чтобы злоумышленник мог произвести «действительные» токены, только точные токены, которые были сгенерированы через конечную точку / login будет принято. Это разумно или просто избыточно?
2) Если проверка подписи JWT является единственным средством проверки токенов, а это означает, что целостность секрета сервера является критической точкой, как следует управлять секретами сервера? Считывать из переменной среды и создавать (случайным образом?) Один раз для каждого развернутого стека? Периодически обновляется или обновляется (и если да, то как обрабатывать существующие действительные токены, которые были созданы до вращения, но должны быть проверены после вращения; возможно, этого достаточно, если сервер хранит текущий и предыдущий секреты в любой момент времени) ? Что-то другое?
Может быть, я просто чрезмерно параноик, когда дело касается риска компрометации секрета сервера, что, конечно, является более общей проблемой, которую необходимо решать во всех криптографических ситуациях ...
RSAPrivateKey privateKey
??Ответы:
Я тоже играл с токенами для своего приложения. Хотя я ни в коем случае не эксперт, я могу поделиться некоторыми своими впечатлениями и мыслями по этому поводу.
Суть JWT - это, по сути, целостность. Он предоставляет вашему серверу механизм проверки того, что предоставленный ему токен является подлинным и был предоставлен вашим сервером. Подпись, созданная с помощью вашего секрета, обеспечивает это. Итак, да, если ваш секрет каким-то образом просочился, этот человек может генерировать токены, которые ваш сервер сочтет своими собственными. Система на основе токенов все равно будет более безопасной, чем ваша система имени пользователя / пароля, просто из-за проверки подписи. И в этом случае, если у кого-то все равно есть ваш секрет, у вашей системы есть другие проблемы с безопасностью, с которыми нужно иметь дело, кроме тех, кто делает поддельные токены (и даже тогда, простое изменение секрета гарантирует, что любые токены, созданные с использованием старого секрета, теперь недействительны).
Что касается полезной нагрузки, подпись сообщит вам только, что предоставленный вам токен был точно таким, каким он был, когда ваш сервер отправил его. проверка того, что содержимое полезных данных является допустимым или подходящим для вашего приложения, очевидно, зависит от вас.
По вашим вопросам:
1.) По моему ограниченному опыту, определенно лучше проверять свои токены с помощью второй системы. Простая проверка подписи означает, что токен был создан с вашим секретом. Хранение любых созданных токенов в какой-либо базе данных (redis, memcache / sql / mongo или другом хранилище) - отличный способ убедиться, что вы принимаете только токены, созданные вашим сервером. В этом сценарии, даже если ваш секрет просочился, это не будет иметь большого значения, поскольку любые сгенерированные токены в любом случае не будут действительными. Это подход, который я использую в своей системе - все сгенерированные токены хранятся в БД (redis), и при каждом запросе я проверяю, что токен находится в моей БД, прежде чем я его принимаю. Таким образом, токены могут быть отозваны по любой причине, например, токены, которые каким-то образом были выпущены в дикую природу, выход пользователя из системы, изменение пароля, изменение секрета и т. Д.
2.) Это то, в чем у меня нет большого опыта, и я все еще активно исследую это, поскольку я не профессионал в области безопасности. Если вы найдете какие-либо ресурсы, не стесняйтесь размещать их здесь! В настоящее время я просто использую закрытый ключ, загружаемый с диска, но, очевидно, это далеко не лучшее или самое безопасное решение.
источник
Вот несколько вещей, которые следует учитывать при реализации JWT в вашем приложении:
Поддерживайте относительно короткий срок жизни JWT и управляйте им на сервере. Если вы этого не сделаете, и позже вам потребуется дополнительная информация в ваших JWT, вам придется либо поддерживать 2 версии, либо подождать, пока срок действия ваших старых JWT не истечет, прежде чем вы сможете реализовать свое изменение. Вы можете легко управлять им на сервере, если вы только посмотрите на
iat
поле в jwt и проигнорируете егоexp
.Рассмотрите возможность включения URL-адреса запроса в ваш JWT. Например, если вы хотите, чтобы ваш JWT использовался в конечной точке
/my/test/path
, включите поле, как'url':'/my/test/path'
в вашем JWT, чтобы гарантировать, что оно когда-либо использовалось только на этом пути. Если вы этого не сделаете, вы можете обнаружить, что люди начнут использовать ваши JWT на других конечных точках, даже на тех, для которых они не были созданы. Вы также можете рассмотреть возможность включения вместо этого md5 (url), поскольку наличие большого URL-адреса в JWT в конечном итоге приведет к тому, что JWT станет намного больше, и они могут стать довольно большими.Срок действия JWT должен настраиваться для каждого варианта использования, если JWT реализуются в API. Например, если у вас есть 10 конечных точек для 10 различных вариантов использования JWT, убедитесь, что вы можете заставить каждую конечную точку принимать JWT, срок действия которых истекает в разное время. Это позволяет заблокировать одни конечные точки больше, чем другие, если, например, данные, обслуживаемые одной конечной точкой, очень чувствительны.
Вместо того, чтобы просто истекать JWT через определенное время, рассмотрите возможность реализации JWT, которые поддерживают оба:
Все сбои аутентификации JWT должны генерировать заголовок ответа "error", в котором указывается, почему аутентификация JWT не удалась. например, «просрочено», «не осталось использований», «отозвано» и т. д. Это помогает разработчикам узнать, почему их JWT дает сбой.
Подумайте о том, чтобы игнорировать «заголовок» ваших JWT, поскольку они утекают информацию и предоставляют хакерам некоторую степень контроля. В основном это касается
alg
поля в заголовке - игнорируйте это и просто предполагайте, что заголовок - это то, что вы хотите поддерживать, поскольку это позволяет избежать попыток хакеров использоватьNone
алгоритм, который удаляет проверку безопасности подписи.JWT должен включать идентификатор, подробно описывающий, какое приложение сгенерировало токен. Например, если ваши JWT создаются двумя разными клиентами, mychat и myclassifiedsapp, тогда каждый должен включать имя проекта или что-то подобное в поле «iss» в JWT, например, «iss»: «mychat»
iat
(выдано в) вместоexp
(истечение срока) в ваших JWT. Зачем? Поскольку вiat
основном означает, когда был создан JWT, это позволяет вам настроить на сервере, когда истекает срок действия JWT, в зависимости от даты создания. Если кто-то пройдет черезexp
20 лет в будущем, JWT будет жить вечно! Обратите внимание, что срок действия JWT автоматически истекает, если ихiat
находятся в будущем, но немного места для маневра (например, 10 секунд) на случай, если время клиента немного не синхронизируется со временем сервера./mysite/userInfo?jwt=XXX
и этот URL кэшируется. Они выходят из системы, и через пару минут в ваше приложение входит обычный пользователь. Они получат кэшированный контент - с информацией о суперпользователе! Обычно это происходит реже на клиенте, а больше на сервере, особенно в случаях, когда вы используете CDN, например Akamai, и позволяете некоторым файлам жить дольше. Это можно исправить, включив соответствующую информацию о пользователе в URL-адрес и проверив ее на сервере, даже для кешированных запросов, например/mysite/userInfo?id=52&jwt=XXX
источник
created_by
, уже существует в JWT и называетсяiss
(эмитент).Я не думаю, что я эксперт, но хотел бы поделиться некоторыми мыслями о Jwt.
1: Как сказал Акшай, лучше иметь вторую систему для проверки вашего токена.
a .: То, как я с этим справляюсь: я сохраняю сгенерированный хэш в хранилище сеанса с указанием срока действия. Чтобы проверить токен, он должен быть выпущен сервером.
б .: Есть хотя бы одна вещь, которую необходимо проверить используемым методом подписи. например:
Некоторые библиотеки, проверяющие JWT, примут это без проверки хеша. Это означает, что, не зная, что ваша соль используется для подписи токена, хакер может предоставить себе некоторые права. Всегда следите за тем, чтобы этого не произошло. https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/
c .: Использование cookie с идентификатором сеанса бесполезно для проверки вашего токена. Если кто-то хочет перехватить сеанс пользователя лямбда-выражения, ему просто нужно будет использовать сниффер (например, wirehark). Этот хакер будет иметь обе информации одновременно.
То, как я с этим справляюсь, связано с пунктом 1.а. : У меня есть секрет, смешанный со случайной величиной. Секрет уникален для каждого токена.
Если вы хотите обеспечить максимальную безопасность, не следует слепо следовать лучшим практикам. Лучший способ - понять, что вы делаете (я думаю, это нормально, когда я увижу ваш вопрос), а затем оценить необходимую безопасность. И если Моссад захочет получить доступ к вашим конфиденциальным данным, они всегда найдут способ. (Мне нравится это сообщение в блоге: https://www.schneier.com/blog/archives/2015/08/mickens_on_secu.html )
источник
Здесь много хороших ответов. Я объединю некоторые ответы, которые считаю наиболее актуальными, и добавлю еще несколько предложений.
1) Должна ли проверка токена JWT ограничиваться проверкой подписи самого токена, полагаясь только на целостность секрета сервера, или с отдельным механизмом проверки?
Нет, по причинам, не связанным с раскрытием секрета токена. Каждый раз, когда пользователь входит в систему с использованием имени пользователя и пароля, сервер авторизации должен сохранять либо сгенерированный токен, либо метаданные о сгенерированном токене. Думайте об этих метаданных как об авторизационной записи. У данной пары пользователя и приложения должен быть только один действующий токен или авторизация в любой момент времени. Полезные метаданные - это идентификатор пользователя, связанный с токеном доступа, идентификатор приложения и время, когда был выпущен токен доступа (что позволяет отозвать существующие токены доступа и выпустить новый токен доступа). При каждом запросе API проверяйте, содержит ли токен правильные метаданные. Вам необходимо сохранить информацию о том, когда был выпущен каждый токен доступа, чтобы пользователь мог отозвать существующие токены доступа, если их учетные данные были скомпрометированы, и снова войти в систему и начать использовать новый токен доступа. Это обновит базу данных с указанием времени, когда был выпущен токен доступа (время создания авторизации). При каждом запросе API проверяйте, что время выдачи токена доступа превышает время авторизации.
Другие меры безопасности включали не регистрацию JWT и требование безопасного алгоритма подписи, такого как SHA256.
2) Если проверка подписи JWT является единственным средством проверки токенов, а это означает, что целостность секрета сервера является критической точкой, как следует управлять секретами сервера?
Компрометация секретов сервера позволит злоумышленнику выдать токены доступа для любого пользователя, а сохранение данных токенов доступа на шаге 1 не обязательно помешает серверу принять эти токены доступа. Например, предположим, что пользователю был выдан токен доступа, а затем злоумышленник генерирует токен доступа для этого пользователя. Время авторизации токена доступа будет действительным.
Как говорит Акшай Дхалвала, если ваш секрет на стороне сервера скомпрометирован, у вас возникнут более серьезные проблемы, потому что это означает, что злоумышленник скомпрометировал вашу внутреннюю сеть, репозиторий исходного кода или и то, и другое.
Однако система для смягчения повреждения скомпрометированного секрета сервера и предотвращения хранения секретов в исходном коде включает ротацию секрета токена с использованием службы координации, например https://zookeeper.apache.org. Используйте задание cron для генерации секрета приложения примерно каждые несколько часов (независимо от того, на какой срок действуют ваши токены доступа), и отправьте обновленный секрет в Zookeeper. На каждом сервере приложений, которому необходимо знать секрет токена, настройте ZK-клиент, который обновляется при изменении значения ZK-узла. Сохраните первичный и вторичный секреты, и каждый раз, когда секрет токена меняется, устанавливайте новый секрет токена на первичный, а старый секрет токена - на вторичный. Таким образом, существующие действительные токены будут по-прежнему действительны, потому что они будут проверены на соответствие вторичному секрету. К тому времени, когда вторичный секрет будет заменен старым первичным секретом, все токены доступа, выпущенные с вторичным секретом, в любом случае будут просрочены.
источник
IETF разрабатывает RFC в рабочей группе oAuth, см. Https://tools.ietf.org/id/draft-ietf-oauth-jwt-bcp-05.html
источник