sql注入代码分析及预防

sql注入的原因,表面上说是因为 拼接字符串,构成sql语句,没有使用 sql语句预编译,绑定变量。但是更深层次的原因是,将用户输入的字符串,当成了 “sql语句” 来执行。

1.union注入攻击

<?php
$con=mysqli_connect("localhost","root","","test");
// 检测连接
if (mysqli_connect_errno())
{
    echo "连接失败: " . mysqli_connect_error();
}

$id = $_GET['id'];

$result = mysqli_query($con,"select * from users where `id`=".$id);

while($row = mysqli_fetch_array($result))
{
    echo $row['username'] . " " . $row['address'];
    echo "<br>";
}
?>

当前端通过get方法传参进来之后,如果没有进行判断,或者过滤一些非法的字符串,这些非法的字符串,就会和$result = mysqli_query($con,"select * from users where `id`=".$id);拼接在一起,然后传入后台数据库,进行sql语句查询,然后数据库会返回来所查询到的信息,以至于泄露用户的账号及其密码等敏感信息,因此程序员在编写程序时,一定要对传入的参数值进行过滤。

2.boolean注入攻击

<?php
$con=mysqli_connect("localhost","root","","test");
// 检测连接
if (mysqli_connect_errno())
{
    echo "连接失败: " . mysqli_connect_error();
}

$id = $_GET['id'];

if (preg_match("/union|sleep|benchmark/i", $id)) {
    exit("no");
}

$result = mysqli_query($con,"select * from users where `id`='".$id."'");

$row = mysqli_fetch_array($result);

if ($row) {
    exit("yes");
}else{
    exit("no");
}


?>

3.报错注入

<?php
$con=mysqli_connect("localhost","root","","test");
// 检测连接
if (mysqli_connect_errno())
{
    echo "连接失败: " . mysqli_connect_error();
}

$username = $_GET['username'];

if($result = mysqli_query($con,"select * from users where `username`='".$username."'")){
    echo "ok";
}else{
    echo mysqli_error($con);      /*这个语句本不应该在这里出现的,在编写程序时,程序员为了检查代码,然后造成了报错sql注入,如果将输出语句改成 echo "no",即便查询语句传入数据库,但也没办法在前端              显示,但是还是要对传入的参数进行过滤的*/
}

?>

通过上面两个实例,我们对sql注入有了初步的了解,平时应该怎样防御sql注入呢?

4.sql注入的防御

1>采用sql语句预编译和绑定变量,是防御sql注入的最佳方法。

String  sql = "select  * from test where id=?";

PreparedStatement  ps = conn.prepareStatement(sql);

ps.setInt(1,id);

ps.executeQuery();

通过采用PreparedStatement,就会将sql语法 "select  * from test where id=?" 预先编译好,也就是SQL引擎会预先进行语法分析,产生语法树,生成执行计划,也就是说,后面你输入的参数,无论你输入的是什么,都不会影响sql语句的语法结构,因为语法分析已经完成了,而语法分析主要是分析sql命令,如select,from,等等,所以即便你后面输入了这些sql命令,也不会当成sql命令来执行,因为这些sql命令的执行,必须先得通过语法分析,生成执行计划,既然语法分析已经完成,已经预编译过了,那么后面输入的参数,是绝对不可能作为sql命令来执行的,只会被当做字符串字面值参数。所以sql语句预编译可以防御sql注入

2>除了以上得方法,我们还需要使用一些安全函数来防止sql注入,因为不是所有场景都能够采用 sql语句预编译,有一些场景必须的采用 字符串拼接的方式。

比如 String sql = "select * from test where id =" +id;

在接收到用户输入的参数时,我们就严格检查 id,只能是int型。复杂情况可以使用正则表达式来判断。这样也是可以防止sql注入的。

MySQLCodec codec = new MySQLCodec(Mode.STANDARD);
name = ESAPI.encoder().encodeForSQL(codec, name);
String sql = "select * from test where name=" + name;
ESAPI.encoder().encodeForSQL(codec, name)
该函数会将 name 中包含的一些特殊字符进行编码,这样 sql 引擎就不会将name中的字符串当成sql命令来进行语法分析了。

 

posted @ 2021-10-28 21:12  kalibb  阅读(354)  评论(0编辑  收藏  举报