常见的SQL注入问题:
数据库查询参数的类型转换处理
1.转义字符处理不当
空谈很便宜,给我看代码。
废话不多说了,直接上代码吧!
// 构造动态SQL语句
$sql = "select * from tbl where field = '$_GET['input']'";
// 执行SQL语句
$res = mysql_query($sql);
测试:
下面的URL后面加单引号,会报数据库错误
2. 类型处理不当
// 构造动态SQL语句
$sql = "select * from tbl where field = $_GET['user_id']";
// 执行SQL语句
$res = mysql_query($sql);
Mysql有一个内置命令可以读取文件
Union all select load_file('/etc/passwd')--
select * from tbl where userid = 1 union all select load_file('etc/passwd')--
该命令将获取数据库管理员的密码。
方法:
客户端发送的数据在查询之前需要转换成某种类型。
$user_id = (int)$_GET['user_id'];
"select * from tbl where userid = {$user_id}";
3、查询组织不当
user.php?table=user&
4.错误处理不当
这会将网站的错误信息暴露给用户,这是非常危险的。
// 构造动态查询语句
$getid = "select * from tbl where userid > 1";
// 执行SQL语句
$res = mysql_query($getid) or die('
'.mysql_error().'
');
5. 多次提交处理不当
// 参数是字符串吗?
if(($_GET["参数"])){}
当数据存储到数据库中时,单引号、双引号和反斜杠将转换为实体。
如果在向数据库输入数据时没有过滤掉'"",数据库可能会报错或者出现注入问题。
首先,使用()将字符串转换为实体并将其存储到数据库中。 然后,当从数据库中读取它时,ode() 将其转换为 HTML 标签。
() 函数将一些预定义的字符转换为 HTML 实体。
函数原型:
htmlspecialchars(string,quotestyle,character-set)
预定义的字符有:
& (和号) 成为 &
” (双引号) 成为 "
‘ (单引号) 成为 '
< (小于) 成为 <
> (大于) 成为 >
ode() 函数将一些预定义的 HTML 实体转换为字符(反之亦然)。
函数原型:
htmlspecialchars_decode(string,quotestyle)
2. 防止XSS攻击
什么是 XSS 攻击?
与上面的SQL注入不同,XSS攻击是合法的字符串。 通过()方法具体化后,可以保存到数据库中。 但是,当访问包含该字符串的内容页面时,就会出现问题。 例如,如果字符串中存在框架代码,则原始页面将被篡改。
例如,如果你写了一本留言簿,有人留言,
除了通过正常渠道输入XSS攻击字符外,还可以通过修改请求来绕过验证,达到XSS攻击的目的,如下图所示:
了解了XSS攻击的原理和危害后,防范起来就不难了。 下面是一个简单的 PHP 函数来防止 XSS 攻击:
除了通过正常渠道输入XSS攻击字符外,还可以通过修改请求来绕过验证,达到XSS攻击的目的。
了解了XSS攻击的原理和危害后,防范起来就不难了。 下面是一个简单的 PHP 函数来防止 XSS 攻击:
/**
* @blog http://www.digtime.cn
* @param $string
* @param $low 安全别级低
*/
function clean_xss(&$string, $low = False)
{
if (! is_array ( $string ))
{
$string = trim ( $string );
$string = strip_tags ( $string );
$string = htmlspecialchars ( $string );
if ($low)
{
return True;
}
$string = str_replace ( array ('"', "\\", "'", "/", "..", "../", "./", "//" ), '', $string );
$no = '/%0[0-8bcef]/';
$string = preg_replace ( $no, '', $string );
$no = '/%1[0-9a-f]/';
$string = preg_replace ( $no, '', $string );
$no = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S';
$string = preg_replace ( $no, '', $string );
return True;
}
$keys = array_keys ( $string );
foreach ( $keys as $key )
{
clean_xss ( $string [$key] );
}
}
//just a test
$str = 'codetc.com';
clean_xss($str); //如果你把这个注释掉,你就知道xss攻击的厉害了
echo $str;
?>
避免 XSS:
1.向用户开放的编辑器应尽量过滤掉危险代码
如果是HTML编辑器,一般的做法是保留大部分代码,过滤掉一些有潜在危险的代码,比如等等。
3. PHP MySQL 准备好的语句
准备好的语句对于防止 MySQL 注入非常有用。
准备好的语句和绑定参数
准备语句用于执行多个相同的SQL语句,执行效率更高。
准备好的语句的工作原理如下:
预处理:创建SQL语句模板并将其发送到数据库。
保留值用参数“?”标记。
例如:
INSERT
INTO MyGuests (firstname, lastname, email) VALUES(?, ?, ?)
数据库对SQL语句模板进行解析、编译、查询优化,并存储结果,但不输出。
实施:
最后,数据库执行该语句,将应用程序绑定的值传递给参数(“?”标记)。
如果参数值不同,应用程序可以多次执行该语句。
与直接执行SQL语句相比,准备好的语句有两个主要优点:
准备好的语句大大减少了解析时间,并且只执行一次查询(尽管该语句被执行了多次)。
绑定参数可以减少服务器带宽,因为您只需发送查询参数而不是整个语句。
准备好的语句对于SQL注入非常有用,因为参数值是使用不同的协议发送的,保证了数据的合法性。
PDO预处理机制
预处理可以通过多种方式实现:这意味着有多种方式来绑定数据以执行。
准备好的语句中的变量
使用数组指定预处理变量
1.准备准备好的语句(发送到服务器让服务器准备准备好的语句)
PDOStatement PDO::prepare:类似exec将一条SQL语句发送给Mysql服务器
//PDO::prepare 能够自动的准备一个预处理语句,用户需要准备的只是预处理所要执行的语句
//需求:往学生表里循环插入10条记录
//PDO的预处理能够自动的将对应的以:开始的变量给记录下来,实际发送给服务器的是“?”
$sql1 = "insert into pro_student values(null,:s_name,:s_num,:s_gender,:s_age,:c_id)";
2. 发送准备好的报表
$stmt = $pdo->prepare($sql1);
3. 将数据绑定到预处理
$arr = array(
':s_name' => '房祖名',
':s_num' => 'itcast0013',
':s_gender' => 0,
':s_age' => 28,
':c_id' => 2
);
4.执行预处理:将要操作的数据发送到语句中,然后执行语句
PDOStatement::execute([$array]):数组用来传递对应的参数
$stmt->execute($arr); //执行预处理
PDO预处理原理
PDO防止SQL注入的机制类似于使用ring进行转义。 PDO有两种转义机制;
第一种是本地转义,即使用单字节字符集(PHP < 5.3.6)转义(单字节和多字节)对输入进行转义; 然而,这种逃生方式却存在一些隐患。
主要隐患有:
当PHP版本低于5.3.6时,本地转义只能转换单字节字符集。 大于5.3.6的版本将根据PDO连接中的指定进行转义。
第二种方式是PDO。 首先将SQL语句模板发送到Mysql,然后将绑定的字符变量发送到Mysql。 这里的转义是在Mysql中完成的,根据连接PDO时指定的编码格式进行转换。
这种转义方式更加健壮,在重复查询的业务场景中还可以通过复用模板来提高程序性能。 如果要设置MySQL转义,必须先执行:
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
原链接方法:
// PDO的使用
// http://blog.csdn.net/qq635785620/article/details/11284591
$dbh = new PDO('mysql:host=127.0.0.1:3306;dbname=mysql_safe', 'root', '518666');
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbh->exec('set names utf8');
$title = "我们的爱情";
$content = '你是/谁啊,大几\都"老梁"做做&>women没' . " 测试打印号'我是单引号'哈哈";
$user_id = 174742;
$add_time = date("Y-m-d H:i:s");
$insert_sql = "insert into post_tbl (title, content, user_id, add_time) values (:x_title, :x_content, :x_user_id, :x_add_time)";
$stmt = $dbh->prepare($insert_sql);
$stmt->execute(array('x_title'=>$title,':x_content'=> $content, ':x_user_id' => $user_id, ':x_add_time' => $add_time));
echo $dbh->lastinsertid();
可以看到,这次PHP将SQL模板和变量发送给MySQL两次,MySQL完成了变量转义处理。 由于变量和SQL模板发送了两次,因此不存在SQL注入问题,但是需要在DSN中指定属性,例如:
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'root');
例子:
/**
* 插入用户的Token
*/
function photo_save_token($user_id, $token)
{
// 参数判断
$user_id = (int)$user_id;
$token = trim($token);
if(empty($token) || empty($user_id)) return false;
$sql = "replace into token_db.app_token_tbl
( user_id, token, t_date, last_open_time)
values
( :x_user_id, :x_token, :x_t_date, :x_last_open_time)";
sqlSetParam($sql,"x_user_id",$user_id);
sqlSetParam($sql,"x_token",$token);
sqlSetParam($sql,"x_t_date",date('Y-m-d H:i:s'));
sqlSetParam($sql,"x_last_open_time", time());
return mysql_query($sql);
}
总结:
当()被调用时,查询语句已经被发送到数据库服务器。 此时,只有占位符? 已发送,且无用户提交的数据;
当()被调用时,用户提交的值将被传输到数据库。 它们是分开独立传输的,SQL攻击者没有机会。
概括
①. 对于SQL注入,可以使用()或()方法。 如果连接MySQL,可以使用ring(),并在php.ini中配置自动转义扩展。
PHP环境中启用自动转义,检查PHP.INI。
当= on时,会自动转义(默认为on),在程序中可以用()查看其状态
程序是:
if (get_magic_quotes_gpc()==1){
$name=stripcslashes($_POST["name"]);
}else{
$name=$_POST["name"];
}
②. 关于xss攻击,可以写方法去除、框架等代码:
直接使用该函数即可,既保证安全又可以使用大部分HTML代码
function editor_safe_replace($content){ $content = trim($content); $tags = array( "''is", "']*?>.*?'is", "''is", "']*?>.*?'is", "']*?>.*? 'is", "']*?>'is", "']*?>'is", ); // 1.先过滤掉含有xss攻击的代码 $content = preg_replace($tags, "", $content); // strip_tags过滤掉全部HTML标签(script,iframe,head,a 等标签)和上边的正则方法类似 // $content = strip_tags($content); // 2.入库时,防止sql注入,转为HTML实体保存在数据库,单双引号都转 $content = htmlspecialchars($content, ENT_QUOTES); // 3.替换反斜杠 $content = preg_replace("/\\\/", "\", $content); // 4.替换斜杠 $content = preg_replace("/\//", "/", $content); return $content;}
因此,为了PHP的安全,需要对用户提交的数据进行过滤和验证,即先防止SQL注入,然后再进行XSS过滤。 这些都需要一起做,而且双手一定要有力,否则,你的网站将会面临很大的安全风险。
扫一扫在手机端查看
我们凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求,请立即点击咨询我们或拨打咨询热线: 13761152229,我们会详细为你一一解答你心中的疑难。