本页介绍使用 MongoDB 客户端库开发应用程序的最佳实践。遵循这些建议,以降低在您的应用程序处理不可信输入时可能出现的注入攻击和其他安全问题的风险。
使用 SRV 连接字符串
当您的部署支持时,请使用 mongodb+srv:// 连接字符串格式,而不是标准 mongodb:// 格式。+srv 格式会自动启用连接的 Transport Layer Security (TLS),默认情况下加密应用程序与 MongoDB 部署之间的流量。标准格式不会启用 TLS,除非您明确设置它。
+srv 格式还可以从 DNS SRV 记录中解析出完整的种子托管列表。当根本的托管发生变化时,您的连接字符串不需要更新。
警告
驱动程序信任与原始种子主机名共享相同父域的 SRV 查找结果。示例,对 foo.example.com 的查找可能会返回 node1.foo.example.com。它也可能返回 node1.example.com,它共享 example.com 父域,即使它不在 foo.example.com 下。
恶意或已受损的 DNS 服务器可能会尝试将您的应用程序重定向到攻击者控制的托管,在连接设置过程中。父域限制降低了这种风险。验证种子主机名的父域仅解析为集群中的托管,或解析为由同一可信实体控制的集群。
To learn more, see SRV Connection Format and Connection Strings in the MongoDB Server manual.
在将 JSON 转换为 BSON 之前验证不受信任的输入
许多客户端库提供一种便捷方法,可将 JSON string 转换为 BSON 文档,例如通过 Extended JSON。如果您的应用程序在未经验证的情况下将结果文档传递到查询、更新或命令中,攻击者可以更改该操作的含义。
考虑一个 API 终结点,它接受 JSON 请求主体,并预期包含 string 值的 name 字段。假设终结点将请求正文转换为 BSON,并将结果用于查询筛选条件,未经验证。攻击者可以提交一个对象代替预期的 string,如以下示例所示:
{"name": {"$ne": null}}
MongoDB 将 $ne 字段评估为查询操作符,而不是字面值。此过滤器不会按名称匹配单个文档,而是匹配每个具有非空 name 字段的文档,从而暴露了比预期更多的数据。
在将不可信输入转换为 BSON 之前,将其拼接到 JSON string 中会产生相同的风险。以下 C++ 示例通过使用 string 连接将用户提供的值插入到 JSON string 中来构建查询筛选条件:
std::string json_query = "{ \"name\": \"" + user_supplied_name + "\" }"; bsoncxx::document::value filter = bsoncxx::from_json(json_query); mongocxx::cursor cursor = collection.find(filter.view());
如果 user_supplied_name 包含双引号或 JSON 操作符,则生成的 string 可以逃避预期的字段值并注入任意的查询语法。
当 JSON string 源自用户、API 请求或您的应用程序无法控制的其他来源时,此风险即应用。为了降低这种风险,在将不可信的输入转换为 BSON 之前,请先进行类型检查和验证。许多驱动程序提供类型化文档 API 或查询构建者,您可以使用它来构建查询。您还可以在接受用于转换的 JSON 输入之前,在应用程序内应用 JSON schema 或类似的验证层。
以下示例构建与上述连接示例相同的过滤器,但是使用了一个强类型文档构建者:
bsoncxx::builder::basic::document filter_builder; filter_builder.append( bsoncxx::builder::basic::kvp("name", user_supplied_name)); mongocxx::cursor cursor = collection.find(filter_builder.view());
由于构建者将 user_supplied_name 视为一个值,而不是要解析的 string 的一部分,因此该值无法更改查询的结构。
Building queries as BSON documents instead of strings avoids traditional SQL injection, since attackers have no query string to manipulate. To learn more, see FAQ: MongoDB Fundamentals in the MongoDB Server manual. To learn more about Extended JSON types and conversions, see MongoDB Extended JSON in the MongoDB Server manual.
限制服务器端 JavaScript 执行
MongoDB supports operators and commands that execute JavaScript, including $where, $function, $accumulator, and mapReduce. When your application builds one of these expressions from user input, the server executes that input as code. This behavior creates the same class of risk as passing untrusted input to an eval function in application code.
为了降低这一风险,请遵循以下建议:
避免 string 连接:不要通过将不受信任的输入连接或插值到 JavaScript string 中来构建
$where表达式、$function主体或$accumulator函数。请改用标准查询操作符,因为 MongoDB 会对其进行评估而无需执行 JavaScript。Disable server-side scripting: Disable server-side scripting if your application doesn't use
$where,$function,$accumulator, ormapReduce. Set thesecurity.javascriptEnabledconfiguration option tofalse, or start themongodormongosprocess and pass the--noscriptingoption.
To learn more about securing server-side JavaScript execution, see Run MongoDB with Secure Configuration Options.
To learn more about the $where operator, see $where in the MongoDB Server manual.
更多信息
For a list of best practices on securing self-managed deployments, see the Security Checklist in the MongoDB Server manual.