select from user where username='张三'
# 被注入后的查询语句构造
select from user where username='张三' and 1=1

目前都是通过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");// 实行预编译SQLResultSet 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") ));}