PHP安全之道3:常见漏洞和攻防

第一篇 SQL注入

安全配置和编程安全并不是万全之法,攻击者往往可以通过对漏洞的试探找到新的突破口,甚至0days。

下面总结以下常见漏洞,在日常开发维护工作中可以留意。

*聊聊老朋友:SQL注入漏洞

多年前我还在念本科三年级的时候就做了一次关于SQL注入的攻防实验,SQL注入在WEB1.0时代是非常常见的攻击手段,特别是一些远古时期的ASP、PHP站点,往往容易被注入提权。

简单来说SQL注入就是利用url中参数请求,不断尝试获取数据库信息,从猜字段,推测表,甚至到最后暴库得到后台管理员账号密码。

常见类型

A.报错注入
假设可以通过url来传递该参数,如:
https://learnhackerphp.com/search?username=freephp
如本来的sql为:

select * from users where name = 'freephp'

但是我们在浏览器浏览框中输入:

https://learnhackerphp.com/search?username=freephp'lol

则sql语句变为:

select * from users where name='frephp'lol'

这会导致sql语句执行报错,如果我们开启了错误调试,可能会把数据库的错误堆栈打印到浏览器页面,这会被别有用心之辈利用。网站上线后一定设置display_errors=Off。

B.普通注入

例子如下:

https://localhost/search.php?name=name' OR 'a'='a

最终SQL为:
select * from user whre name=' name' OR 'a' ='a'

这变成了一个万能查询语句,可以查到你任何想要的数据,利用union和复合语句,甚至可以获取到数据库任何数据。

C.隐式类型注入

先了解一下MySQL默认的查询优化器对入参的处理:

输入类型 表字段类型 转换后的类型
NULL 任意类型 NULL
STRING STRING STRING
INT INT INT
INT STRING DOUBLE
INT DOUBLE DOUBLE
INT TIMESTAMP TIMESTAMP
任意类型 DECIMAL DECIMAL
任意类型 十六进制 二进制

编写如下sql:

select * from user whre address=0

可以获取到该表的所有数据

D.无套路方式试探

比如在SQL语句当中附加一些其他执行命令,如:

select * from user where if (MID(version(), 1, 1) LIKE 5, sleep(5), 1)

如果真的让MySQL查询sleep了5秒,说明MySQL版本为5.

讲完了常见SQL注入,那么如何来防范呢。其实PHP已经提供了一些优秀的预处理。

可以使用PDO或者mysqli*系列函数,对sql语句进行预编译,杜绝sql注入。

prepare($sql);

$name = "freephp'hack";
$address= "CDC,china";

// 绑定参数
$stmt->bindParam(':name', $name);
$stmt->bindParam(':address', $address);

$stmt->execute();

if ($stmt->errorCode() == 0) {
    echo "insert success";
} else {
    print_r($stmt->errorInfo());
}

然而在默认情况下,使用PDO也不是让MySQL执行真正的预处理语句,一定要添加如下代码:

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO:ERRMODE_EXCEPTION);

另外我们也应该对于用户的入参进行判断,比如有效性判断、类型判断,甚至加入一些有效类型数组来约束。

不要相信任何来自用户的数据,永远都留有一个悲观锁,即使你是一个命中注定的乐天派。

你可能感兴趣的:(PHP安全之道3:常见漏洞和攻防)