Я пытаюсь создать безопасный токен для ReCaptcha V2, как описано здесь: https://developers.google.com/recaptcha/docs/secure_token
К сожалению, мой сгенерированный сток недействителен, и я не могу найти способ проверить, почему он не работает. Существует рабочий пример 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 или указать какие-либо очевидные ошибки в моем коде?
В вашем коде есть ряд проблем. Во-первых, ваше значение $secretKey
вычисляется как $secretKey
хэш SHA1, когда для реализации требуются первые шестнадцать байтов хэш SHA1.
$secretKey = substr(hash('sha1', $secretKey, true), 0, 16);
Во-вторых, вы пытаетесь выполнить декодирование base64 секретного ключа, что здесь недействительно. Второй аргумент mcrypt_encrypt()
должен быть $sKey
, а не base64_decode($sKey)
.
Наконец, как объяснено в ответе x77686d, вы должны использовать «base-safe» base64. Это вариация base64, которая не заполнена и не использует символы +
или /
. Вместо этого в своих местах используются символы -
и _
.
Честно говоря, защищенные жетоны ReCaptcha – это немного боль. Они небезопасны, и алгоритм не документирован. Я был в том же положении, что и вам, и мне нужна была реализация, поэтому я написал одну и опубликовал ее на Packagist как «slushie / recaptcha-secure-token» . Я бы рекомендовал использовать его и / или внести вклад, хотя бы из-за отсутствия альтернативных вариантов реализации этого алгоритма.
В примере примера STokenUtils.java Google используется com.google.common.io.BaseEncoding.base64url()
(см. BaseEncoding
), и его кодировка использует '-' и '_' вместо '+' и '/', соответственно.
PHP base64_encode
не выполняет эти замены. См. https://gist.github.com/nathggns/6652997 для base64url_encode
, но вы увидите, что он просто меняет '+' на '-', '/' на '_' и обрезает trailing '=' s ,
У вас могут быть другие проблемы, но я только что исправил эту проблему ( ERROR: Invalid stoken
) в версии Java, используя встроенный кодировщик Base64, выполнив следующие действия:
encoded = encoded.replace('+','-').replace('/','_').replace("=","");
В качестве фиксированной цели попробуйте шифровать и кодировать этот объект:
{"session_id":"1","ts_ms":1437712654577}
с этим секретным ключом
6Lc0MgoTAAAAAAXFM388zn66iPtjOdQgREfZAgqZ
и посмотрите, получилось ли это: (обратите внимание, что подчеркивание посередине!)
XlPyYFtyfzmsf5rnRIzyuZ4MZo5GoCSxNcI_wAeOqb18zCxhSM5cYxU8fFerrdcC
BTW, просто используя этот безопасный токен as-is должен генерировать другую ошибку: ERROR: Stoken expired
. Сделайте, чтобы подчеркнуть косую черту, и вы вернулись к ERROR: Invalid stoken
!
См. Также base64url
на 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; }