常见防御方法
防御原理:输入(解决数字型注入–>即加is_numeric这些去判断)-------转义处理(解决字符型注入)-------输出(解决数据库报错)
1.禁止数据库爆错信息泄露件 php.ini文件中display_errors = Of
2.php内部转义处理函数
mysql_real_escape_string-->能将特殊字符进行转义
mysql_escape_string()
magic_quote_gpc()
addslashes->这个函数会加上转义符
对立函数stripcslashes-->这个函数为删除字符串中存在的\
3.预处理技术进行查询
利用
m
y
s
q
l
i
−
>
p
r
e
p
a
r
e
和
mysqli->prepare和
mysqli−>prepare和mysqli_stmt->bind_param函数进行去预处理
<?php
$sql = "select id,username,password from users where id=?";创建一个预定义的对象 ?占位
$mysqli_stmt = $mysqli->prepare($sql);
$id=$_REQUEST['id'];
$mysqli_stmt->bind_param("i",$id);绑定参数
$mysqli_stmt->bind_result($id,$username,$password);绑定结果集
$mysqli_stmt->execute();//执行
while($mysqli_stmt->fetch()){ //取出绑定的结果集
echo $id." ".$username ." ". $password;
}
?>
代码分析
== 防御成功的利用这两个函数即可==
<?php
if (isset($_GET['Submit'])) {
// Retrieve data
$id = $_GET['id'];
$id = stripslashes($id);
$id = mysql_real_escape_string($id);
if (is_numeric($id)){
$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id'";
$result = mysql_query($getid) or die('<pre>' . mysql_error() . '</pre>' );
$num = mysql_numrows($result);
$i=0;
while ($i < $num) {
$first = mysql_result($result,$i,"first_name");
$last = mysql_result($result,$i,"last_name");
echo '<pre>';
echo 'ID: ' . $id . '<br>First name: ' . $first . '<br>Surname: ' . $last;
echo '</pre>';
$i++;
}
}
}
?>
如果没有两个过滤函数
利用方法 http://127.0.0.1/?id=1
特殊案例
1.宽字节注入思路
1.1 常规宽字节注入
核心:mysql查询的时候采用宽字节方式查询导致
<?php
$con = mysql_connect("localhost","root","root");
mysql_query("SET NAMES 'gbk'");
mysql_select_db("test", $con);
$id = isset($_GET['id']) ? addslashes($_GET['id']) : 1;
$query = "SELECT * FROM users WHERE id ='{$id}' ";
?>
因此可以利用
id=%df%27进行去绕
修复方法:
1.将character_set_client设置为binary(二进制)
全部指定为二进制传输
mysql_query("SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary",
$conn);
2.指定php连接mysql的字符集
mysql_set_charset('gbk',$conn);
id=mysql_real_escape_string(_GET['id']);
1.2php编码转换导致的宽字节注入
导致原理:在字符输入后进行了编码转换进而导致逃逸单引号
<?php
$con = mysql_connect("localhost","root","root");
mysql_query("SET NAMES 'gbk'");
mysql_select_db("test", $con);
mysql_query("SET character_set_connection=gbk,
character_set_results=gbk,character_set_client=binary", $con);
$id = isset($_GET['id']) ? addslashes($_GET['id']) : 1;
$id=iconv('utf-8','gbk',$id);//和上面相比 添加了这个代码
$query = "SELECT * FROM users WHERE id ='{$id}' ";
$result = mysql_query($query)or die('<pre>'.mysql_error().'</pre>');
while($row = mysql_fetch_array($result))
{
echo $row['0'] . " " . $row['1'];
echo "<br />";
}
echo "<br/>";
echo $query;
mysql_close($con);
?>
#绕过语句--> 錦',因为utf-8编码和gbk编码的不同性质,进而导致逃逸,溢出导致sql注入。
2.编码解码导致sql注入
原理:
字符在拼接到sql注入之前进行了解码
例子
<?php
$con = mysql_connect("localhost","root","root");
mysql_select_db("test", $con);
$id = addslashes($_REQUEST['id']);
$id = urldecode($id);//$id = base64_decode($id);#核心导致的原因
$query = "SELECT * FROM users WHERE id = '{$id}'";
$result = mysql_query($query)or die('<pre>'.mysql_error().'</pre>');
#绕过方法
id=1%2527union select 1,2,3,4%23
3.json编码注入绕过
json编码绕过addslashes是因为json编码会把\转换为\ ,admin’ # 被addslashes会变成admin’ # 引号被过滤了转移不了,但是
经过了json_encode后变成admin\’ # 引号成功逃了出来,可以注入
4.二次注入
导致原理:
1.数据入库后转义符号会无
2.而且在次调用了我们插入的内容去查询
如2018 网鼎杯
5.其他类型的
5.1
stripslashes+addslashes导致的注入
即在入库数据之前做了stripslashes操作
5.2
字符替换导致的addslashes