SQL注入简介

1年前 (2024-04-28)
SQL 注入是一种代码渗透技术,是最常用的网络黑客技术之一。SQL 注入非常危险,可能会导致数据库中的数据被暴露,甚被损坏。

通过网页输入框(<input> 标签、<textarea> 标签等)将恶意 SQL 代码提交给服务器是最常见的 SQL 注入方式之一。

当网站要求输入诸如用户名(用户ID)之类的内容时,通常会发生 SQL 注入。黑客会输入一条 SQL 语句,而不是用户名/用户ID,当页面被提交以后,我们将不知不觉地在数据库上运行这条恶意的 SQL 语句。例如,下面的代码会将 userID 参数拼接到 SQL 语句中,从而构建 SELECT 查询,从数据库中获取当前用户的所有信息。

demoUserID = getrequestString("userID");

demoSQL = "SELECT * FROM users WHERE id =" + demoUserID;

SQL 注入的危害

SQL 注入会带来很多危害,包括但不限于:

  • 骗过登录校验,查看用户登录后的详细信息(例如发布的评论、购买的商品、邮寄地址等),这是 SQL 注入的最简单形式;

  • 更新、删除和插入记录,破坏数据库中的数据;

  • 在服务器上执行令,该令可以下载和安装木马等恶意程序;

  • 将有价值的用户数据(例如邮箱、密码、信用卡等)导出到攻击者的远程计算机。

SQL 注入示例

现在有一个查看员工信息的页面,该页面允许所有员工通过输入自己的 ID 来查看个人信息。假设员工 ID 在数据表中的字段名为 id,现在有黑客在 <input> 文本框中输入以下内容:

236893238 OR 1=1

它将被拼接成下面的 SQL 语句:

SELECT * FROM employee WHERE id = 236893238 OR 1=1;

这条 SQL 代码是有效的,将从 employee 表中返回所有符条件的记录。1=1始终成立,这条 SQL 语句将返回 employee 表中的所有记录,这意味着,所有的员工信息都将被泄露。

类似的,黑客还可以骗过登录校验,使用无效的用户名和密码登录:

SELECT * FROM employee WHERE (username="" or 1=1) AND (password="" or 1=1);


有些数据库支持批处理 SQL 语句,也即一组由分号;分隔的两条或者多条 SQL 语句。下面给出的 SQL 语句将返回 employee 表的所有行,然后删除 employee_add 表:

SELECT * FROM employee; DROP TABLE employee_add;

防止 SQL 注入

SQL 注入不能杜绝,只能尽力防止,因为即使秀的程序员也会犯错。Web 防火墙可以检测和阻止最基本的 SQL 注入攻击,但是它仅仅是一种预防手段,我们还要从自己的代码入手,检测用户输入的内容。永远不要信任用户提供的数据,仅在校验通过后才能将数据提交给数据库。

通常使用模式匹配(Pattern Matching),借助正则表达式来校验用户输入的数据,几乎每种编程语言都提供了模式匹配函数。

下面是一段 PHP 代码,它使用 preg_match() 校验用户输入的数据,限定用户名只能包含汉字、字母、数字、下划线_和连字符-

if (preg_match("/^[\x{4e00}-\x{9fa5}0-9A-Za-z_\-]{2,20}$/u", $_POST['username'], $matches)) {

$result = mysql_query("SELECT * FROM user WHERE name = $matches[0]");

} else {

echo "Tips from c.biancheng网站站点" rel="nofollow" />

// 去除斜杠

if (get_magic_quotes_gpc()) {

$name = stripslashes($name);

}

// 对特殊字符进行转义

$name = mysql_real_escape_string($name);

mysql_query("SELECT * FROM user WHERE name='{$name}'");


对于 LIKE 查询,应该使用 addcslashes() 函数对用户输入的%_字符进行转义。addcslashes() 允许用户指定要转义的字符,请看下面的代码:

$sub = addcslashes(mysql_real_escape_string("%str"), "%_");

// 转换以后的 $sub == \%str\_

mysql_query("SELECT * FROM messages WHERE subject LIKE '{$sub}%'");