前言,在作某个渠道的过程当中,发现一个验签错误的问题。可是,当时验签在两个地方表现不一致,同一套处理方法,想到了这是由于两个地方请求方式是不一样的一个get方法另一个天然是post方法。固然,出问题确定就是get。php
GET请求方式,因为是将参数放在URL中,因此在进行传递的时候可能会受到浏览器端的一些策略问题,对参数进行urlencode处理。因此,当你在服务端拿到参数的时候可能并非原始的数据。所以,在经过GET方式请求拿到数据,若是不作任何处理的话去验签可能会存在问题。这边的可能就是当base64处理以后不含+这个特殊的字符,+在GET方式以后不作任何处理拿到的就是一个空白字符串。程序员
POST请求方式,是将参数放在request body中,在进行http传递的过程当中不会存在因为浏览器的一些策略问题对参数进行任何的处理。所以,经过POST请求进行参数验签的时候不会存在问题,可以很顺利的进行验签。可是,咱们没有办法去要求渠道商将get请求变成post请求,所以咱们只能本身想办法。算法
urlencode:浏览器
(PHP 4, PHP 5, PHP 7) urlencode — 编码 URL 字符串 string urlencode ( string $str ) 此函数便于将字符串编码并将其用于 URL 的请求部分,同时它还便于将变量传递给下一页。 return 返回字符串,此字符串中除了 -_. 以外的全部非字母数字字符都将被替换成百分号(%)后跟两位十六进制数,空格则编码为加号(+)。此编码与 WWW 表单 POST 数据的编码方式是同样的,同时与 application/x-www-form-urlencoded 的媒体类型编码方式同样
urldecode:app
(PHP 4, PHP 5, PHP 7) urldecode — 解码已编码的 URL 字符串 string urldecode ( string $str ) 解码给出的已编码字符串中的任何 %##。 加号('+')被解码成一个空格字符。 返回解码后的字符串。
好像咱们看到了曙光,对+这个会变成空格的字符串的"完美处理方式"。那就是,对签名字符串进行urlencode进行加密处理。而后,兴高采烈的去验证,fxxk,false。仍是不经过,而后甩本身一个耳光。base64加密以后会出现=这个补位字符串,很蛋疼。因而我就想了一个临时处理方式。函数
urlencode(substr($str,0,strlen($sign)-2)).substr($sign,strlen($sign)-2)
当时,考虑到base64最多出现两个==,因此在最后两个不进行urlencode处理。这个基本上可以处理,可是可能存在一个问题,那就是在最后两位出现+也是不行的,果真这个方案不能说服本身,推翻。而且在这个过程还发现一个问题就是,传过来的签名字符串还有可能会已经通过urlencode处理。这个仍是一个小问题,先进行urldecode处理,由于decode不会引发误会。post
当时,小伙伴提出一个解决办法,那就是直接替换+号不就能够了吗?的确,这是一个办法。可是我认为这个办法很挫,若是之后加密算法改变了或者增长了其余特殊字符呢,好比@#¥%……&**( 等这些,咱们不可能都去匹配替换什么的。因此,我赞成临时方案处理,可是我继续想。编码
rawurlencode:加密
(PHP 4, PHP 5, PHP 7) rawurlencode — 按照 RFC 3986 对 URL 进行编码 string rawurlencode ( string $str ) 根据 » RFC 3986 编码指定的字符。
rawurldecode:url
(PHP 4, PHP 5, PHP 7) rawurldecode — 对已编码的 URL 字符串进行解码 string rawurldecode ( string $str ) 返回字符串,此字符串中百分号(%)后跟两位十六进制数的序列都将被替换成原义字符。
新的曙光出现了,理解rawurldecode,替换成原义字符。因此,解决方案呼之欲出了。
rawurldecode(urlencode(urldecode($sign))));
初看上去以为还臃肿或者为何要这么绕来绕去处理呢?其实你还真得这么处理,至于为何,请看上上面的吹牛逼。
做为程序员,咱们必需要有两手准备,一手临时方案,可以快速修复如今问题。在生产环境恢复正常,可是从长远来看必需要可以一个稳定可靠的方案。方案来源于你不断的尝试和php.net。