PHP数据对象(PHP Data Object PDO)框架最常用的数据库接口之一,通过使用问好占位符来支持参数化语句
<?php
$dbh = new PDO("mysql:host=localhost;dbname=demo","user","pass");
$dbh -> exec("set names 'GBK');
$sql = "select * from test where name= ? and password = ?";
$stmt = $stmt->execute(arry($name,$pass));
?>
使用PDO访问MySQL数据库时,真正的real prepared statements 默认情况下是不使用的。为了解决这个问题,你必须禁用 prepared statements的仿真效果,应该加上
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
setAttribute()这一行是强制性的,它会告诉 PDO 禁用模拟预处理语句,并使用 real parepared statements 。这可以确保SQL语句和相应的值在传递到mysql服务器之前是不会被PHP解析的(禁止了所有可能的恶意SQL注入攻击)。
虽然你可以配置文件中设置字符集的属性(charset=utf8),但是需要格外注意的是,老版本的 PHP( < 5.3.6)在DSN中是忽略字符参数的。
此处代码因为使用了gbk编码所以可以进行宽字节注入
PDO为什么能防止sql注入?
当调用 prepare() 时,查询语句已经发送给了数据库服务器,此时只有占位符 ? 发送过去,没有用户提交的数据;当调用到 execute()时,用户提交过来的值才会传送给数据库,他们是分开传送的,两者独立的,SQL攻击者没有一点机会
下面是安全的代码
<?php
$dbh = new PDO("mysql:host=localhost;dbname=demo","user","pass");
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES,false);
$dbh->exec("set names 'utf8'");
$sql = "select * from test where name = ? and password = ?";
$stmt = $dbh->prepare($sql);
$exeres = $stmt->execute(array($name,$pass));
?>
以下情况不能用PDO防止sql注入
1,你不能让占位符 ? 代替一组值
2,你不能让占位符?代替数据表名或列名
3,你不能让占位符 ? 代替任何其他SQL语法
注意 : 不要忽略X-Forwarded-For,Header,Refferer参数 包括从数据库取出时也要经过安全函数过滤,因为这些攻击者完全可以通过抓包修改这些参数,一切输入甚至输出都可能是有害的