站点安全之-php内容过滤,敏感词屏蔽,防注入,cookie加密

一个完整成熟的站点,内容过滤,防注入,加密存储和传输,敏感词屏蔽都是必不可少功能,关于加密传输有cookie加密存储和解密,客户端js加密到php解密和php文件之间的加密传输,涉及的内容较多,如有可能将另开一贴,本贴主要分享一下内容过滤和敏感词屏蔽的经验

一,内容过滤

说起过滤,大概马上会想到addslashes函数,这个常用于防止sql注入,但其实光这些还远远不够,我们要做的常常是将所有不相关的sql关键词全部替换掉,保证发上来的东西放进sql语句里是无法改变sql行为的,所以一般来说,安全起见这两点要求都需要达到

addslashes函数为了不重复转义,一般会需要判断下服务器是否开启了自动转义,然后再进行转义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function add_slashes($string, $force = 0)
{
    if(!get_magic_quotes_gpc() || $force)
    {
        if(is_array($string))
        {
            foreach($string as $key => $val)
            {
                $string[$key] = daddslashes($val, $force);
            }
        }
        else
        {
            $string = addslashes($string);
        }
    }
 
    return $string;
}

 为了让所有的sql关键词都安全存储,我们需要将它们转义,显示的时候再翻译回来

  

function sql_encode($str)
{
    if(empty($str)) return "";
    $str=trim($str);

    $str=str_replace("_","\_",$str);
    $str=str_replace("%","\%",$str);
    $str=str_replace(chr(39),"'",$str);
    $str=str_replace("‘","‘‘",$str);
    $str=str_replace("select","select",$str);
    $str=str_replace("join","join",$str);
    $str=str_replace("union","union",$str);
    $str=str_replace("where","where",$str);
    $str=str_replace("insert","insert",$str);
    $str=str_replace("delete","delete",$str);
    $str=str_replace("update","update",$str);
    $str=str_replace("like","like",$str);
    $str=str_replace("drop","drop",$str);
    $str=str_replace("create","create",$str);
    $str=str_replace("modify","modify",$str);
    $str=str_replace("rename","rename",$str);
    $str=str_replace("alter","alter",$str);
    $str=str_replace("cast","cas",$str);
    return $str;
}
function sql_decode($str)
{
    if(empty($str)) return "";

    $str=str_replace("'",chr(39),$str);
    $str=str_replace("‘‘","‘",$str);
    $str=str_replace("select","select",$str);
    $str=str_replace("join","join",$str);
    $str=str_replace("union","union",$str);
    $str=str_replace("where","where",$str);
    $str=str_replace("insert","insert",$str);
    $str=str_replace("delete","delete",$str);
    $str=str_replace("update","update",$str);
    $str=str_replace("like","like",$str);
    $str=str_replace("drop","drop",$str);
    $str=str_replace("create","create",$str);
    $str=str_replace("modify","modify",$str);
    $str=str_replace("rename","rename",$str);
    $str=str_replace("alter","alter",$str);
    $str=str_replace("cas","cast",$str);
    return $str;
}

  

有了以上的函数,对于sql语句涉及的内容就可以放心使用了,但这还不够,页面显示内容也需要过滤,页面内容过滤也分很多情况,比如标题是不允许html标签的,用户名是除了限制的数字字母,下划线外,其他都不允许使用的,而内容是可以有限制性的使用一些html标签,这就需要我们针对不同情况做不同的过滤处理

1,标题过滤

function filters_title($text)
{
    $text = trim($text);
    $text = str_replace("‘","",$text);
        $text = strip_tags($text);
        $text = stripslashes($text);
      return $text;
}

2,用户名过滤

function filters_username($string)
{
    $length=strlen($string);
    if($length<2 || $length>18){return false;}
    for($n=0; $n<$length; $n++)
    {
        $t = ord($string[$n]);
        if( (47<$t && $t<58) || (64<$t && $t<91) || (96<$t && $t<123) || $t==45 || $t==95 || $t>126){}
        else{return false;}
    }
    return true;
}

3,内容过滤

