PHP编程要注意的安全问题 | ||||||||||||||||
<?php nl2br(); // to addslashes(); stripslashes(); //对数据库操作时,转义特殊字符 chop(); //除去字符串右边空格 trim(); //除去字符串中所有空格 ltrim(); //除去字符串左边空格 htmlspecialchars(); //转换'$','"','<','>'为相应的html实体 htmlentities(); //转换所有html标记为相应的html实体 //两个函数在格式化带有英文字符的html代码的时候基本没啥问题,但是htmlentities对中文字符也不放过,这样得出来的结果是中文字符部分变为一堆乱码。 array explode(string separator, string str); //分割字符串 string implode(string separator, array arr); //连接字符串 strtoupper(); strtolower(); //转换大小写 ucfirst(); //只转换第一个字符为大写 ucwords(); //转换每个words的第一个字母为大写 mysql_real_escape_string()//本函数将unescaped_string 中的特殊字符转义,并计及连接的当前字符集,因此可以安全用于。注: () 并不转义% 和_。 ?> //防止sql注入 在PHP编码的时候,一些比较基本的安全问题 1. 注意初始化你的变量 2.防止SQL Injection (sql注射) 我们知道Web上提交数据有两种方式,一种是get、一种是post,那么很多常见的sql注射就是从get方式入手的,而且注射的语句里面一定是包含一些SQL语句的,因为没有SQL语句,那么如何进行,sql语 句有四大句:select 、update、delete、insert,那么我们如果在我们提交的数据中进行过滤是不是能够避免这些问题呢? 于是我们使用正则就构建如下函数: (1)把select,insert,update,delete, union, into, load_file, outfile /*, ./ , ../ , ' 等等危险的参数字符串全部过滤掉,处理掉' select * from ***的情况 <?php /* 函数名称:inject_check() 函数作用:检测提交的值是不是含有SQL注射的字符,防止注射,保护服务器安全 参数:$sql_str: 提交的变量 返回值:返回检测结果,ture or false 函数作者:heiyeluren */ function inject_check($sql_str) { return eregi('select|insert|update|delete|'|/*|*|../|./|union|into|loa d_file|outfile', $sql_str); // 进行过滤 } ?> (2)处理掉a.php?id=1asdfasdfasdf <?php /* 函数名称:verify_id() 函数作用:校验提交的ID类值是否合法 参数:$id: 提交的ID值 返回值:返回处理后的ID 函数作者:heiyeluren */ function verify_id($id=null) { if (!$id) { exit('没有提交参数!'); } // 是否为空判断 elseif (inject_check($id)) { exit('提交的参数非法!'); } // 注射判断 elseif (!is_numeric($id)) { exit('提交的参数非法!'); } // 数字判断 $id = intval($id); // 整型化 return $id; } ?> (3)去除' _ ', ' % ',这些字符特殊意义字符 <?php /* 函数名称:str_check() 函数作用:对提交的字符串进行过滤 参数:$var: 要处理的字符串 返回值:返回过滤后的字符串 函数作者:heiyeluren */ function str_check( $str ) { if (!get_magic_quotes_gpc()) // 判断magic_quotes_gpc是否打开 { $str = addslashes($str); // 进行过滤 } $str = str_replace("_", "\_", $str); // 把'_'过滤掉 $str = str_replace("%", "\%", $str); // 把' % '过滤掉 return $str; } ?> (4)对编辑内容进行过滤和转换 <?php /* 函数名称:post_check() 函数作用:对提交的编辑内容进行处理 参数:$post: 要提交的内容 返回值:$post: 返回过滤后的内容 函数作者:heiyeluren */ function post_check($post) { if (!get_magic_quotes_gpc()) // 判断magic_quotes_gpc是否为打开 { $post = addslashes($post); // 进行magic_quotes_gpc没有打开的情况对提交数据的过滤 } $post = str_replace("_", "\_", $post); // 把'_'过滤掉 $post = str_replace("%", "\%", $post); // 把' % '过滤掉 $post = nl2br($post); // 回车转换 $post= htmlspecialchars($post); // html标记转换 return $post; } ?> 综合来说即2个,1. 初始化你的变量 2. 一定记得要过滤你的变量 //服务器端用mysql_real_escape_string 清洁客户端数据 在服务器端清洁客户端数据是每个程序员经常要做的工作,虽然我们通常会在客户端添加Javascript 验证,但是,恶意用户很容易自己构造FORM 提交数据以绕过客户端验证,另外,在客户端禁用Javascript 时验证同样不能起到作用。因此,服务器端清洁数据必不可少,本文介绍的是用mysql_real_escape_string 清洁数据的方法,经过清洁的数据可以直接插入到数据库中。 由于mysql_real_escape_string 需要MySQL 数据库连接,因此,在调用mysql_real_escape_string 之前,必须连接上MySQL 数据库。 PHP: <?php // 说明:用array_map() 调用mysql_real_escape_string 清理数组 // 整理: function mysqlClean($data) { return (is_array($data))?array_map('mysqlClean', $data):mysql_real_escape_string($data); } ?> 调用方法 PHP: <?php $conn = mysql_connect('localhost', 'user', 'pass'); $_POST = mysqlClean($_POST); ?> 经过清洁的数据可以直接插入数据库。 注意!mysql_real_escape_string 必须在(PHP 4 >= 4.3.0, PHP 5)的情况下才能使用。否则只能用mysql_escape_string ,两者的区别是: mysql_real_escape_string 考虑到连接的当前字符集,而 mysql_escape_string 不考虑。 由于mysql_real_escape_string 需要MySQL 数据库连接,因此,在调用mysql_real_escape_string 之前,必须连接上MySQL 数据库。 在知道数据类型为字符串时,我们可以在清洁数据的同时限制字符串长度。此方法来自David Lane, Hugh E. Williams《Web Database Application with PHP and MySQL 》(O'Reilly,May 2004) PHP: <?php // 说明:用mysql_real_escape_string 清洁并限制字符长度 // 整理: function mysqlClean($array, $index, $maxlength) { if (isset($array[$index])) { $input = substr($array["{$index}"], 0, $maxlength); $input = mysql_real_escape_string($input); return ($input); } return NULL; } ?> 调用方法: PHP: <?php $conn = mysql_connect('localhost', 'user', 'pass'); if(isset($_POST['username'])) { $_POST['username'] = mysqlClean($_POST, 'username', 20); echo $_POST['username']; } ?> 将$_POST 数组中的'username' 清洁并截取前20位字符。 //关于sql注入 //用户发布的html,过滤危险代码 function uh($str) { $farr = array( "/s+/", //过滤多余的空白 "/<(/?)(scripti?framestylehtmlbodytitlelinkmeta?\%)([^>]*?)>/ isU", //过滤<script 等可能引入恶意内容或恶意改变显示布局的代码,如果不需要插入flash等,还可以加入<object的过滤 ); $tarr = array( " ", "<>", //如果要直接清除不安全的标签,这里可以留空 "", ); $str = preg_replace( $farr,$tarr,$str); return $str; } SFun{var $Fun="now()";function SFun($Date=""){if($Date!="")$this->Fun=$Date;}} MySqlDB { var $dbConn; var $dbHost; var $dbUID; var $dbPWD; var $dbName; var $dbEncode; var $IsOp; MySqlDB($Host='localhost',$UID='root',$Pwd='',$Name='',$Enc ode='utf8') { $this->dbHost = $Host; $this->dbUID = $UID; $this->dbPWD = $Pwd; $this->dbName = $Name; $this->dbEncode = $Encode; $this->IsOp=false; } //打开数据库 Open() { if (!$this->dbConn) { @$this->dbConn = mysql_connect($this->dbHost, $this->dbUID, $this->dbPWD) or die("数据库连接错误!..."); } mysql_query("SET NAMES '" . $this->dbEncode . "'"); mysql_select_db($this->dbName); $this->IsOp=true; } //关闭数据库 Close() { if ($this->dbConn&&$this->IsOp) { mysql_close($this->dbConn); $this->IsOp=false; } } htmlrsp($str) { $str=str_replace("<","<",$str); $str=str_replace(">",">",$str); return $str; } //过滤XSS危险脚本 RemoveXSS($val) { if(strpos($val,"<")===false)return $val; $val = preg_replace('/([x00-x08][x0b-x0c][x0e-x20])/', '', $val); $search = 'abcdefghijklmnopqrstuvwxyz'; $search .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; $search .= '1234567890!@#$%^&*()'; $search .= '~`";:?+/={}[]-_|''; for ($i = 0; $i < strlen($search); $i++) { $val = preg_replace('/(&#[x|X]0{0,8}'.dechex(ord($search[$i])).';?)/i', $search[$i], $val); // with a ; $val = preg_replace('/(?{0,8}'.ord($search[$i]).';?)/', $search[$i], $val); // with a ; } $ra1 = array('javascript', 'vbscript', 'expression', 'applet'); $ra2 = array('onabort', 'onactivate', 'onafterprint', 'onafterupdate', 'onbeforeactivate', 'onbeforecopy', 'onbeforecut', 'onbeforedeactivate', 'onbeforeeditfocus', 'onbeforepaste', 'onbeforeprint', 'onbeforeunload', 'onbeforeupdate', 'onblur', 'onbounce', 'oncellchange', 'onchange', 'onclick', 'oncontextmenu', 'oncontrolselect', 'oncopy', 'oncut', 'ondataavailable', 'ondatasetchanged', 'ondatasetcomplete', 'ondblclick', 'ondeactivate', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onerror', 'onerrorupdate', 'onfilterchange', 'onfinish', 'onfocus', 'onfocusin', 'onfocusout', 'onhelp', 'onkeydown', 'onkeypress', 'onkeyup', 'onlayoutcomplete', 'onload', 'onlosecapture', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onmove', 'onmoveend', 'onmovestart', 'onpaste', 'onpropertychange', 'onreadystatechange', 'onreset', 'onresize', 'onresizeend', 'onresizestart', 'onrowenter', 'onrowexit', 'onrowsdelete', 'onrowsinserted', 'onscroll', 'onselect', 'onselectionchange', 'onselectstart', 'onstart', 'onstop', 'onsubmit', 'onunload'); $ra = array_merge($ra1, $ra2); $val=preg_replace("'<script[^>]*?>.*?</script>'si","",$val); $val=preg_replace("'<style[^>]*?>.*?</style>'si","",$val); $val=preg_replace("/<(script|iframe|expression|applet|meta|xml| blink|style|frame|frameset|ilayer|layer|bgsound|title|base|link )(|[^>]+)>/i","",$val); $val=preg_replace("/</(script|iframe|expression|applet|meta|x ml|blink|style|frame|frameset|ilayer|layer|bgsound|title|base)> /i","",$val); $newval=""; $idx=0; $edx=0; do { $idx=strpos($val,"<",$edx); if($idx!==false) { if($idx>$edx){ $str=substr($val,$edx,$idx-$edx); $newval.=$this->htmlrsp($str); } $edx=strpos($val,">",$idx); if($edx!==false&&$edx>$idx) { $edx++; $tag=substr($val,$idx,$edx-$idx); $ridx=strrpos($tag,"<",1); if($ridx!==false){ $str=substr($val,$idx,$ridx); $newval.=$this->htmlrsp($str); $idx=$idx+$ridx; $tag=substr($val,$idx,$edx-$idx); } if(stripos($tag,"on")===false) {$newval.=$tag;} else { for($j=0;$j<count($ra1);$j++){if(stripos($tag,$ra1[$j])!= =false){$tag=str_ireplace($ra1[$j],"",$tag);}} for($j=0;$j<count($ra2);$j++){ if(stripos($tag,$ra2[$j])!==false){ $tag=preg_replace('/'.$ra2[$j].'="[^"]+"/i',"",$tag); $tag=preg_replace("/".$ra2[$j]."='[^']+'/i","",$tag); $tag=preg_replace("/".$ra2[$j]."=[^ ]+>/i",">",$tag); $tag=preg_replace("/".$ra2[$j]."=[^ ]+ /i","",$tag); $tag=str_ireplace($ra2[$j],"",$tag); }} $newval.=$tag; } } else { $str=substr($val,$idx); $newval.=$this->htmlrsp($str); } } else { $str=substr($val,$edx); $newval.=$this->htmlrsp($str); } }while($idx!==false&&$edx!==false); return $newval; } //执行SQL语句 ExeSql($sql) { mysql_query($sql, $this->dbConn) or die("执行SQL语句错误...".$sql); } HGexecute($SqlArr) { mysql_query("SET AUTOCOMMIT=0");//设置为不自动提交,因为MYSQL默认立即执行 mysql_query("BEGIN");//开始事务定义 for($i=0;$i<count($SqlArr);$i++) { $sql=$SqlArr[$i]; if(!mysql_query($sql, $this->dbConn)) { mysql_query("ROLLBACK");//判断执行失败回滚 mysql_query("SET AUTOCOMMIT=1"); return false; } } mysql_query("SET AUTOCOMMIT=1"); mysql_query("COMMIT");//执行事务 return true; } //取SQL数据 GetData($sql) { $result = mysql_query($sql, $this->dbConn) or die("查询 SQL语句错误...".$sql); $records=array(); //while($record = mysql_fetch_array($result)) while($record = mysql_fetch_object($result)) { $records[] = $record; } return $records; } _T($str){ $str=$this->RemoveXSS($str); $str=str_replace('','',$str); $str=str_replace(''',''',$str); //$str=str_replace('"','"',$str); return $str;} GetOne($sql) { $records=$this->GetData($sql); return $records[0]; } Like($str) { $str=$this->_T($str); $str=str_replace('%','\%',$str); return $str; } //插入记录 Add($Tb,$A,$IsId=false) { $SqlKey=array(); $SqlArr=array(); foreach ($A as $key=>$value) { $SqlKey[]="`".$key."`"; if($value===NULL) $SqlArr[]="NULL"; else if(gettype($value)=="integer"||gettype($value)=="boolean"||gett ype($value)=="double"||gettype($value)=="float") $SqlArr[]=$value; else if(gettype($value)=="object") $SqlArr[]=$value->Fun; else $SqlArr[]="'".$this->_T($value)."'"; } $Sql="INSERT INTO ".$Tb."(".join(",",$SqlKey).") VALUES (".join(",",$SqlArr).")"; mysql_query($Sql, $this->dbConn) or die("执行SQL语句错误...".$Sql); if($IsId) return mysql_insert_id($this->dbConn); else return 0; } Update($Tb,$A,$Id) { $Id=intval($Id); $SqlArr=array(); foreach ($A as $key=>$value) { if($value===NULL) $SqlArr[]="`".$key."`=NULL"; else if(gettype($value)=="integer"||gettype($value)=="boolean"||gett ype($value)=="double"||gettype($value)=="float") $SqlArr[]="`".$key."`=".$value; else if(gettype($value)=="object") $SqlArr[]="`".$key."`=".$value->Fun; else $SqlArr[]="`".$key."`='".$this->_T($value)."'"; } $Sql="update ".$Tb." set ".join(",",$SqlArr)." where id=".$Id; mysql_query($Sql, $this->dbConn) or die("执行SQL语句错误...".$Sql); } Del($Tb,$Id) { $Id=intval($Id); $Sql="delete from ".$Tb." where id=".$Id; mysql_query($Sql, $this->dbConn) or die("执行SQL语句错误...".$Sql); } }
|