Javascript和PHP base64加密解密实现(支持中文)


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加密的数据稍作处理,把空格替换成+,否则会有乱码。

加密后的字符串虽然会比原来的大一些,但是兼容性和完整性更佳。

所以目前使用的就是这个方案。

 

参考地址:

  1. hi-base64 · github

  2. PHP的几个常用加密函数