基于PHP的SQL注入防御

标签: web安全

一、漏洞页面实例

需要用到的知识:PHP语言,Apache Web服务器,MySQL数据库

1.首先打开phpstudy,开启apache web服务和数据库

在这里插入图片描述
2.利用Navicat创建数据库(也可以用别的软件创建,在phpstudy里也可以创建,懂mysql命令行的也可以用cmd创建,看自己喜好)

创建数据库名为test,在数据库中创建表users,在表中插入两个字段name和password,添加若干数据。

在这里插入图片描述

3.书写sql.php和sql.html代码

将这两个文件保存到phpstudy目录的WWW跟目录下(我保存到了WWW目录下的CrackTest中了)

//sql.php代码
<?php
$name=$_POST["userID"];
$passwd=$_POST["userPasswd"];
[email protected]_connect('localhost','root','root') or die("Fail");
mysqli_select_db($db,"test");
$sql="SELECT * FROM users WHERE name = '$name' AND password = '$passwd'";
echo "<TABLE border=1>";
echo "<tr><th>Name</th><th>Password</th><tr>";
if($result=mysqli_query($db,$sql)) {
	while($array=mysqli_fetch_row($result)) {
		printf("<tr><td>%s</td><td>%s</td><tr>", $array[0], $array[1]);
	}
}
echo "</TABLE>";
echo "</div>";
?>
<!--sql.html代码-->
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>SQLtest</title>
</head>
<body>
<form action="sql.php" method="post">
	用户名:
	<input type="text" name="userID" />
	密码:
	<input type="text" name="userPasswd" />
	<input type="submit" />
</form>
</body>
</html>

4.开始sql注入测试

在浏览器中打开我们的sql.html

在这里插入图片描述
完整的sql语句是

SELECT * FROM users WHERE name = '' OR 1=1# AND password = '';

所以我们构造sql注入payload,sql语句执行的结果是永真的

' OR 1=1#

在这里插入图片描述
提交后
在这里插入图片描述
数据库中的用户名和密码就被我们全部查出来了

二、分析及防御

1.php输入验证

在上面的例子中,我们后端并没有对前端传过来的参数进行验证,所以导致了恶意sql代码的执行。是不是可以通过对像单引号',反斜杠\,字符or等敏感字符进行过滤,或者转义一些参数,从而破坏构造的sql语句,达到我们的目的呢。

参考:sql注入之代码层防御策略

<?php
$name=$_POST["userID"];
$passwd=$_POST["userPasswd"];

// 使用白名单进行输入用户名和密码验证
$whitepattern="/^[a-z\d]*$/i";         // 构造的白名单正则表达式,只允许输入的内容是字符串和数字的组合
$blackpattern="/\*|'|\"|#|;|,|or|\^|=|<|>|and/i";
// 构造的黑名单正则表达式
if(preg_match($blackpattern, $name)){ // preg_match:使用正则表达式对字符串进行正则匹配
	die('illegal input! 用户名中包含敏感词汇!');
}
if(!preg_match($whitepattern, $passwd)){
	die('illegal input! 密码中包含敏感词汇!');
}

[email protected]_connect('localhost','root','root') or die("Fail");
mysqli_select_db($db,"test");
$sql="SELECT * FROM users WHERE name = '$name' AND password = '$passwd'";
echo "<TABLE border=1>";
echo "<tr><th>Name</th><th>Password</th><tr>";
if($result=mysqli_query($db,$sql)) {
	while($array=mysqli_fetch_row($result)) {
		printf("<tr><td>%s</td><td>%s</td><tr>", $array[0], $array[1]);
	}
}
echo "</TABLE>";
echo "</div>";
?>

测试一下
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.PHP预处理

PHP5.x开始引入了一种新的mysql操作方式-----mysqli,在php中也有一项相应的操作方式叫做PHP预处理。采用面向对象的方式来进行参数化绑定操作,由于对数据库操作的模式驱动不同,因此可以非常有效的防御sql注入。

参考:php之防御sql注入

<?php
if( isset($_POST["userID"]) && isset($_POST["userPasswd"]) && $_POST["userID"]!='' && $_POST["userPasswd"]!=''){
	$name=$_POST["userID"];
	$passwd=$_POST["userPasswd"];

	echo "<TABLE border=1>";
	echo "<tr><th>Name</th><th>Password</th><tr>";


	$root="root";
	$pwd="root";
	$host="localhost";
	$database="test";
	$conn = new mysqli($host,$root,$pwd,$database);// 创建数据库连接
	$search_sql = "select * from users where name=? and password=?";// ?为占位符
	$search_action = $conn->prepare($search_sql);// 进行预处理操作
	$search_action->bind_param("ss", $name, $passwd);// 绑定参数,第一个参数表示占位符的个数,s表示字符串,i为×××,d为双精度小数,有几个占位符就写几个
	$search_action->bind_result($username, $password);// 将结果绑定到相对应的变量上
	$search_action->execute();// 执行sql操作
	while($search_action->fetch()){
		printf("<tr><td>%s</td><td>%s</td><tr>", $username, $password);
	}
	echo "</TABLE>";
	echo "</div>";
	$search_action->free_result();// 释放内存
	$search_action->close();// 结束实例化
}else {
	die("Illegal input! 用户名或密码不能为空!");
}

?>


代码中,我们设定输入的参数不能为空,之后通过php预处理的方式构造sql查询,代码有注释,不明白的地方可以看一下。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们看到虽然没有报出错误,但是后台什么内容都没有返回。大家可以自己用别的语句测试一下,这里就不赘述啦!

完结撒花~~

版权声明:本文为qq_43535990原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_43535990/article/details/109429086