站点安全之-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(‘<html‘, ‘<body‘, ‘<input‘, ‘<script‘, ‘<form‘, ‘<iframe‘, ‘<textarea‘, ‘</textarea>‘), $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))就可以读入到数组里了。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。