1 问题
最近遇到一个问题,前端提交的HTML模板一直无法保存,但是前端的jQuery显示已经提交。
后来一步步调试才知道,表单提交到后台时,有一层封装好的PHP基类,对POST/GET
数据进行了过滤。
如果符合过滤条件,则直接exit()
退出错误,所以肯定没办法提交数据。
如下是POST
拦截条件:
class Safety{ private static $postFilter="\\b(and|or)\\b.{1,6}?(=|>|<|\\bin\\b|\\blike\\b)|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)"; // GET、COOKIE... private static function checkAttack($value, $condition){ if(is_array($value)){ $value = implode($value); } if (preg_match("/" . $condition . "/is", $value) == 1){ exit(); } } public static function stopAttach(){ foreach($_POST as $value){ self::checkAttack($value, self::$postFilter); } // GET、COOKIE... } }
这条语句会侦测POST
中的关键字and
、or
、in
、/* */
注释、<script
标签和一些数据库关键字等等。
如果POST
内容包含这些内容,会直接退出程序。
那怎么办,公共基类类不好改也是不能改的。
2 提示法
后来想到的第一个办法是,将特殊字符转义。
再前端根据后台的正则表达式,在前端建一个同样的判断,如果含有过滤字符,提示,更改后才能提交。
这里有两个难点。
第一是JS没有内置的特殊字符转义函数,得自己些函数,办法:JQuery Post转义提交HTML模板。
第二个是PHP的正则表达和JS的还不太一样,主要提现在点字符上,后来也解决:PHP和JavaScript正则匹配所有字符(包括换行符)的差异。
提交之前再用encodeURIComponent()
转码一遍,再提交。
这样就可以提交了。
只是,这样一些特殊的字还是无法提交,比如update...set
、/* */
。
3 base64加解密
base64是通用的加解密方法,JavaScript也有现成的库可以使用,PHP更是有现成函数可用。
解决方法如下。
首先,前端引用base64加密库,推荐用支持中文的库:https://github.com/emn178/hi-base64
数据提交之前,用base64的方法加密:
var html_source = base64.encode(html_source)
这样不论什么字符,都可以提交了,都是。
然后,在PHP读取数据时,用base64_decode() 方法就可以解密了。
$html_source = str_replace(' ', '+', $html_source); $html_source = base64_decode($html_source);
说明:这里需要把JavaScript加密的数据稍作处理,把空格替换成+,否则会有乱码。
加密后的字符串虽然会比原来的大一些,但是兼容性和完整性更佳。
所以目前使用的就是这个方案。
参考地址:
-
hi-base64 · github
- PHP的几个常用加密函数