我正在尝试为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示例或指出任何明显的错误在我的代码?
您的代码中有许多问题。首先,当实现需要SHA1散列的前16个字节时,您的$secretKey
值被计算为填充的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。
您可能有其他其他问题,但我刚刚通过这样做,在使用本地Base64编码器的Java版本修复了同样的问题(ERROR: Invalid stoken
):
encoded = encoded.replace('+','-').replace('/','_').replace("=","");
作为一个固定目标,尝试加密和编码这个对象:
{"session_id":"1","ts_ms":1437712654577}
使用这个秘密密钥
6Lc0MgoTAAAAAAXFM388zn66iPtjOdQgREfZAgqZ
,看看你是否得到这个:(注意中间的下划线!)
XlPyYFtyfzmsf5rnRIzyuZ4MZo5GoCSxNcI_wAeOqb18zCxhSM5cYxU8fFerrdcC
顺便说一句,简单地使用这个安全令牌应该会产生一个不同的错误: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;
}