优秀的编程知识分享平台

网站首页 > 技术文章 正文

mysql进阶之SQL注入(mysql sql注入执行命令)

nanyue 2024-07-20 23:52:58 技术文章 10 ℃

什么是SQL注入

SQL注入就是外部传入特殊的SQL查询参数,经mysql解析执行后得到非预期结果。如要查询昵称为张三的用户,如果接收到的查询参数是张三 and 1=1这时会查询到所有用户。

# 常规的查询语句结构

select * from user where username='张三'

# 被注入后的查询语句结构

select * from user where username='张三' and 1=1

服务器如何避免被SQL注入

目前都是通过SQL预编译避免SQL注入。

什么是SQL预编译?

通常服务器接收到一条SQL需要经过语法、语义解析,生成执行计划,最后执行返回结果。一般同一条SQL会执行多次,只是字段参数值不同,通过预编译后可以生成一条SQL模板,相同的SQL可以省略解析的步骤,直接替换字段参数值即可执行。可以提高执行效率。

为什么SQL预编译可以防止SQL注入?

经过预编译后,mysql在执行参数替换时只会把参数值当做普通的值加入到SQL中,而不会再将整个SQL重新编译。

如何使用预编译

在PHP中

// 连接数据库
$link = mysqli_connect("127.0.0.1", "root","root","db_xb", 3308);
if ($link) {
    echo "连接成功...", PHP_EOL;
    // 创建预编译的Statement
    $stmt = mysqli_prepare($link, "select username,nickname from xb_sys_user where username=?");
    $username = "uu";
    // 绑定预编译SQL的参数
    $stmt->bind_param("s", $username);
    // 将查询结果绑定到指定的变量
    $stmt->bind_result($db_username, $db_nickname);
    // 执行预编译SQL
    $stmt->execute();
    // 获取执行后的结果
  	$stmt->fetch();
    // 使用关联数组的方式获取结果
//            $rs = $stmt->get_result();
//            dump($rs->fetch_assoc());
    
    printf("%s is in username: %s nickname: %s\n", $username, $db_username, $db_nickname);
    mysqli_close($link);
}

在Java中

// 注册JDBC驱动
Class.forName("com.mysql.cj.jdbc.Driver");
Connection connection = DriverManager.getConnection(
        "jdbc:mysql://localhost:3308/db_xb",
        "root",
        "root"
);
// 预编译方式
PreparedStatement preparedStatement = connection.prepareStatement("select * from xb_sys_user where username=?");
// 设置预编译SQL的参数
preparedStatement.setString(1, "uu");
// 执行预编译SQL
ResultSet rs = preparedStatement.executeQuery();
System.out.println("执行查询成功...");
// 获取结果
while (rs.next()) {
    System.out.println(String.format(
            "按字段索引位置取\tid: %d username: %s nickname: %s password: %s status: %d",
            rs.getLong(1), // 按数据表中的字段索引位置开始取
            rs.getString(2),
            rs.getString(3),
            rs.getString(4),
            rs.getInt(5)
    ));
    System.out.println(String.format(
            "按字段名取\tid: %d username: %s nickname: %s password: %s status: %d",
            rs.getLong("id"), // 按数据表中的字段名开始取
            rs.getString("username"),
            rs.getString("nickname"),
            rs.getString("password"),
            rs.getInt("status")
    ));
}

Tags:

最近发表
标签列表