PHP SQL防注入

参考资料:

PHP中防止SQL注入的方法
php操作mysql防止sql注入(合集)
PDO防注入原理分析以及使用PDO的注意事项
php SQL 防注入的一些经验
如何在PHP中防止SQL注入?
PHP安全编程:防止SQL注入
addslashes与mysql_real_escape_string的区别
How can I prevent SQL injection in PHP?

什么是SQL注入?

Sql注入,是通过程序员编程时的疏忽,经过查找sql注入的位置、判断服务器类型和后台数据类型、针对不同类型的服务器以及数据库进行攻击,实现无账号登录,甚至篡改数据库。

解决方法

1.魔术函数 addslashes

Addslashes()是与stripslashes()是功能相反的函数。
Addslashes()用于给变量中的’ ” 与null添加反斜杠\,用于避免传入sql语句的参数格式错误,同时如果有人注入子查询,通过加可以将参数解释为内容,而非执行语句,避免被mysql执行。
Addslashes()只在PHP中执行,\是不会写入mysql中的。
当 PHP 指令 magic_quotes_sybase 被设置成 on 时,意味着开启addslashes()。
在PHP5.4.0版本之前,magic_quotes_sybase 默认开启。
可以通过函数get_magic_quotes_gpc()判断magic_quotes_gpc是否开启。

if (!get_magic_quotes_gpc()) {
		$lastname = addslashes($_POST[‘lastname’]);
	} else {
		$lastname = $_POST[‘lastname’];
	}

但是addslashes()并不会检测字符集,比如如果是gbk编码,可能会将某些字符解释成两个ASCII字节,造成新的注入风险。Utf没有这个问题。

2.mysql_real_escape_string

mysql_real_escape_string()与addslashes()相比,不仅会将’ " NOL(ascii的0)转义,还会把r n进行转义。同时会检测数据编码。
mysql_real_escape_string()使用时需要进行数据库的连接,因为要获取数据库的字符集,如果当前不存在连接,会使用上一次连接。
这个函数在PHP5.5.0不被推荐使用,PHP7.0被废弃

3.预处理 (Prepared Statements) ---- mysqli:prepare()

Mysqli的参数化绑定

$mysqli = new mysqli('localhost', 'my_user', 'my_password', 'world');
$stmt = $mysqli->prepare("INSERT INTO CountryLanguage VALUES (?, ?, ?, ?)");
$code = 'DEU';
$language = 'Bavarian';
$official = "F";
$percent = 11.2;
$stmt->bind_param('sssd', $code, $language, $official, $percent);

在这里插入图片描述

mysqli=newmysqli("example.com","user","password","database");
stmt = mysqli−>prepare("SELECT id,label FROM test WHERE id=?");
stmt->bind_param(1, city);stmt->execute();
res=stmt->get_result();
row=res->fetch_assoc();

Mysqli预处理查询是将一步查询分作两步操作
A 写sql语句,用?占位,替代sql中的变量
B 替换变量
C 执行SQL语句
D 得到一个二进制结果集,从二进制结果中取出php结果集
E 遍历结果集

4.预处理 (Prepared Statements) ---- PDO

使用PDO参数化绑定
类似于mysqli也是分两步预处理

$pdo = new PDO("mysql:host=192.168.0.1;dbname=test;charset=utf8","root");
$st = $pdo->prepare("select * from info where id =? and name = ?");
 
$id = 21;
$name = 'zhangsan';
$st->bindParam(1,$id);
$st->bindParam(2,$name);
 
$st->execute();
$st->fetchAll();

PHP将sql模板和变量两次发送给mysql,由mysql进行变量的转义处理。
PHP版本不同,有不同的处理方式。
PHP版本小于5.3.6,需要关闭PHP使用本地模拟prepare
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
PHP版本为5.3.6+的,请在在PDO的DSN中指定charset属性
因为PHP5.3.6版本之前,并不支持PDO的DSN charset设定

总结

控制注入主要分三个方面:
1.做参数合法性,特殊字符,长度校验
2.数据库中严格设定参数类型,没必要用字符串类型的,就少用,不得已使用可以控制字符长度;能用int,bool之类的就用此种类型
3.操作SQL采用参数化(parameter)

猜你喜欢

转载自blog.csdn.net/qq_41654694/article/details/85785333