这两天又开始做微信公众平台的开发,发现一个很奇怪的现象,从微信客户端发送的消息有时候能被回应,有时不能回应,起初我以为是网络问题,换了几个服务器问题依旧,检查后发现原因居然是签名验证问题!!!
而SDK用的签名验证代码分明是微信官方开发文档里的Demo代码:
private function checkSignature()
{
$signature = $_GET["signature"];
$timestamp = $_GET["timestamp"];
$nonce = $_GET["nonce"];
$token = TOKEN;
$tmpArr = array($token, $timestamp, $nonce);
sort($tmpArr);
$tmpStr = implode( $tmpArr );
$tmpStr = sha1( $tmpStr );
if( $tmpStr == $signature ){
return true;
}else{
return false;
}
}
同时文档给出的加密/校验流程如下:
1. 将token、timestamp、nonce三个参数进行字典序排序
2. 将三个参数字符串拼接成一个字符串进行sha1加密
3. 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
问题出在sort($tmpArr) 排序这一步。php中的sort函数的第二个参数是sort_flags,PHP文档说明如下
可选的第二个参数 sort_flags 可以用以下值改变排序的行为:
排序类型标记:
1. SORT_REGULAR – 正常比较单元(不改变类型)
2. SORT_NUMERIC – 单元被作为数字来比较
3. SORT_STRING – 单元被作为字符串来比较
4. SORT_LOCALE_STRING – 根据当前的区域(locale)设置来把单元当作字符串比较,可以用 setlocale() 来改变。
5. SORT_NATURAL – 和 natsort() 类似对每个单元以“自然的顺序”对字符串进行排序。 PHP 5.4.0 中新增的。
6. SORT_FLAG_CASE – 能够与 SORT_STRING 或 SORT_NATURAL 合并(OR 位运算),不区分大小写排序字符串。
默认状态下为SORT_REGULAR ,而要将token、timestamp、nonce三个参数进行字典序排序实际上应该是SORT_STRING。
比如下面一个数组:
array (
0 =>'weixin',
1 =>'1393914919',
2 =>'576856862',
)
//用SORT_REGULAR排序:
array (
0 =>'576856862',
1 =>'1393914919',
2 =>'weixin',
)
//用SORT_STRING排序:
array (
0 =>'1393914919',
1 =>'576856862',
2 =>'weixin',
)
SORT_REGULAR在比较整数时是按数字大小
而SORT_STRING在比较整数时则是按ASCI码
这个排序就不一样了,当然因为nounce是一串随机数字,所以也有可能出现这两种排序一致的情况.
比如这个:
array (
0 =>'weixin',
1 =>'1393915880',
2 =>'1540126295',
)
//用SORT_REGULAR排序:
array (
0 =>'1393915880',
1 =>'1540126295',
2 =>'weixin',
)
//用SORT_STRING排序:
array (
0 =>'1393915880',
1 =>'1540126295',
2 =>'weixin',
)
所以服务端的响应有一定机率成功,一定机率失败。
实际上这种情况是最近这几天才出现的,用以前的SDK开发之前一直没问题,最近腾讯应该改了服务端的代码,通知不发,官方文档DEMO代码不改,让那些还用原来SDK的开发者情何以堪!而签名验证这种基础层面的错误,目测是中招者一大片的节奏了。
本人测试公众号,欢迎关注: