Как создать безопасный токен Google ReCaptcha V2 с PHP?
Я пытаюсь создать безопасный токен для ReCaptcha V2, как описано здесь: https://developers.google.com/recaptcha/docs/secure_token
к сожалению, мой сгенерированный stoken недействителен, и я не могу найти способ проверить, почему он не работает. Существует рабочий пример Java (STokenUtils.java), но я не могу перевести его на PHP.
public static function generateSecurityToken($secretKey){
$stoken = array(
'session_id' => session_id(),
'ts_ms' => round(microtime(true)*1000)
);
$secretKey = self::pkcs5_pad(hash('sha1', $secretKey), 16);
$stoken_json = json_encode($stoken);
$stoken_crypt = self::encrypt(self::pkcs5_pad($stoken_json, 16), $secretKey);
return $stoken_crypt;
}
public static function encrypt($sStr, $sKey) {
return base64_encode(
mcrypt_encrypt(
MCRYPT_RIJNDAEL_128,
base64_decode($sKey),
$sStr,
MCRYPT_MODE_ECB
)
);
}
public static function pkcs5_pad ($text, $blocksize) {
$pad = $blocksize - (strlen($text) % $blocksize);
return $text . str_repeat(chr($pad), $pad);
}
может ли кто-нибудь предоставить рабочий пример PHP или указать на какие-либо очевидные ошибки в моем коде?
3 ответов
в вашем коде есть ряд проблем. Во-первых, ваш $secretKey
значение вычисляется как дополненный хэш SHA1, когда реализация требует первые шестнадцать байт хэша SHA1.
$secretKey = substr(hash('sha1', $secretKey, true), 0, 16);
во-вторых, вы пытаетесь выполнить декодирование base64 секретного ключа, который здесь недействителен. Второй аргумент к mcrypt_encrypt()
должно быть $sKey
, а не base64_decode($sKey)
.
наконец, как объясняется в ответе x77686d, вы должны использовать " URL-безопасный" в base64. Это вариация base64, которая не загружена и не использует +
или /
символы. Вместо -
и _
символы используются на своих местах.
Google STokenUtils.пример java использует com.google.common.io.BaseEncoding.base64url()
(см. BaseEncoding
), и его кодировка использует " - " и " _ "вместо" + " и " / " соответственно.
PHP base64_encode
не делает эти замены. См.https://gist.github.com/nathggns/6652997 для base64url_encode
, но вы увидите, что он просто меняет " + "На" -", " / " На " _ "и обрезает трейлинг" = " s.
у вас могут быть другие проблемы, но я только что исправил это та же проблема (ERROR: Invalid stoken
) в версии Java с использованием доморощенного кодировщика Base64, выполнив следующее:
encoded = encoded.replace('+','-').replace('/','_').replace("=","");
в качестве фиксированной цели попробуйте зашифровать и кодировать этот объект:
{"session_id":"1","ts_ms":1437712654577}
С этим секретным ключом
6Lc0MgoTAAAAAAXFM388zn66iPtjOdQgREfZAgqZ
и посмотрите, если вы получите это: (обратите внимание, что подчеркивание в середине!)
XlPyYFtyfzmsf5rnRIzyuZ4MZo5GoCSxNcI_wAeOqb18zCxhSM5cYxU8fFerrdcC
BTW, просто используя этот безопасный токен, как есть, должен генерировать другую ошибку:ERROR: Stoken expired
. Сделайте это подчеркивание косой чертой, и вы вернетесь к ERROR: Invalid stoken
!
см. также base64url
on https://en.wikipedia.org/wiki/Base64
попробуйте это:
public static function generateSecurityToken($secretKey){
$stoken = array(
'session_id' => session_id(),
'ts_ms' => round(microtime(true)*1000)
);
$stoken_json = json_encode($stoken);
$stoken_json = str_replace('+', '-', $stoken_json);
$stoken_json = str_replace('/', '_', $stoken_json);
$stoken_json = str_replace('=', '', $stoken_json);
$secretKey = pack('H*', substr(hash('sha1', $secretKey), 0, 32));
$stoken_crypt = self::encrypt(self::pkcs5_pad($stoken_json, 16), $secretKey);
return $stoken_crypt;
}
public static function encrypt($sStr, $sKey) {
$json = base64_encode(
mcrypt_encrypt(
MCRYPT_RIJNDAEL_128,
$sKey,
$sStr,
MCRYPT_MODE_ECB
)
);
$sStr = str_replace('+', '-', $json);
$sStr = str_replace('/', '_', $sStr);
$sStr = str_replace('=', '', $sStr);
return $sStr;
}