您的位置:首页 > 编程语言 > PHP开发

PHP SQL注入攻击与防御

2018-03-22 20:31 204 查看
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.phpfunction 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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息