参数化查询
<?php
// 获取用户输入的关键字
$keyword = $_GET['keyword'];
// 执行参数化查询
$query = "SELECT * FROM articles WHERE title LIKE ?";
$stmt = mysqli_prepare($connection, $query);
mysqli_stmt_bind_param($stmt, "s", "%" . $keyword . "%");
mysqli_stmt_execute($stmt); # 执行拼接好的查询语句
$result = mysqli_stmt_get_result($stmt); # 查询结果集存储,以便后用
?php>
*这段代码是使用参数化查询来执行SQL查询语句,并从数据库中获取结果。
具体解释如下:
$query = "SELECT * FROM articles WHERE title LIKE ?";
:定义了SQL查询语句,使用占位符?
表示待填入的参数。$stmt = mysqli_prepare($connection, $query);
:使用mysqli_prepare()
函数准备查询语句,传入数据库连接对象$connection
和查询语句$query
。mysqli_stmt_bind_param($stmt, "s", "%" . $keyword . "%");
:使用mysqli_stmt_bind_param()
函数将参数绑定到查询语句中的占位符。"s"
表示参数的类型为字符串,"%".$keyword."%"
表示待填入的参数值,即用户输入的关键字。mysqli_stmt_execute($stmt);
:执行准备好的查询语句,通过mysqli_stmt_execute()
函数执行。mysqli_stmt_get_result($stmt);
:从执行的语句中获取结果集,使用mysqli_stmt_get_result()
函数将结果集存储在变量$result
中。这样可以进一步处理结果集,例如遍历结果、获取数据等操作。
使用参数化查询的方式可以确保用户输入的关键字被正确地处理,避免了宽字节注入等安全风险。通过将参数绑定到查询语句中的占位符,可以确保输入的数据被视为数据而不是可执行的代码,提高了应用程序的安全性。
预编译
<?php
// 获取用户输入的关键字
$keyword = $_GET['keyword'];
// 准备预编译语句
$query = "SELECT * FROM articles WHERE title LIKE ?";
$stmt = $connection->prepare($query);
$stmt->bind_param("s", $keywordParam);
// 设置参数并执行查询
$keywordParam = "%" . $keyword . "%";
$stmt->execute();
// 获取结果集
$result = $stmt->get_result();
// 处理结果集
while ($row = $result->fetch_assoc()) {
// 处理每行数据
// ...
}
// 关闭预编译语句和数据库连接
$stmt->close();
$connection->close();
*在这个例子中,我们使用了预编译语句和参数绑定来执行 SQL 查询。具体解释如下:
$query = "SELECT * FROM articles WHERE title LIKE ?";
:定义了 SQL 查询语句,使用占位符?
表示待填入的参数。$stmt = $connection->prepare($query);
:使用$connection
对象的prepare()
方法准备预编译语句。$stmt->bind_param("s", $keywordParam);
:使用$stmt
对象的bind_param()
方法将参数绑定到查询语句中的占位符。"s"
表示参数的类型为字符串,$keywordParam
是参数的变量。$keywordParam = "%" . $keyword . "%";
:设置参数的值为%关键字%
,即用户输入的关键字。$stmt->execute();
:执行预编译语句,通过$stmt
对象的execute()
方法执行查询。$result = $stmt->get_result();
:从执行的语句中获取结果集,通过$stmt
对象的get_result()
方法将结果集存储在变量$result
中。- 使用
while
循环遍历结果集并处理每行数据。在这个例子中,我们使用fetch_assoc()
方法获取每行数据,并进行相应的处理。 - 最后,通过
$stmt->close()
关闭预编译语句,通过$connection->close()
关闭数据库连接。
使用预编译语句和参数绑定可以防止 SQL 注入攻击,并提高应用程序的安全性。预编译语句会将参数视为数据而不是代码,避免了输入的关键字被误解为可执行的语句。
预编译和参数化的区别
- 我的理解:预编译就是把语句存储到变量中,可以重复调用,参数化是直接使用,一次性的。
- AI解释:
预编译语句和参数化查询的概念和实现方式非常相似,并且在实际使用中经常结合使用。它们都是为了解决相同的安全问题,即SQL注入攻击。
参数化查询是通过使用占位符(例如?
)来表示查询语句中的参数,并将参数值与查询语句分开发送给数据库。这样可以确保参数被正确地解释为数据而不是代码,从而预防了SQL注入攻击。
预编译语句是一种使用参数化查询的技术实现方式。在预编译过程中,应用程序将查询语句发送给数据库,并告诉数据库该查询语句包含参数。数据库会对查询语句进行编译和优化,并准备一个可重复使用的执行计划。然后,应用程序可以通过绑定参数的方式多次执行该预编译语句,避免了每次执行查询都需要重新编译查询语句的开销,提高了查询的效率。
因此,预编译语句在实现上与参数化查询非常相似。它们都使用占位符来表示参数,并将参数值与查询语句分开处理,以防止输入数据被误解为可执行的代码,从而提高了应用程序的安全性。预编译语句可以看作是对参数化查询的一种优化,可以提供更好的性能和可维护性。预编译和参数化为什么可以预防
*参数化查询是通过使用占位符(例如?
)来表示查询语句中的参数,并将参数值与查询语句分开发送给数据库。这样可以确保参数被正确地解释为数据而不是代码,从而预防了SQL注入攻击。
宽字节注入例子
*常出现再双字节编码的场景下
<?php
// 获取用户输入的关键字
$keyword = $_GET['keyword'];
// 执行SQL查询
$query = "SELECT * FROM articles WHERE title LIKE '%" . $keyword . "%'";
$result = mysqli_query($connection, $query);
*攻击者可以利用宽字节注入来绕过输入过滤和验证。例如,如果攻击者输入 %bf%27 OR 1=1 --
作为关键字,那么最终的查询语句将变成:
SELECT * FROM articles WHERE title LIKE '%¿' OR 1=1 -- %'
*这里也可以称作单引号绕过的一种方式(编码绕过 %bf%27
)
最常见的sql注入方法
<?php
$username = $_POST['username'];
$password = $_POST['password'];
$query = "SELECT * FROM users WHERE username='$username' AND password='$password'";
$result = mysqli_query($connection, $query);
// ...
?>
*这是一个登录验证的例子
如果客户端输入
SELECT * FROM users WHERE username='admin'--' AND password='...'
*在双字节编码(如UTF-8)中,单引号'
被表示为%bf%27
,注释符号--
被表示为%bf%23%bf%23
。把后面的密码验证注释掉了,不用验证了
常见的编码
%bf%27 单引号编码 (')
%bf%23%bf%23 注释符编码(--)