PHP SQL注入攻击与防御

PS:下章节我会就XSS/CSRF写一篇文章,还请各位关注

1.什么是SQL注入攻击?

百度百科:所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意的)SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。

其实,我们可以简单的理解SQL注入为:未对用户输入进行过滤,导致用户的一些输入在程序执行时,当做SQL语句的一部分进行执行,从而针对一些敏感操作:OR 1=1 或者 WHERE 1=1 这种条件的加入,使得我们本身的SQL逻辑被跳过执行。


2.PHP通用SQL注入攻击方式

为了方便理解SQL注入攻击,现在模拟网站的用户登录操作,进行SQL注入攻击演示,附上以下示例:

登录界面如下:


我们的测试用户名及密码:admin/123456

①首先,我们使用正确的登录用户名及密码:

 

②我们通过SQL注入方式跳过密码验证登录:



通过两次登录的SQL语句,我们可以很清楚的看出差异

# step 1 SQL
SELECT * FROM users WHERE username = 'admin' AND password = 'e10adc3949ba59abbe56e057f20f883e'
# step 2 SQL
SELECT * FROM users WHERE username = 'admin'#' AND password = '96e79218965eb72c92a549dd5a330112'

其中第二步由于前台传入特殊字符单引号(')及#,在数据库中#为语句注释部分,则后续SQL语句不会被执行,可直接跳过我们的密码验证逻辑。

同时,我们也可以通过下面方式跳过逻辑判定


SQL语句如下:

SELECT * FROM users WHERE username = 'admin' OR 1='1' AND password = '96e79218965eb72c92a549dd5a330112'

同样,我们使用此种方式可以达到跳过登录验证的目的

此类问题是未对用户输入的特殊字符进行过滤,如单引号('),双引号("),NULL等。PHP可以通过设置打开magic_quotes_gpc,自动针对特殊字符增加反斜线(\)的方式,对其进行转义,而避免被程序执行,当然,也可以利用以下方法针对未开启magic_quotes_gpc时,进行处理:

function addslashes_deep($value)
{
    if (empty($value))
    {
        return $value;
    }
    else
    {
        return is_array($value) ? array_map('addslashes_deep', $value) : addslashes($value);
    }
}
	
if(!get_magic_quotes_gpc())
{	
    $_POST = addslashes_deep($_POST);
    $_GET = addslashes_deep($_GET);
}

这样,上述经过处理的SQL语句如下:

SELECT * FROM users WHERE username = 'admin\' OR 1=\'1' AND password = '96e79218965eb72c92a549dd5a330112'
就不会被解释执行了


③数字型SQL注入攻击

首先,我们将上面测试代码一部分改为如下:

$id = $_GET['id'];	
$sql = "SELECT * FROM users WHERE id=".$id;
$res = $db->query($sql)->fetch_all();
/test.php?id=1 UNION SELECT 1,username,password,4,5,6,password,8,9,10,11 FROM users

浏览器地址栏输入如上地址,后台显示SQL如下:

SELECT * FROM users WHERE id=1 UNION SELECT 1,username,password,4,5,6,password,8,9,10,11 FROM users

我们通过这里很容易利用UNION命令,查询出用户名和密码等敏感信息

当然,此类防御也相当简单,对于整数型数据,我们在获取时,需要对其进行转化如下:

$id = intval($_GET['id'])
即可避免此类上述SQL注入


3.总结

通过以上两个示例,在PHP中,可以通过简单的三种方法来防御SQL注入:

①对用户的输入进行过滤处理后,在进行操作,如:addslashes()方法或者开启magic_quotes_gpc方法

②针对获取的数值型数据,进行二次转换,如intval(),floatval()

③所有需进行数据库查询的变量都使用单引号(')包围,如下:

$sql = "SELECT * FROM users WHERE username='".$username."'";

4.代码:

后台test.php

function pretty_print($array)
{
	echo '<pre>';
	print_r($array);
	echo '</pre>';
}
function addslashes_deep($value)
{
    if (empty($value))
    {
        return $value;
    }
    else
    {
        return is_array($value) ? array_map('addslashes_deep', $value) : addslashes($value);
    }
}
	
if(!get_magic_quotes_gpc())
{	
	$_POST = addslashes_deep($_POST);
	$_GET = addslashes_deep($_GET);
}

$db = mysqli_connect('127.0.0.1','root','root','mysqli_test');

$username = $_POST['username'];
$password = $_POST['password'];

$sql = "SELECT *".
       " FROM users".
       " WHERE username = '".$username.
       "' AND password = '".md5($password)."'";
	

$res = $db->query($sql)->fetch_row();

if(empty($res))
{
	echo '登录失败,用户名或密码不正确!';
}
else
{
	echo '登录成功,欢迎您:'.$res[1];
}


前台index.html

<!DOCTYPE html>
<html>
<head>
	<title>表单提交测试</title>
	<meta charset="utf-8">
</head>
<body>
	<form method="post" action="test.php">
		用户名:<input type="text" name="username"><br/>
		密    码:<input type="text" name="password"><br/><br/>
		<button type="submit">提交</button>
	</form>
</body>
</html>

资源参考:

百度百科:https://baike.baidu.com/item/sql%E6%B3%A8%E5%85%A5/150289?fr=aladdin

BLOG:https://www.cnblogs.com/joshua317/articles/3939718.html


展开阅读全文

没有更多推荐了,返回首页