之前一直用得好好的系统今天出现了一点小状况, 在http请求时抛出了久违的签名错误,这里的签名是自己定义的规则,客户端与服务端在交互时会对参数进行一定规则排序加密后的值当做签名以防篡改.
跟踪了服务端日志跟客户端日志后发现最终排序后的签名串是一致的,但签名出来的结果不一样,那只能是在排序后进行编码签名时出现了值不一致的情况
用户输入的值是"select*from'tab"
js encodeURIComponent后的值依旧是: select*from'tab
java URLEncoder编码后的值是: select*from%27tab
也就是对于"'"这个字符,js没有将其编码,而java却将其编码成%27
继续查资料, 发现javascript跟java在进行编码时遵循的规范不一样,
javascript遵循的是:
RFC3986
java的为了在各个系统间做兼容,处理了特殊符号,处理方式如下
1.字符"a"-"z","A"-"Z","0"-"9",".","-","*",和"_" 都不会被编码;2.将空格转换为加号 (+) ;3.将非文本内容转换成"%xy"的形式,xy是两位16进制的数值;4.在每个 name=value 对之间放置 & 符号
最终将js和java的ascii 1-127的字符循环编码匹配不同,最终发现有以下几值不同
ascii java js
+ %20
! %21 !
' %27 '
( %28 (
) %29 )
~ %7E ~
! %21 !
' %27 '
( %28 (
) %29 )
~ %7E ~
然后在js 编码后对特殊字符做个处理
s = s.replace(/%20/gi, "+").replace(/(!)|(')|(\()|(\))|(\~)/gi, function(item) {
return "%" + item.charCodeAt(0).toString(16).toLocaleUpperCase();
});
return "%" + item.charCodeAt(0).toString(16).toLocaleUpperCase();
});
问题解决