Я использую JWT в приложении веб-API ASP.NET Core. Для JWT мне нужен секрет, который я сейчас храню в appsettings.json
. Это выглядит так:
"Jwt": {
"Secret": "cB7lN2sz3H9wI5pAJ8fgkLzV0Q4yxXMiRSO6rTKP1tE7mdjFZCpvWGuoDbhYaeqJnMVwiX5UFz4t8NYsQBoL3rlc20PGfMkj1HvT9pqRbDdOEJZmKaU6gSyWbVx8CnI7T0xywZ2mLI4pk3A9vgHeD5PoFN8jQK1X6sruYRhO0eWtxM3BVzZ9nLD4yfpA7qlUki2Sc6mHJ5XboGrQCVwIwxa9tgPB2sKjRyuM1ZvF7Ylnzhe4H8qo3k"
},
Потенциальный злоумышленник, получивший доступ к моему серверу, теперь может прочитать этот секрет из моего appsettings.json
. Если злоумышленник теперь владеет этим секретом, он может создать любые токены JWT для моего приложения.
Чтобы решить эту проблему, я бы теперь использовал шаблон Singleton. Для этого я бы сначала сгенерировал статический класс, имеющий метод генерации случайных строк.
Это будет выглядеть так:
using System.Text;
namespace MyApp.Utils
{
public class RandomStringGenerator
{
private static readonly char[] chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();
private static readonly Random random = new Random();
public static string Generate(int length)
{
var stringBuilder = new StringBuilder(length);
for (int i = 0; i < length; i++)
{
var randomIndex = random.Next(chars.Length);
stringBuilder.Append(chars[randomIndex]);
}
return stringBuilder.ToString();
}
}
}
Тогда мне нужен JWTSecretProvider
(синглтон). Это будет выглядеть так:
namespace MyApp.Utils
{
sealed class JWTSecretProvider
{
private static string _secret = null!;
private static JWTSecretProvider _instance;
private static readonly object _lock = new object();
private JWTSecretProvider()
{
_secret = RandomStringGenerator.Generate(200);
}
public static JWTSecretProvider Instance()
{
if (_instance == null)
{
lock (_lock)
{
if (_instance == null)
{
_instance = new JWTSecretProvider();
}
}
}
return _instance;
}
public string GetSecret()
{
return _secret;
}
}
}
Если мне теперь понадобится доступ к секрету JWT, например. при запуске сервера или когда клиент запрашивает токен JWT после аутентификации, я могу получить к нему доступ следующим образом:
JWTSecretProvider.Instance().GetSecret()
Что вы думаете об этом подходе?
Вы можете хранить их в переменных среды. Переменные среды позволяют избежать хранения секретов приложения в коде или локальных файлах конфигурации, а для доступа к переменным среды требуются более высокие разрешения, чем для чтения файлов. Learn.microsoft.com/en-us/aspnet/core/security/….
Однако следует отметить, что переменные среды обычно хранятся в незашифрованном виде. Если компьютер или процесс скомпрометированы, недоверенные стороны могут получить доступ к переменным среды. Возможно, вам придется принять дополнительные меры для предотвращения раскрытия секретов пользователей.
Просто чтобы прояснить несколько моментов, вы сказали:
Если злоумышленник теперь владеет этим токеном, он может создать любые токены JWT для моего приложения.
Это не совсем так. Прежде всего, JWT уже зашифрован, поэтому злоумышленник не сможет выяснить, что находится внутри. Даже если злоумышленник сможет выяснить, где, например, находится раздел claims
, любая попытка изменить его не сработает. Это связано с тем, что JWT содержит в себе контрольную сумму, гарантирующую, что он не был подделан. Таким образом, злоумышленник не сможет получить доступ после взлома JWT, поскольку сервер обнаружит, что новая контрольная сумма не соответствует значению, содержащемуся в JWT.
Думаю, здесь нужно кое-что объяснить. В JWT есть два токена. Один токен — случайно сгенерированная строка — находится в настройках приложения. Меня беспокоит этот вопрос. Не токен JWT, который получает клиент. Мне нужен токен в настройках приложения, чтобы генерировать токены для клиентов. Как правильно защитить токен в настройках приложения? Подходит ли мой подход для этого?
Итак, по сути, вы спрашиваете, хранить ли секрет Het JWT в appsettings.json или другим способом?
@WiseDev да. Мой подход хорош? Я храню секрет JWT в одноэлементном классе и создаю секрет при запуске сервера. Это хороший подход?
«Достаточно хорошо», если вы уверены, что он там будет в безопасности. Но, конечно, всегда можно улучшить хранение секретов, используя такие методы, как Хранилища и т. д.
Поскольку секрет JWT — это секрет, который необходимо особо охранять, я пришел к выводу, что мой подход неправильный. Как уже упоминалось в своем комментарии Peppermintology, рекомендуемым решением является хранение секрета JWT в Azure Key Vault или чем-то подобном. Я рассмотрю это решение для моей проблемы. Спасибо Peppermintology и всем остальным, кто здесь помог.
Вы тут путаете терминологию. В вашем
appsettings
есть неJWT
, а ключ, используемый в процессе генерацииJWT
. Конфиденциальная информация никогда не должна храниться вappsettings
. Вместо этого рассмотрите что-то вроде Azure Key Vault или какую-либо альтернативу.