因 php 默认的 url encode 编码标准引发的一个问题
2018-09-25 16:05
681 查看
先看常用的校验请求合法性的一个方式
输出
client 每个请求都携带一个 token ,token 是由请求参数和一个 secret key 一起md5之后计算出来的, 然后 server 端使用同样的算法计算token(一般还会校验time,给 token 一个有效期,我这里简化了),然后对比 token ,保证请求的合法性。
乍一看,这个算法几乎天衣无缝,恩,我之前也是这么认为的,直到我用这个算法和一个 java 的服务交互时,才发现这个写法有些问题。
我在和 java 的同事连调时,有个请求总是报 token 校验错误,但是其他请求却没这个问题,我俩百思不得其解,互相 review 对方代码,也没有发现问题,然后和 java 的同事加了很多 log,终于发现了端倪。
我请求的参数里,有一个参数的值带有空格,然后我这边 url encode 之后
但是他那边 url encode 之后是
这样,问题就很清晰了,不是算法问题,而是 url encode 的编码标准的问题。
php的 http_build_query (urlencode也一样)默认使用的 RFC 1738 (http://php.net/manual/zh/function.http-build-query.php)
默认使用 PHP_QUERY_RFC1738,如果 enc_type 是 PHP_QUERY_RFC1738,则编码将会以 RFC 1738 标准和 application/x-> www-form-urlencoded 媒体类型进行编码,空格会被编码成加号(+),如果 enc_type 是 PHP_QUERY_RFC3986,将根据 RFC 3986 编码,空格会被百分号编码(%20)。
而他那边用的是 RFC 3986 。
那么怎么规避这个问题呢?
常见的无非就是这两种方案,第一,两边使用同样的编码标准,第二,生成 token 的算法改一下,不要使用 url encode 之后的字符串加密(建议)。
更多架构、PHP、GO相关踩坑实践技巧请关注我的公众号:PHP架构师
function createToken($params) { $secretKey = 'secretKey'; ksort($params); $query = http_build_query($params); $token = md5($query . $secretKey); return $token; } function createQuery($params) { $params['token'] = createToken($params); $query = http_build_query($params); return $query; } function checkQuery($params) { $token = $params['token']; unset($params['token']); return $token == createToken($params); } $params = [ 'k1' => 'v1', 'k2' => 'v2', 'time' => time() ]; $query = createQuery($params); echo $query, PHP_EOL; parse_str($query, $result); var_dump(checkQuery($result));
输出
k1=v1&k2=v%202&time=1537806711&token=e088ac85569f9eb5266026bb8da989b2 bool(true)
client 每个请求都携带一个 token ,token 是由请求参数和一个 secret key 一起md5之后计算出来的, 然后 server 端使用同样的算法计算token(一般还会校验time,给 token 一个有效期,我这里简化了),然后对比 token ,保证请求的合法性。
乍一看,这个算法几乎天衣无缝,恩,我之前也是这么认为的,直到我用这个算法和一个 java 的服务交互时,才发现这个写法有些问题。
我在和 java 的同事连调时,有个请求总是报 token 校验错误,但是其他请求却没这个问题,我俩百思不得其解,互相 review 对方代码,也没有发现问题,然后和 java 的同事加了很多 log,终于发现了端倪。
我请求的参数里,有一个参数的值带有空格,然后我这边 url encode 之后
echo urlencode(" "); // +
但是他那边 url encode 之后是
// 假装这里有 java url encode 的代码 %20
这样,问题就很清晰了,不是算法问题,而是 url encode 的编码标准的问题。
php的 http_build_query (urlencode也一样)默认使用的 RFC 1738 (http://php.net/manual/zh/function.http-build-query.php)
默认使用 PHP_QUERY_RFC1738,如果 enc_type 是 PHP_QUERY_RFC1738,则编码将会以 RFC 1738 标准和 application/x-> www-form-urlencoded 媒体类型进行编码,空格会被编码成加号(+),如果 enc_type 是 PHP_QUERY_RFC3986,将根据 RFC 3986 编码,空格会被百分号编码(%20)。
而他那边用的是 RFC 3986 。
那么怎么规避这个问题呢?
常见的无非就是这两种方案,第一,两边使用同样的编码标准,第二,生成 token 的算法改一下,不要使用 url encode 之后的字符串加密(建议)。
更多架构、PHP、GO相关踩坑实践技巧请关注我的公众号:PHP架构师
相关文章推荐
- PHP中utf-8编码格式之BOM引发的问题
- 一个php版本引发的问题
- php中的一个时间函数引发的问题
- apache mod-wsgi引发的文件系统默认编码问题
- 一个编码引发js错误的问题
- InputStreamReader引发的一个编码问题
- Apache以及PHP的默认编码问题解决(详解)
- Apache以及PHP的默认编码问题解决(详解)
- 一个PHP的网页,打开时IE默认用西欧编码来看
- PHP网页UTF8编码开发中空白的问题
- PHP字符集编码问题
- php:一个img问题
- PHP浮点数的一个常见问题的解答 (转载 http://www.laruence.com/2013/03/26/2884.html)
- 一个小问题引发的论证思考
- 解决php5+mysql5.1.1+html+javascript之间的编码问题
- PHP中递归函数的一个常见逻辑问题
- PHP 各个服务器对同一个客户端产生同一个SessionID的问题
- PHP浮点数的一个常见问题的解答
- 一个问号引发的血案之程序员的职业素养(java.sql.SQLException: 无效的列索引问题)
- 【PHP】数组foreach引发的小问题