Я пытаюсь использовать работники cloudflare для выполнения действий с проверкой подлинности.
Я использую firebase для аутентификации и имею доступ к проходящим токенам доступа, но, поскольку firebase-admin использует модули nodejs, он не может работать на платформе, поэтому мне остается вручную проверять токен.
Я пытался пройти аутентификацию с помощью Crypto API и, наконец, получил его для импорта открытого ключа, подписывающего токен, чтобы проверить его действительность, но я продолжаю получать FALSE. Я изо всех сил пытаюсь понять, почему он всегда возвращает false для достоверности.
Криптографический ключ, который я импортировал, имеет тип «секрет», хотя я ожидаю, что он будет «общедоступным».
Любые мысли или помощь будут огромными. Последние пару дней бьюсь головой о стол, пытаясь понять это.
Это то, что у меня есть до сих пор:
function _utf8ToUint8Array(str) {
return Base64URL.parse(btoa(unescape(encodeURIComponent(str))))
}
class Base64URL {
static parse(s) {
return new Uint8Array(Array.prototype.map.call(atob(s.replace(/-/g, '+').replace(/_/g, '/').replace(/\s/g, '')), c => c.charCodeAt(0)))
}
static stringify(a) {
return btoa(String.fromCharCode.apply(0, a)).replace(/=/g, '').replace(/\+/g, '-').replace(///g, '_')
}
}
export async function verify(userToken: string) {
let jwt = decodeJWT(userToken)
var jwKey = await fetchPublicKey(jwt.header.kid);
let publicKey = await importPublicKey(jwKey);
var isValid = await verifyPublicKey(publicKey, userToken);
console.info('isValid', isValid) // RETURNS FALSE
return isValid;
}
function decodeJWT(jwtString: string): IJWT {
// @ts-ignore
const jwt: IJWT = jwtString.match(
/(?<header>[^.]+)\.(?<payload>[^.]+)\.(?<signature>[^.]+)/
).groups;
// @ts-ignore
jwt.header = JSON.parse(atob(jwt.header));
// @ts-ignore
jwt.payload = JSON.parse(atob(jwt.payload));
return jwt;
}
async function fetchPublicKey(kid: string) {
var key: any = await (await fetch('https://www.googleapis.com/robot/v1/metadata/x509/[email protected]')).json();
key = key[kid];
key = _utf8ToUint8Array(key)
return key;
}
function importPublicKey(jwKey) {
return crypto.subtle.importKey('raw', jwKey, { name: 'HMAC', hash: { name: 'SHA-256' } }, false, ['sign']);
}
async function verifyPublicKey(publicKey: CryptoKey, token: string) {
const tokenParts = token.split('.')
let res = await crypto.subtle.sign({ name: 'HMAC', hash: { name: 'SHA-256' } }, publicKey, _utf8ToUint8Array(tokenParts.slice(0, 2).join('.')))
return Base64URL.stringify(new Uint8Array(res)) === tokenParts[2];
}
да не повезло к сожалению
Есть несколько проблем с вашим кодом:
URL-адрес, который вы вызываете для получения открытых ключей, возвращает список сертификатов x509. Это не открытые ключи, используемые для проверки подписи. Вы уверены, что у вас нет прямого доступа к открытым ключам? Похоже, что можно получить информацию об открытом ключе из сертификата x509 (как описано здесь: Извлечение открытого ключа PEM из сертификата X.509), хотя я не уверен, возможно ли это от работника Cloudflare.
В importPublicKey
вы сообщаете методу import
, что ключ имеет необработанный формат и что это ключ HMAC
. Это означает, что Crypto обрабатывает ваш ключ как симметричный ключ HMAC, а не как открытый ключ. Согласно документам: https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey#subjectpublickeyinfo вы должны использовать формат spki
, так как именно он импортирует открытый ключ. Вам нужно заранее знать, подписан ли токен доступа JWT с использованием алгоритма RSA или Elliptic Curve. (например, проверьте претензию заголовка alg
)
Вы используете метод sign
для проверки подписи. Это не так работает. Вы должны использовать метод verify
из crypto.subtle
, и этот метод проверит подпись за вас.
Я думаю, вам не следует пытаться проверять JWT вручную, так как вы, скорее всего, сделаете это неправильно (и создадите проблемы безопасности для своего приложения). Вы должны использовать библиотеки, которые занимаются проверкой подписей JWT. Это будет намного проще для вас и безопаснее для вашего приложения. Одна вещь, которую вы должны выяснить, это то, откуда вы должны взять открытый ключ.
Привет Михал, Спасибо за ваши мысли. Я покопаюсь в 1 и исправлю 2 и 3. Я согласился проверить JWT вручную, надеюсь, криптобиблиотека поможет. Моя самая большая проблема заключается в том, что я не могу найти библиотеку JWT, которая не использует узел для выполнения этой проверки. Я наткнулся на 1 по этой документации: firebase.google.com/docs/auth/admin/…
Удалось заставить его работать с jsrsasign, спасибо за вашу помощь!. Я перешел к проверке. сертификаты X.509 вроде бы работали
Работники Cloudflare поддерживают пакет Облачный рабочий JWT. вы пробовали это использовать?