SQL 全文索引和 SQL 注入

SQL FullText Indexes and SQL Injection

将全文索引的使用暴露给内部用户和可能的 public 用户是否存在任何已知的危险?

假设查询已正确参数化,用户是否可以通过任何方式滥用输入来触发 SQL 注入或拒绝服务攻击?

// SQL Server
select * from content_table WHERE CONTAINS((Title, Subtitle, Body), @fullTextSearch);

// MySQL
select * from content_table WHERE MATCH(Title, Subtitle, Body) AGAINST (@fullTextSearch);

// Oracle
select * from content_table WHERE CONTAINS(Body, @fullTextSearch);

这个问题的触发因素是用户可以指定的输入种类繁多,而且不同的 SQL 服务器具有不同的查询语法,至少有一些 (MySQL) return 如果指定了无效查询,则会出现语法错误。

在谈论 SQL 注入时,风险在于有人可以通过将 SQL 添加到数据参数来将 SQL 关键字引入查询本身。

这就是为什么数据和查询的分离是绝对重要的。这通常通过使用 占位符值 来实现,如:

SELECT * FROM content_table WHERE MATCH(Title, Subtitle, Body) AGAINST (?);

在搜索的情况下,您通常需要注意两个级别:

  • 使用原始SQL关键字表达查询条件的SQL层,例如WHERE x=? AND y=?
  • 您在字符串 中表达条件的搜索层 ,例如 WHERE CONTAINS(?) 具有绑定数据参数 '"computer software" NEAR hardware)'

请注意,第二种形式在字符串中有一个语法,所以如果你公开你本身没有 SQL 注入的风险,但你最终可能会收到很多您需要处理由错误的用户输入引起的语法错误。

第一种情况如果需要组合查询条件需要遵循通常的规则:

  • 不允许:
    • 查询中包含未知字段。
    • 查询中包含未知运算符。
  • 尽可能严格区分查询和数据。

您可能需要将请求的数据解析为可重组为 SQL 查询的组件。这可能会变得混乱,特别是如果您允许在搜索方式上有很大的自由度,所以请尽量保持简单和可测试

如果您有单元测试,请包括一个故意敌对并试图将无效或注入式数据引入查询的单元测试。确保正确包含数据。

Note: If you're calling a stored procedure using placeholder values, but the stored procedure composes SQL statements using concatenation you're still at risk, so you need to be absolutely certain you're keeping the data separated from the query. If you have a query with zero user data introduced in it there is no risk of SQL injection.