function filters_outcontent($str)
{
      $str = stripslashes($str);

      $str = preg_replace("/<div[^>]*?>/is","",$str);
      $str = str_replace("aaaaa","\r\n",$str);
      $str = str_replace("bbbbb","\n",$str);
      $str = str_replace("ccccc","\r",$str);
      $str = str_replace(‘\"‘,‘"‘,$str);

      $str = str_replace(array(‘<HTML‘, ‘<BODY‘, ‘<INPUT‘, ‘<SCRIPT‘, ‘<FORM‘, ‘<IFRAME‘), array(‘<html‘, ‘<body‘, ‘<input‘, ‘<script‘, ‘<form‘, ‘<iframe‘), $str);
      $str = str_replace(array(‘<html‘, ‘<body‘, ‘<input‘, ‘<script‘, ‘<form‘, ‘<iframe‘, ‘<textarea‘,‘</textarea>‘), array(‘&lt;html‘, ‘&lt;body‘, ‘&lt;input‘, ‘&lt;script‘, ‘&lt;form‘, ‘&lt;iframe‘, ‘&lt;textarea‘, ‘&lt;/textarea&gt;‘), $str);
      return $str;
}

可以根据以上思路添加自己的过滤场景,做到符合项目要求

 

二,敏感词屏蔽

敏感词屏蔽是现在国内站点必须使用的功能之一了,国情如此,辛辛苦苦做的站,因为这个被封,实在很不划算。根据应用场景,敏感词过滤可以分为替换和禁止两种,替换就是不提示,直接替换敏感词为**等,禁止一半而言需要提示用户,有敏感词,需要修改,例如在用户注册时候,替换一般用在文章中。

敏感词需要数据库支持,将敏感词存入数据库时候,可以按照分类,那些是要替换的,那些是要禁止的,按照固定格式存储,例如 abc=**,这是替换。cba={banned},这是禁止,或者在函数中制定第二个参数,replace或者banned来制定函数执行替换或者精致操作都可以,我采用的是第一种,如果有需要,大家可以根据原函数修改为第二种,最核心的其实很简单就是个正则查找的过程

function censor($string) {

    global $dblink, $tablepre;

    
    $censoraray = $banned = $banwords = array();
    $query = $dblink->query("SELECT * FROM censor WHERE var=‘censor‘ ");
    if($value = $dblink->fetch_array($query)) {        
        $censorstr = is_array($value)?$value[‘datavalue‘]:$value;
    } else {
        $censorstr = ‘‘;
    }
    
    if (strlen(trim($censorstr)) > 0) {  //有值就屏蔽
        $censorarr = explode("\n", $censorstr);//按输入时候的回车分割为数组
        
        foreach($censorarr as $censor) {
            $censor = trim($censor);
            if(empty($censor)) continue;
            list($find, $replace) = explode(‘=‘, $censor);
            $findword = $find;
            $find = preg_replace("/\\\{(\d+)\\\}/", ".{0,\\1}", preg_quote($find, ‘/‘));//匹配屏蔽语法中的"a{1}s{2}s"
            switch($replace) {
                case ‘{BANNED}‘:
                    $banwords[] = preg_replace("/\\\{(\d+)\\\}/", "*", preg_quote($findword, ‘/‘));
                    $banned[] = $find;
                    break;
                default:
                    $censoraray[‘filter‘][‘find‘][] = ‘/‘.$find.‘/i‘;
                    $censoraray[‘filter‘][‘replace‘][] = $replace;
                    break;
            }
        }
        
        
        if($banned) {
            $censoraray[‘banned‘] = ‘/(‘.implode(‘|‘, $banned).‘)/i‘;
            $censoraray[‘banword‘] = implode(‘, ‘, $banwords);
        }

        if($censoraray[‘banned‘] && preg_match($censoraray[‘banned‘], $string)) {
            return $censoraray[‘banned‘];//有敏感词汇不予显示
        } else {
            $string = empty($censoraray[‘filter‘]) ? $string :
                @preg_replace($censoraray[‘filter‘][‘find‘], $censoraray[‘filter‘][‘replace‘], $string);
        }

    }
    return $string;
}

