预准备语句如何避免或阻止 SQL 注入?

我知道ReadyStatements避免/阻止SQL注入。它是如何做到这一点的?使用 ReadyStatements 构造的最终表单查询是字符串还是其他类型?


答案 1

考虑两种做同样的事情的方法:

PreparedStatement stmt = conn.createStatement("INSERT INTO students VALUES('" + user + "')");
stmt.execute();

PreparedStatement stmt = conn.prepareStatement("INSERT INTO student VALUES(?)");
stmt.setString(1, user);
stmt.execute();

如果“user”来自用户输入,并且用户输入是

Robert'); DROP TABLE students; --

然后,首先,你会被管住。在第二种情况下,你会很安全,小鲍比桌子会为你的学校注册。


答案 2

要了解 ReadyStatement 如何阻止 SQL 注入,我们需要了解 SQL 查询执行的各个阶段。

1. 编译阶段。2. 执行阶段。

每当SQL服务器引擎收到查询时,它必须通过以下阶段,

Query Execution Phases

  1. 解析和规范化阶段:在此阶段,将检查查询的语法和语义。它检查查询中使用的引用表和列是否存在。它还还有许多其他任务要做,但让我们不要详细介绍。

  2. 编译阶段:在此阶段,查询中使用的关键字(如select,from,where等)将转换为机器可以理解的格式。这是解释查询并确定要采取的相应操作的阶段。它还还有许多其他任务要做,但让我们不要详细介绍。

  3. 查询优化计划:在此阶段,将创建决策树以查找执行查询的方式。它找出可以执行查询的方式的数量以及与执行查询的每种方式相关的成本。它选择执行查询的最佳计划。

  4. 缓存:在查询优化计划中选择的最佳计划存储在缓存中,以便下次出现同一查询时,它不必再次通过阶段 1、阶段 2 和阶段 3。下次查询时,将直接在缓存中检查它,并从那里选取以执行。

  5. 执行阶段:在此阶段,将执行提供的查询,并将数据作为对象返回给用户。ResultSet

预准备语句 API 在上述步骤中的行为

  1. 预准备语句不是完整的 SQL 查询,并且包含占位符,这些占位符在运行时由用户提供的实际数据替换。

  2. 每当任何包含占位符的准备语句传递到 SQL Server 引擎时,它都会经历以下阶段

    1. 解析和规范化阶段
    2. 编译阶段
    3. 查询优化计划
    4. 缓存(带占位符的已编译查询存储在缓存中。

更新用户设置用户名=?和密码 =?其中 id=?

  1. 上面的查询将被解析,使用占位符编译作为特殊处理,优化并获取缓存。此阶段的查询已以机器可理解的格式进行编译和转换。因此,我们可以说存储在缓存中的查询是预编译的,只有占位符需要替换为用户提供的数据。

  2. 现在,在运行时,当用户提供的数据进入时,将从缓存中选取预编译查询,并将占位符替换为用户提供的数据。

PrepareStatementWorking

(请记住,在用用户数据替换占位符后,不会再次编译/解释最终查询,并且 SQL Server 引擎将用户数据视为纯数据,而不是需要再次分析或编译的 SQL;这就是 PreparedStatement 的优点。

如果查询不必再次经历编译阶段,则在占位符上替换的任何数据都将被视为纯数据,对 SQL Server 引擎没有任何意义,它将直接执行查询。

注意:解析阶段之后的编译阶段是理解/解释查询结构并为其提供有意义的行为。对于 ReadyStatement,查询只编译一次,并且始终拾取缓存的已编译查询以替换用户数据并执行。

由于ReadkEdStatement的一次性编译功能,它没有SQL注入攻击。

您可以在此处通过示例获得详细说明:https://javabypatel.blogspot.com/2015/09/how-prepared-statement-in-java-prevents-sql-injection.html


推荐