微信公众号服务器的接入

Published on 2017 - 02 - 19

微信公众平台提供了一种网址接入的方法,这种方法让我们把公众账号服务器地址提交给微信后台;微信在向我们的公众账号服务器发送数据的时候会带一个加密串,这个加密串只有我们能解密,同时也只有微信后台能生成这个加密串。接下来就具体介绍这个流程和加密/解密方法。

填写服务器配置

登录微信公众平台官网后,在公众平台官网的开发-基本设置页面,勾选协议成为开发者,点击“修改配置”按钮,填写服务器地址(URL)、Token和EncodingAESKey,其中URL是开发者用来接收微信消息和事件的接口URL。Token可由开发者可以任意填写,用作生成签名。 EncodingAESKey由开发者手动填写或随机生成,将用作消息体加解密密钥。

同时,开发者可选择消息加解密方式:明文模式、兼容模式和安全模式。模式的选择与服务器配置在提交后都会立即生效,请开发者谨慎填写及选择。加解密方式的默认状态为明文模式。

Token验证

Token是一个任意的字符串,你提交Token给微信后台之后,只有你和微信后台知道这个字符串是什么,也就是只有微信后台和我们的公众账号服务器知道这个字符串。于是Token就成了这两台服务器之间的密钥,它可以让公众账号服务器确认请求是来自微信后台还是恶意的第三方。

开发者提交信息后,微信服务器将发送GET请求到填写的服务器地址URL上,GET请求携带参数如下表所示:

参数 描述
signature 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
timestamp 时间戳
nonce 随机数
echostr 随机字符串
  • signature是对timestamp、nonce和Token进行SHA1加密后的字符串。SHA1的加密过程是不可逆的,即不能通过signature、timestamp和nonce计算出Token是什么。

  • 在公众账号服务器收到timestamp、nonce和signature之后,同样对nonce、timestamp和Token使用SHA1加密算法,得到自己的签名,如果自己的签名和请求中的signatrue是一样的,那么说明请求是来自微信后台

开发者通过检验signature对请求进行校验(下面有校验方式)。若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,成为开发者成功,否则接入失败。加密/校验流程如下:

  1. 将token、timestamp、nonce三个参数进行字典序排序
  2. 将三个参数字符串拼接成一个字符串进行sha1加密
  3. 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信

检验signature的PHP示例代码:

private function checkSignature()
{
    $signature = $_GET["signature"];
    $timestamp = $_GET["timestamp"];
    $nonce = $_GET["nonce"];

    $token = TOKEN;
    $tmpArr = array($token, $timestamp, $nonce);
    sort($tmpArr, SORT_STRING);
    $tmpStr = implode( $tmpArr );
    $tmpStr = sha1( $tmpStr );

    if( $tmpStr == $signature ){
        return true;
    }else{
        return false;
    }
}

注意恶意的第三方有可能会截获到微信后台发过来的signature、timestamp和nonce三个参数,然后直接用这个三个参数来对公众账号服务器发起请求。按照上面的逻辑是无法判断的出这是个恶意的请求。这种攻击称为“replay攻击”。这种攻击方式的防御方法很简单:加上对timestamp的校验。收到请求之后,我们将请求包中的timestamp和当前时间比较,如果误差大于一定的值就可以认为这个请求是恶意的。这里不能做相等的比较,因为数据在网络上传输需要时间,同时各个服务的本地时间也是有一些差异的。

access_token凭证

Token的存在是用来验证发送给我们的信息是否来自微信后台,但是却没有任何措施来保证微信后台接到的消息是来自合法的公众账号服务器。凭证的出现是为了解决这个问题。虽然通过接入地址可以识别出很大一部分对微信后台的恶意请求,但是通过凭证的方式可以做到更完整、更统一。

获取凭证有以下两个步骤:

  1. 获取自己公众账号的appid和appsecret,在开启开发模式之后,微信公众平台就会在页面上提供给开发者。appid和appsecret是静态的,不会改变。
  2. 通过获取凭证接口获取acess_token,也就是凭证。该接口是以一个HTTP的GET请求的方式提供的。完整的地址和入参如下所示:https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET。

具体的GET参数描述如表所示:

参数 是否必须 说明
grant_type 获取access_token填写client_credential
appid 第三方用户唯一凭证
secret 第三方用户唯一凭证密钥,即appsecret

返回说明

正常情况下,微信会返回下述JSON数据包给公众号:

{"access_token":"ACCESS_TOKEN","expires_in":7200}
参数 说明
access_token 获取到的凭证
expires_in 凭证有效时间,单位:秒

expires_in的值表示在经过多长的时间后,该凭证将会失效。当凭证失效后需要重新调用凭证接口获取新的凭证。如果还没失效前就调用凭证接口,那么获取到新的凭证之后,老的凭证将自动作废,也就是一个公众账号最多同时只能有一个凭证。

错误时微信会返回错误码等信息,JSON数据包示例如下(该示例为AppID无效错误):

{"errcode":40013,"errmsg":"invalid appid"}

参考文档