注意:这是 CenterEdge Software 的 Brant Burnett 的客座帖子,该公司为游乐园、休闲和娱乐行业开发 POS 和专业软件。
概述
N1QL 是一个非常强大的新工具,它将有助于以更浅的学习曲线将 NoSQL 数据库带给更广泛的开发人员群体。这将帮助开发人员比以往更快、更轻松地创建高级、高性能和健壮的应用程序。但是对于任何新技术,黑客攻击的表面积都在本质上增加。
SQL 注入是一种众所周知的安全漏洞,常见于基于 SQL 的应用程序中,并且多年来已得到很好的记录。那么 N1QL 在安全性方面与 SQL 相比如何呢? N1QL 是否也容易受到注入攻击?如果是这样,开发人员如何避免这些陷阱?
SQL注入回顾
SQL 注入是一种代码注入形式,最终用户可以将恶意代码添加到您的应用程序运行的 SQL 查询中。一个简单的例子是这个查询:
var query = "SELECT * FROM users WHERE name ='" + userName + "'";
如果开发人员不采取措施保护他们的应用程序,用户可能会在 userName 字段中包含恶意文本。例如:
SELECT * FROM users WHERE name = '' OR '1'='1'
此查询是用户输入“' OR '1'='1”的结果。现在查询会将系统中的所有用户返回给恶意用户。
为了允许更强大的查询更改,恶意用户还可能使用注释来排除开发人员的部分查询。扩展前面的例子:
var query = "SELECT * FROM users WHERE name ='" + userName + "'";
可以注射:
var query = "SELECT * FROM users WHERE name ='" + userName + "'";
由于 SQL 将忽略“--”之后的所有文本,因此组必须为 5 的限制现在已从查询中删除。系统中的所有用户再次返回给恶意用户。
用户还可以将注释与批处理命令结合起来以更改数据库中的数据:
var query = "SELECT * FROM users WHERE name ='" + userName + "'";
这对 N1QL 有何影响?
经过一些实验,N1QL 实际上比传统的 SQL 更能抵抗注入攻击。但是,恶意用户仍然可以选择执行攻击。如果没有保护,这些攻击可能会导致允许访问安全数据或拒绝服务,因为更改的查询在 Couchbase 集群上使用了过多的处理能力。
N1QL 当前不支持批处理多个命令。因此,没有等同于允许恶意修改 SQL 中数据的批处理攻击。但是,批处理肯定会作为新功能添加到 N1QL 的未来版本中。因此,如果开发人员不保护查询中的用户输入,数据修改将来可能会成为一个问题。
Where 子句修改
与 SQL 注入一样,N1QL 注入允许更改 WHERE 子句。例如:
var query = "SELECT * FROM users WHERE name ='" + userName + "'";
可以变成:
var query = "SELECT * FROM users WHERE name ='" + userName + "'";
由于 AND 和 OR 运算符的运算符优先级规则,如果有附加子句,这种攻击甚至可以起作用:
var query = "SELECT * FROM users WHERE name ='" + userName + "'";
当它变成:时仍然返回所有用户:
var query = "SELECT * FROM users WHERE name ='" + userName + "'";
N1QL 评论
N1QL 的注释系统使用 C 风格的注释块(/* comment */)而不是使用“--”来注释掉该行的剩余部分。这可以保护 N1QL 免受一些更高级的注入攻击。由于 N1QL 需要结束注释 */,攻击者无法在不导致语法错误的情况下注释掉部分查询。
但是请注意,这取决于开发人员不在他们的查询中留下评论。如果查询文本中有评论,用户现在可以使用一个结束评论块来利用他们的优势:
var query = "SELECT * FROM users WHERE name ='" + userName + "'";
可以注入“OR 1=1 /*”:
var query = "SELECT * FROM users WHERE name ='" + userName + "'";
与 SQL 示例一样,组限制现在已从查询中删除。
N1QL 标识符注入
Couchbase 的无模式文档模型实际上创造了一个有趣的新攻击领域。使用 SQL 时,很少在查询的 WHERE 或 ORDER BY 子句以外的任何地方包含用户输入。这是因为表名和列名是众所周知的并且不会更改。
然而,Couchbase 文档缺少模式意味着开发人员可能会想要允许用户控制他们从文档中选择的字段。
var query = "SELECT * FROM users WHERE name ='" + userName + "'";
注入后变成:
var query = "SELECT * FROM users WHERE name ='" + userName + "'";
现在,攻击者可以从开发人员指定的用户文档中没有的相关密码文档访问数据。
如何保护您的应用程序
幸运的是,保护您的应用程序免受 N1QL 注入攻击与保护您的应用程序免受 SQL 注入攻击一样容易。以下是一些使安全变得容易的准则。这些示例使用 C# 编写,但这些概念同样适用于任何其他语言。
-
最佳实践:
不是将用户输入直接插入查询,而是使用命名或位置参数作为保护。通过这种方式,用户输入永远不会直接添加到您的查询中,从而提供 100% 的针对所有注入攻击的保护。
应该:var query = "SELECT * FROM users WHERE name ='" + userName + "'";
var query = "SELECT * FROM users WHERE name ='" + userName + "'";
-
如果您确实将用户输入的字符串插入到您的查询中,请始终对引号进行转义。将单引号 (') 的任何实例替换为两个单引号 ('')。
应该:var query = "SELECT * FROM users WHERE name ='" + userName + "'";
var query = "SELECT * FROM users WHERE name ='" + userName + "'";
-
将用户输入标识符插入查询时,请始终使用刻度线 (`) 对标识符进行转义。然后用两个刻度 (``) 替换输入中任何一个刻度的实例。请注意,标识符没有等效的命名参数,因此转义标识符是最好的解决方案。
应该:var query = "SELECT * FROM users WHERE name ='" + userName + "'";
var query = "SELECT * FROM users WHERE name ='" + userName + "'";
-
如果您实施其他规则,您也可以免受基于评论的攻击。但是,针对包含用户输入的查询中的评论的辅助策略可以提供额外的保护,以防开发人员忘记其他规则。相反,只需将任何注释放在应用程序代码中而不是查询本身。
应该:var query = "SELECT * FROM users WHERE name ='" + userName + "'";
var query = "SELECT * FROM users WHERE name ='" + userName + "'";
要在 C# 中查看这些攻击及其保护方法的示例,请参阅此 GitHub 存储库:https: //github.com/brantburnett/N1QlInjection 。请注意,您需要在本地安装 Couchbase 并安装 beer-sample 才能运行测试。
结论
虽然 N1QL 容易受到注入攻击,但这个漏洞并不比 SQL 中众所周知的漏洞更糟。此外,开发人员很容易防止注入攻击。因此,N1QL 为使用 Couchbase NoSQL 数据库开发安全应用程序提供了一个出色的平台。