1

我正在使用 Laminas 框架(以前的 ZEND 框架),并想知道数据库适配器是否在插入和选择语句/执行 ($statement->prepare() / $statement->execute()-> current()) 来避免 SQL 注入?

如果不是,在使用 LAMINAS DB 适配器时实现它的最佳方法是什么?一个包装函数来获得一个干净的 SQL 语句?

之前,我使用的是一个包装函数,它使用mysqli_real_escape_string

4

1 回答 1

1

您需要提供一些示例代码才能更准确地回答这个问题,但是您在这里谈论的主题是参数化。如果您正确使用 laminas-db,则无需调用mysqli_real_escape_string或类似方法来防止 SQL 注入。但是,如果写入数据库的任何数据最终被回显到浏览器,您仍然应该非常警惕任何潜在的跨站点脚本 (XSS) 问题。请参阅下面的部分。

如何不做

如果你做这样的事情,laminas-db 不会为你参数化你的查询,而且你很容易受到 SQL 注入的影响:

// DO NOT DO THIS
$idToSelect = $_POST['id'];
$myQuery = "select * from myTable where id = $idToSelect";
$statement->prepare($myQuery);
$results = $statement->execute();

如何正确地做

就个人而言,我使用了 LaminasTableGatewayInterface抽象,因为它通常使生活变得更轻松。如果您想在较低级别进行操作,则这样的操作是一种更安全的方法;它将确保您不会意外地将一大堆 SQL 注入漏洞添加到您的代码中

命名参数

$idToSelect = $_POST['id'];
$myQuery = "select * from myTable where id = :id";
$statement->prepare($myQuery);
$results = $statement->execute(['id' => $idToSelect]);

匿名参数

$idToSelect = $_POST['id'];
$myQuery = "select * from myTable where id = ?";
$statement->prepare($myQuery);
$results = $statement->execute([$idToSelect]);

如果您以与此类似的方式执行此操作,则不需要任何额外的包装函数或任何东西,底层组件将为您处理。您可以使用命名参数版本或匿名参数版本,但我个人更喜欢命名参数,因为我发现它有助于代码可读性并且通常使调试更容易。

清理输入/转义输出

清理输入时要非常小心。它不仅会导致错误的安全感,还会引入微妙且非常令人沮丧的行为,最终用户会将其视为错误。

举个例子:有人试图以“Bob & Jane Smith”的名义注册一个网站,但是输入清理例程发现了 & 字符并将其删除。突然之间,鲍勃获得了一个他们从来不知道的中间名。
输入清理的最大问题之一是上下文。有些字符在一个给定的上下文中可能是不安全的,但在另一个上下文中完全是良性的。此外,如果您需要支持整个 unicode 字符集(我们通常应该支持,除非我们有充分的理由不支持),请尝试清除可能通过多个不同系统(html、javascript、 html、php、sql 等)由于处理多字节字符的方式而成为一个非常困难的问题。

对于 MySQL,参数化几乎可以解决所有这些问题,因此我们无需担心“小鲍比表”场景

将所有这些都颠倒过来并逃避输出要容易得多。理论上,呈现输出数据的代码知道它的目的地是哪个上下文,因此可以转义所述上下文的输出,用安全的替代品替换控制字符。

例如,假设有人在一个虚构的社交网站上的个人简历中添加了以下内容:

My name is Bob, I like to write javascript
<script>window.postStatusUpdate("Bob is my hero ♥️");</script>

这将需要以不同的方式进行转义,具体取决于要显示此数据的上下文。如果要在浏览器中显示,转义符需要用转义版本替换尖括号。如果它作为 JSON 输出输出,则需要对双引号进行反斜杠转义等。

我很欣赏这是对一个看似简单的问题的一个相当随意的答案,但是这些事情当然应该在应用程序设计的早期考虑;它可以为您节省大量时间和进一步的挫败感。

于 2021-08-02T12:15:45.340 回答