Как создать защищенный токен Google ReCaptcha V2 с помощью PHP?

Я пытаюсь создать безопасный токен для 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; }