jwtпакет
Пакет лежит в основном пуле хаба: короткой формы достаточно, если хаб прописан сервером пакетов в opm.cfg.
opm install jwtУстановка на opm младше 1.7.0
Легаси-флоу. Клиент младше 1.7.0 адрес пула в аргументе не разбирает: пул сначала прописывают сервером пакетов, и только потом ставят через него. На 1.7.0 и новее этот раздел не нужен — хватает команды из шапки страницы.
Добавьте пул сервером пакетов в opm.cfg. Порт продублирован в «Сервер»: у opm push поле «Порт» не читается.
{
"СервераПакетов": [
{
"Имя": "default",
"Сервер": "https://hub.1cdevelopers.ru",
"Порт": 443,
"ПутьНаСервере": "/api/v1/pools/default/download/",
"РесурсПубликацииПакетов": "/api/v1/pools/default/push",
"Приоритет": 1
}
]
}И ставьте пакет, указывая сервер:
opm install -m default jwtОписание
jwt
Реализация JSON Web Token (RFC 7519) для OneScript: подпись и проверка токенов на алгоритмах семейства HMAC.
Подпись собрана поверх штатного ХешированиеДанных - HMAC реализован по RFC 2104, внешних компонент и нативных библиотек не требуется.
Установка
opm install jwt
Использование
Выпуск токена
#Использовать jwt
Нагрузка = Новый Структура("sub,role", "user-42", "admin");
Токен = JWT.Подписать(Нагрузка, Секрет, Новый Структура("ВремяЖизни", 3600));
ВремяЖизни в секундах заполняет exp, а iat проставляется автоматически.
Проверка токена
Проверка не выбрасывает исключений - причина отказа возвращается в результате:
Результат = JWT.Проверить(Токен, Секрет);
Если Результат.Валиден Тогда
Роль = Результат.ПолезнаяНагрузка["role"];
Иначе
Логировать(Результат.КодОшибки, Результат.Ошибка); // TOKEN_EXPIRED, ...
КонецЕсли;
ПолезнаяНагрузка заполняется только для валидного токена: непроверенные данные невозможно использовать по ошибке.
Проверка с ожидаемыми утверждениями
Параметры = Новый Структура();
Параметры.Вставить("Издатель", "oneflag");
Параметры.Вставить("Аудитория", "dashboard");
Параметры.Вставить("Допуск", 30); // расхождение часов, секунды
Результат = JWT.Проверить(Токен, Секрет, Параметры);
Результат.ВыброситьЕслиНеВалиден();
Публичный API
Модуль JWT
| Метод | Возвращает | Описание |
|---|---|---|
Подписать(ПолезнаяНагрузка, Секрет, Параметры = Неопределено) |
Строка |
Токен в компактной сериализации JWS |
Проверить(Токен, Секрет, Параметры = Неопределено) |
JwtVerificationResult |
Проверка подписи и утверждений |
ПроверитьАсимметричный(Токен, Проверяющий, Параметры = Неопределено) |
JwtVerificationResult |
Утверждения чужого токена, подпись которого проверяет внешний объект |
Разобрать(Токен) |
Структура |
Заголовок и нагрузка без проверки подписи |
ПоддерживаемыеАлгоритмы() |
Массив |
HS256, HS384, HS512 |
ТекущееВремя() |
Число |
Текущее время в формате NumericDate |
Параметры подписи
| Параметр | Тип | Действие |
|---|---|---|
Алгоритм |
Строка | HS256 (по умолчанию), HS384, HS512 |
ВремяЖизни |
Число | Срок жизни в секундах, заполняет exp |
ДействителенЧерез |
Число | Задержка вступления в силу, заполняет nbf |
Издатель / Аудитория / Субъект / Идентификатор |
Строка, Массив | iss, aud, sub, jti |
ДобавлятьВремяВыпуска |
Булево | Заполнять iat, по умолчанию Истина |
ИдентификаторКлюча |
Строка | Заголовок kid |
ТипТокена |
Строка | Заголовок typ, по умолчанию JWT |
ДополнительныеЗаголовки |
Структура, Соответствие | Прочие заголовки JOSE |
ТекущееВремя |
Число | Подмена текущего времени (для тестов) |
Если утверждение задано и в полезной нагрузке, и параметром, выбрасывается исключение: молчаливая перезапись слишком легко приводит к неверным токенам.
Параметры проверки
| Параметр | Тип | Действие |
|---|---|---|
Алгоритмы |
Массив | Разрешённые алгоритмы, по умолчанию все три |
ПроверятьСрок |
Булево | Проверять exp и nbf, по умолчанию Истина |
Допуск |
Число | Допустимое расхождение часов в секундах |
Издатель / Аудитория / Субъект |
Строка, Массив | Ожидаемые iss, aud, sub |
ТипТокена |
Строка | Ожидаемый typ |
ТребоватьСрок / ТребоватьДействителенС / ТребоватьВремяВыпуска |
Булево | Считать отсутствие exp / nbf / iat ошибкой |
ТекущееВремя |
Число | Подмена текущего времени (для тестов) |
Класс JwtVerificationResult
Свойства Валиден, ПолезнаяНагрузка, Заголовок, КодОшибки, Ошибка; методы Утверждение(Имя, ЗначениеПоУмолчанию) и ВыброситьЕслиНеВалиден().
Коды отказа
| Код | Причина |
|---|---|
MALFORMED |
Токен не разбирается: не три части, битый base64url или не JSON |
INVALID_SIGNATURE |
Подпись не соответствует содержимому или ключу |
TOKEN_EXPIRED |
Истёк exp |
TOKEN_NOT_ACTIVE |
Не наступил nbf |
MISSING_CLAIM |
Отсутствует утверждение, объявленное обязательным |
INVALID_ISSUER / INVALID_AUDIENCE / INVALID_SUBJECT |
iss / aud / sub не совпали с ожидаемым |
ALGORITHM_NOT_ALLOWED |
Алгоритм none либо алгоритм вне списка разрешённых |
UNSUPPORTED_ALGORITHM |
Алгоритм неизвестен библиотеке |
UNSUPPORTED_CRITICAL_HEADER |
Присутствует заголовок crit |
INVALID_TYPE |
typ не совпал с ожидаемым |
KEY_ID_MISSING |
В заголовке нет kid, выбрать ключ нечем (только асимметричная проверка) |
KEY_NOT_FOUND |
Ключ с таким kid недоступен: ключи не загрузились или их нет (только асимметричная проверка) |
VERIFIER_FAILED |
Внешний проверяющий подписи упал с исключением |
VERIFICATION_FAILED |
Внешний проверяющий отказал по причине, которой нет в этом списке |
Безопасность
Реализованы защиты, отсутствие которых регулярно приводит к обходу авторизации в других библиотеках:
- Алгоритм
noneзапрещён всегда, даже если он указан в списке разрешённых. - Список алгоритмов задаёт проверяющая сторона. Значению
algиз самого токена не доверяем, поэтому подмена алгоритма не проходит. - Подписи сравниваются за постоянное время - по длительности проверки нельзя подобрать корректную подпись.
- Заголовок
critотвергается: RFC 7515 требует понимать критические расширения, а библиотека их не поддерживает. - Нагрузка невалидного токена не возвращается, поэтому её нельзя случайно использовать.
Чужие токены на RS256
Библиотека подписывает и проверяет только HMAC. Для токена, выпущенного чужой стороной, HMAC не годится в принципе: общего секрета нет, а есть открытые ключи издателя. Подпись RS256 проверяет пакет jwt-verify, а эта библиотека добавляет поверх то, чего он намеренно не делает, - ожидания принимающего сервиса:
#Использовать jwt
#Использовать jwt-verify
Проверяющий = Новый ПроверяющийJWS(Новый КэшJWKS("https://token.actions.githubusercontent.com"));
Параметры = Новый Структура();
Параметры.Вставить("Издатель", "https://token.actions.githubusercontent.com");
Параметры.Вставить("Аудитория", "https://hub.example.com");
Результат = JWT.ПроверитьАсимметричный(Токен, Проверяющий, Параметры);
Если Результат.Валиден Тогда
Репозиторий = Результат.Утверждение("repository");
КонецЕсли;
Результат того же класса, что и у симметричной проверки, а коды отказа переведены в общий словарь: прикладной код разбирает исход одинаково, чем бы токен ни был подписан. Проверяющим годится любой объект с методом Проверить(Токен), возвращающим структуру с полями Успех, Код, Сообщение, Алгоритм, Заголовок и Клеймы, поэтому зависимости времени выполнения у библиотеки по-прежнему нет.
Выпускать RS256-токены библиотека не умеет: для подписи нужен закрытый ключ и полноценная реализация RSA, тогда как для проверки достаточно возведения в степень по модулю. Попытка подписать асимметричным алгоритмом вызывает исключение, а не молчаливый откат на HMAC.
Соответствие спецификации
Проверено на эталонных значениях:
- HMAC совпадает с тестовыми векторами RFC 4231 для SHA-256, SHA-384 и SHA-512, включая случай ключа длиннее блока.
- Подписанный токен байт в байт совпадает с эталоном jwt.io для
HS256. - Токен из RFC 7515, приложение A.1 успешно проверяется.
base64urlбез выравнивания - RFC 7515, приложение C.NumericDate(exp,nbf,iat) - секунды с 1970-01-01T00:00:00Z, RFC 7519, раздел 2.audпринимается и строкой, и массивом строк - RFC 7519, раздел 4.1.3.
Тесты
opm install -l
oneunit execute -d ./tests