因为我采用了第一种,所以需要将敏感词从数据库中取出后,做替换或者禁止的判断,其实核心代码很少,算是给大家一些思路吧

 

三,cookie加密

cookie加密存储是站点安全的很重要选择步骤,一些敏感的数据存储在cookie里方便了页面之间的传输,或者用于身份认定,来源判断,这些数据如果不加密,对有经验的人来说,很容易就会分析出一些站点的内部机制,或者将cookie用于跨站攻击。

设置cookie的语法很简单

setcookie(name,value,expire,path,domain,secure)

name         必需。规定 cookie 的名称。

value         必需。规定 cookie 的值。

expire         可选。规定 cookie 的有效期。

path         可选。规定 cookie 的服务器路径。

domain         可选。规定 cookie 的域名。

secure         可选。规定是否通过安全的 HTTPS 连接来传输 cookie。

设置cookie的函数可以这样写

function set_cookie($var, $value, $life = 0, $prefix = 1) 
{
    global $cookiepre, $cookiedomain, $cookiepath, $timestamp, $_SERVER;

    setcookie(($prefix ? $cookiepre : ‘‘).$var, $value, $life ? $timestamp + $life : 0, $cookiepath,$cookiedomain, $_SERVER[‘SERVER_PORT‘] == 443 ? 1 : 0);
}

解释一下

1,$prefix = 1 所以当($prefix ? $cookiepre : ‘‘).$var时候就会加上前缀,也可以选择不加
2,$lift=0 所以当$life ? $timestamp + $life : 0时候,如果传值了且不是0,就会设置有效期

这里最重要的是加密函数,我这里用的是下面这个

function authcode($string, $operation = ‘DECODE‘, $key = ‘‘, $expiry = 0)
{
    $ckey_length = 4;    
    //note 随机密钥长度 取值 0-32;
    //note 加入随机密钥,可以令密文无任何规律,即便是原文和密钥完全相同,加密结果也会每次不同,增大破解难度。
    //note 取值越大,密文变动规律越大,密文变化 = 16 的 $ckey_length 次方
    //note 当此值为 0 时,则不产生随机密钥

    $key = md5($key ? $key : UC_KEY);
    $keya = md5(substr($key, 0, 16));
    $keyb = md5(substr($key, 16, 16));
    $keyc = $ckey_length ? ($operation == ‘DECODE‘ ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : ‘‘;

    $cryptkey = $keya.md5($keya.$keyc);
    $key_length = strlen($cryptkey);

    $string = $operation == ‘DECODE‘ ? base64_decode(substr($string, $ckey_length)) : sprintf(‘%010d‘, $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
    $string_length = strlen($string);

    $result = ‘‘;
    $box = range(0, 255);

    $rndkey = array();
    for($i = 0; $i <= 255; $i++)
    {
        $rndkey[$i] = ord($cryptkey[$i % $key_length]);
    }

    for($j = $i = 0; $i < 256; $i++)
    {
        $j = ($j + $box[$i] + $rndkey[$i]) % 256;
        $tmp = $box[$i];
        $box[$i] = $box[$j];
        $box[$j] = $tmp;
    }

    for($a = $j = $i = 0; $i < $string_length; $i++)
    {
        $a = ($a + 1) % 256;
        $j = ($j + $box[$a]) % 256;
        $tmp = $box[$a];
        $box[$a] = $box[$j];
        $box[$j] = $tmp;
        $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
    }

    if($operation == ‘DECODE‘)
    {
        if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16))
        {
            return substr($result, 26);
        }
        else
        {
            return ‘‘;
        }
    }
    else
    {
        return $keyc.str_replace(‘=‘, ‘‘, base64_encode($result));
    }
}

第二个参数可设置为加密encode,或者解密decode。

这样一来,加密的设置cookie就可以这样写

    set_cookie(‘compound‘, authcode("$uid\t$uname\t$pw", ‘ENCODE‘, $key));

读取的时候,将cookie值读入变量,然后 $cookiearray=explode("\t", authcod($cookieval, ‘DECODE‘, $key))就可以读入到数组里了。

站点安全之-php内容过滤,敏感词屏蔽,防注入,cookie加密,古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。