Как реализовано хранение и шифрование JWT токенов в памяти
Что проверяют
Понимаете ли вы, что сервер обычно вообще не хранит access-токены, а что именно хранить и зачем шифровать, зависит от задачи. Следом спросят, как отозвать токен и что будет с хранилищем в памяти, когда сервис запущен в трёх экземплярах.
Как отвечать
Сначала разведите понятия. Обычный JWT подписан (JWS), а не зашифрован: payload в base64url читается кем угодно, подпись только защищает от подделки. Если содержимое действительно нужно скрыть, для этого есть JWE, но чаще достаточно не класть в токен лишнего.
Дальше про хранение на стороне Go-сервиса:
- access-токен: не хранится, при каждом запросе проверяются подпись и
exp. Библиотекаgithub.com/golang-jwt/jwt/v5;dgrijalva/jwt-goзаброшена и имела уязвимость с проверкойaud; - refresh-токен: хранится не сам, а его хеш SHA-256 с привязкой к пользователю и устройству. Утечка базы тогда не даёт готовых токенов;
- denylist:
jtiотозванных токенов с TTL до ихexp; - где держать:
mapподsync.RWMutexс фоновой очисткой по TTL годится для одного экземпляра и тестов. При нескольких репликах и рестартах нужен Redis, иначе отзыв на одном поде не виден на другом.
Шифровать токены в памяти процесса почти бессмысленно: ключ лежит в той же памяти, и тот, кто прочитал дамп, прочитает и его. Шифрование на уровне приложения уместно для данных в хранилище (AES-GCM из crypto/cipher), и тогда nonce каждый раз берётся из crypto/rand.
Если Go-сервис сам выступает клиентом и держит токен для вызова чужого API, токен хранят в памяти под мьютексом, обновляют заранее, до exp, а одновременные обновления схлопывают через singleflight.
Где спотыкаются
Пишут в обычную map из нескольких горутин без мьютекса. go test -race это ловит, а в проде рантайм падает с concurrent map writes.
Шифруют AES-GCM с нулевым nonce, забыв заполнить его случайными байтами. Повтор nonce в GCM ломает и конфиденциальность, и целостность.
Хранят refresh-токены в открытом виде и хардкодят секрет подписи прямо в коде вместо переменной окружения или менеджера секретов.