前言,在做一个登录的过程中,发现个别账号验证通不过,仔细排查后发现是接收的参数进行了urldecode处理,使得某些特殊字符如加号’+‘变成了空格,以至于影响到了后面的数据。下面来看看代码。
get 方法代码
function get($key = null, $default = null) {
if (is_null($key)) {
foreach ($_GET as $key => $val) {
$_GET[$key] = trim(urldecode($val));
}
return $_GET;
} else {
$_GET[$key] = (isset($_GET[$key]) && $_GET[$key] != '') ? $_GET[$key] : $default;
return trim(urldecode($_GET[$key]));
}
}
登录验证代码
$input = \Util::get('data');
$data = json_decode(base64_decode($input), TRUE);
if ($this->do_verify($data) != 1){
$output['msg'] = "登陆验证失败!";
return (json_encode($output));
}
上述代码\Util::get(‘data’)接收到的 data 数据:
eyJ1aWQiOiIxMTc5NTIwNDA1MDAwNDI1IiwidWluIjoiQe 8h 8hyDkuIDliIDYgiIsInRva2VuIjoiQDE3MUA5MUAxNjNAODJAMTExQDg4QDExMEAxMDNAMTA1QDE1NkAxMDRAMTEwQDEwNkAxMDhAMTUyQDE0OUA4NkA5NkA4N0AxNzJAMTU5QDE0OUA5MEAxMTRAODNAMTAyQDEwM0AxMDhAMTExQDEwNEAxMDVAMTAzQDEwMEAxMDVAMTAxQDk2QDEwMUAxMDJAMTA3QDEwNEAxMDJAODlAOTdAOTFAMTY5QDE1NkAxNjFAMTUyQDg2QDExMEAxMDRAMTAzQDEwM0A5M0A5MEAxNTVAODNAMTExQDg4QDEwM0AxMDZAODVAMTgwIn0=
可以看到有两处分别有一个空格和两个空格,通过base64_decode和json_decode后,值成了 NULL,因此通不过后面的验证。
要怎么办呢,$data 这里肯定是不能改的,不然会影响绝大部分的登录,通不过验证的毕竟只是小部分,最好的方法就是在 if 里将获取的数据进一步处理,将特殊字符解析出来,既然接收的时候用了urldecode,那就将它用urlencode转回来吧
$input = urlencode($input);
urlencode转换后的数据:
eyJ1aWQiOiIxMTc5NTIwNDA1MDAwNDI1IiwidWluIjoiQe+8h++8hyDkuIDliIDYgiIsInRva2VuIjoiQDE3MUA5MUAxNjNAODJAMTExQDg4QDExMEAxMDNAMTA1QDE1NkAxMDRAMTEwQDEwNkAxMDhAMTUyQDE0OUA4NkA5NkA4N0AxNzJAMTU5QDE0OUA5MEAxMTRAODNAMTAyQDEwM0AxMDhAMTExQDEwNEAxMDVAMTAzQDEwMEAxMDVAMTAxQDk2QDEwMUAxMDJAMTA3QDEwNEAxMDJAODlAOTdAOTFAMTY5QDE1NkAxNjFAMTUyQDg2QDExMEAxMDRAMTAzQDEwM0A5M0A5MEAxNTVAODNAMTExQDg4QDEwM0AxMDZAODVAMTgwIn0%3D
仔细看,加号’+‘出来了
再用json_decode(base64_decode($input)), TRUE)处理$input 后发现还是 NULL,为什么呢,一步步分析,先查看base64_decode($input)是什么
{"uid":"1179520405000425","uin":"A'' 一刀","token":"@171@91@163@82@111@88@110@103@105@156@104@110@106@108@152@149@86@96@87@172@159@149@90@114@83@102@103@108@111@104@105@103@100@105@101@96@101@102@107@104@102@89@97@91@169@156@161@152@86@110@104@103@103@93@90@155@83@111@88@103@106@85@180"}7
这个 json 数据后面怎么会单独有个数字呀,一看就不对,怪不得 json_decode 后数据是 NULL,那这个 7 是如何来的呢,数据先是urlencode后再base64_decode,这里可以发现,urlencode后,使得原数据’=‘号变成了’%3D‘,进而造成base64_decode解析错误,所以使用urlencode还是不太正确的,那么究竟用什么来解决这一问题。
这就要讲到rawurldecode了,先来看下它的含义,
(PHP 4, PHP 5, PHP 7)
rawurldecode — 对已编码的 URL 字符串进行解码
说明
rawurldecode ( string $str ) : string
返回字符串,此字符串中百分号(%)后跟两位十六进制数的序列都将被替换成原义字符。
那么就来用下 rawurldecode 吧
$input = rawurldecode(urlencode($input));
再次查看$input 的值:
eyJ1aWQiOiIxMTc5NTIwNDA1MDAwNDI1IiwidWluIjoiQe+8h++8hyDkuIDliIDYgiIsInRva2VuIjoiQDE3MUA5MUAxNjNAODJAMTExQDg4QDExMEAxMDNAMTA1QDE1NkAxMDRAMTEwQDEwNkAxMDhAMTUyQDE0OUA4NkA5NkA4N0AxNzJAMTU5QDE0OUA5MEAxMTRAODNAMTAyQDEwM0AxMDhAMTExQDEwNEAxMDVAMTAzQDEwMEAxMDVAMTAxQDk2QDEwMUAxMDJAMTA3QDEwNEAxMDJAODlAOTdAOTFAMTY5QDE1NkAxNjFAMTUyQDg2QDExMEAxMDRAMTAzQDEwM0A5M0A5MEAxNTVAODNAMTExQDg4QDEwM0AxMDZAODVAMTgwIn0=
真相呼之欲出了,这里已经得到了正确的原数据,那么只要进一步优化验证逻辑,含有特殊字符的登录就走得通了,代码如下
$input = \Util::get('data');
$data = json_decode(base64_decode($input), TRUE);
if ($this->do_verify($data) != 1){
//得到正确的登录数据
$input = rawurldecode(urlencode(urldecode($input)));
//将正确的登录数据再进行一次验证
$data = json_decode(base64_decode($input),TRUE);
if ($this->do_verify($data) != 1) {
$output = "登陆验证失败!";
return (json_encode($output));
}
}
至此,特殊字符造成的解析问题解决完毕。
【声明】:本博客仅为分享信息,不参与任何交易,也非中介,所有内容仅代表个人观点,均不作直接、间接、法定、约定的保证,读者购买风险自担。一旦您访问本博客,即表示您已经知晓并接受了此声明通告。
【关于安全】:任何 IDC 都有倒闭和跑路的可能,备份永远是最佳选择,服务器也是机器,不勤备份是对自己极不负责的表现,请保持良好的备份习惯。