Я использую PHP Firebase JWT для реализации JWT в своем PHP-приложении. Вот мой код
$payload = [
'iss' => 'http://test.com',
'aud' => 'http://test.com',
'iat' => time(), // Issued at
'exp' => time() + 3600, // Expiration (1 hour)
'data' => [
'user_id' => $user['id'],
'email' => $user['email'],
'role' => $user['role'],
'is_admin' => $user['isadmin']
]
];
$jwt = JWT::encode($payload, $key, 'HS256', $key_file);
После кодирования генерирует токен eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6Ii92YXIvd3d3L215a2V5LmtleSJ9.eyJpc3MiOiJodHRwOi8vdGVzdC5jb20iLCJhdWQiOiJodHRwOi8vdGVzdC5jb20iLCJpYXQiOjE3MjM5NzQ5OTMsImV4cCI6MTcyMzk3ODU5MywiZGF0YSI6eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImFiYyIsInJvbGUiOiJ1c2VyIiwiaXNfYWRtaW4iOjB9fQ.uC13pivSZGnPr6i8zmPCfEFMsykWR5miIK8t0-DCnug
это нормально
Содержимое ключевого файла: hellohellohellohellohellohellohe
Я использовал сайт https://jwt.io/ для тестирования своего токена и несколько других сайтов https://dinochiesa.github.io/jwt/
Теперь я хочу, чтобы обычный пользователь сгенерировал токен через любой веб-сайт, изменив ключевой параметр kid и используя любой веб-сайт в Интернете, чтобы его можно было использовать на сайте (демонстрируя уязвимость).
Я столкнулся с двумя проблемами; если я попытаюсь проверить токен с помощью вышеуказанного ключа на любом из веб-сайтов с файлом ключа, он скажет, что он не может сопоставиться или проверить; в чем проблема? Работает ли JWT на основе PHP Firebase по-другому? Я тоже проверил это Подпись JWT не проверяется в PHP
Вот скриншот проверяемой подписи: i.sstatic.net/Je1bka2C.png
@IMSoP, пожалуйста, посмотрите ibb.co/WDs7Nk7 Если вы посмотрите на свой JTW после вставки ключа, вы заметите, что он был изменен.
О, я понимаю, что ты имеешь в виду. Я предполагаю, что $key
не содержит того, что вы думаете, например. вы читаете его из файла, в котором есть дополнительные символы, такие как окончания строк. Попробуйте использовать строку, жестко закодированную в PHP, чтобы вы могли точно знать, что она содержит.
@IMSoP Я просматривал исходный код, и он содержит return \hash_hmac($algorithm, $msg, $key, true); Я проверил, что перед хешированием ключ содержит правильное значение.
Эта строка кода дает мне достаточно информации, чтобы доказать, что значение не такое, как вы думали. Он нигде не меняется, просто каждый раз, когда вы просматриваете его, вы упускаете из виду новую строку, включенную в конец.
Поскольку вы читаете ключ из файла, а не тестируете его с жестко закодированным значением, трудно увидеть, есть ли в нем дополнительные символы, например, разрывы строк.
Если вы сгенерируете хэш вручную, используя то, что, по вашему мнению, является вашим ключом, вы увидите другую подпись:
$msg = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6Ii92YXIvd3d3L215a2V5LmtleSJ9.eyJpc3MiOiJodHRwOi8vdGVzdC5jb20iLCJhdWQiOiJodHRwOi8vdGVzdC5jb20iLCJpYXQiOjE3MjM5NzQ5OTMsImV4cCI6MTcyMzk3ODU5MywiZGF0YSI6eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImFiYyIsInJvbGUiOiJ1c2VyIiwiaXNfYWRtaW4iOjB9fQ';
$key = 'hellohellohellohellohellohellohe';
$algorithm = 'SHA256';
$signature = hash_hmac($algorithm, $msg, $key, true);
echo base64_encode($signature);
#=> zBeba1d7bk/OhMeo5P/Aw1aO2v4JxW+8QXGJsCx1AWI=
Но если вы добавите одну новую строку в конце, вы увидите подпись в образце JWT (кроме немного другого варианта кодировки BASE64 с «-» вместо «+»):
$msg = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6Ii92YXIvd3d3L215a2V5LmtleSJ9.eyJpc3MiOiJodHRwOi8vdGVzdC5jb20iLCJhdWQiOiJodHRwOi8vdGVzdC5jb20iLCJpYXQiOjE3MjM5NzQ5OTMsImV4cCI6MTcyMzk3ODU5MywiZGF0YSI6eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImFiYyIsInJvbGUiOiJ1c2VyIiwiaXNfYWRtaW4iOjB9fQ';
$key = "hellohellohellohellohellohellohe\n";
$algorithm = 'SHA256';
$signature = hash_hmac($algorithm, $msg, $key, true);
echo base64_encode($signature);
#=> uC13pivSZGnPr6i8zmPCfEFMsykWR5miIK8t0+DCnug=
Вы могли бы провести тот же эксперимент непосредственно с функцией JWT::encode
, но у меня нет под рукой среды, в которой я мог бы установить библиотеку.
Я только что вставил ваш пример токена и секрета в отладчик на jwt.io, и там написано «Подпись проверена», поэтому я не понимаю, о чем вы спрашиваете. Я также немного смущен тем, что вы подразумеваете под «изменением параметра ключа ребенка» -
kid
— это просто информационное поле, подсказывающее, какой из нескольких общих ключей пользователь токена должен использовать для проверки или расшифровки токена, это не влияет сама подпись.