本页介绍使用MongoDB客户端端库开发应用程序的最佳实践。请遵循这些建议,以降低应用程序处理不可信输入时可能出现的注入攻击和其他安全问题的风险。
使用 SRV 连接字符串
如果您的部署支持,请使用 mongodb+srv://连接字符串格式而不是标准 mongodb:// 格式。 +srv 格式会自动为连接启用传输层安全性 (TLS),从而默认对应用程序与MongoDB 部署之间的流量进行加密。除非您明确设立,否则标准格式不会启用TLS。
+srv 格式还可以从 DNS SRV记录中解析种子主机的完整列表。当根本的主机发生变化时,您的连接字符串不需要更新。
警告
驱动程序信任与原始种子主机名股票相同父域的 SRV 查找结果。示例,查找 foo.example.com 可能会返回 node1.foo.example.com。它还可能返回 node1.example.com,尽管它不在 foo.example.com 下,但它共享 example.com 父域。
恶意或受损的 DNS服务器可能会在连接设置期间尝试将您的应用程序重定向到攻击者控制的托管。父域限制限制了这种风险。确认种子主机名的父域仅解析为集群中的主机,或由同一受信任实体控制的集群。
要学习;了解更多信息,请参阅MongoDB Server手册中的 SRV 连接格式和连接字符串。
在将JSON转换为BSON之前验证不可信输入
许多客户端端库都提供了一种将JSON字符串转换为BSON文档的便捷方法,示例通过扩展JSON。如果您的应用程序在未经验证下将生成的文档传递到查询、更新或命令中,则攻击者可以更改该操作的含义。
考虑一个API端点,它接受JSON请求正文并需要一个包含字符串值的 name字段。假设端点将请求正文转换为BSON ,并在查询过滤中使用结果而不验证。攻击者可以提交一个对象来代替预期的字符串,如以下示例所示:
{"name": {"$ne": null}}
MongoDB将 $ne字段作为查询运算符符而不是字面值进行计算。此过滤不是按名称匹配单个文档,而是匹配具有非空 name字段的每个文档,从而暴露了比预期更多的数据。
在将不受信任的输入转换为BSON之前将其连接到JSON字符串也会产生同样的风险。以下C++示例通过使用字符串连接将用户提供的值插入到JSON字符串中来构建查询过滤:
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操作符,则生成的字符串可以转义预期的字段值并注入任意查询语法。
每当JSON字符串源自用户、 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 视为一个值,而不是要解析的字符串的一部分,因此该值无法更改查询的结构。
将查询构建为BSON文档而不是字符串可以避免传统的SQL注入,因为攻击者没有可以操作的查询字符串。要学习;了解更多信息,请参阅MongoDB Server手册中的常见问题解答: MongoDB基础知识。要学习;了解有关扩展JSON类型和转换的更多信息,请参阅MongoDB Server手册中的MongoDB扩展JSON 。
限制服务器端JavaScript执行
MongoDB支持执行JavaScript 的操作符和命令,包括 $where、$function、$accumulator 和 mapReduce。当应用程序根据用户输入构建这些表达式之一时,服务器会将该输入作为代码执行。这种行为造成的风险与将不可信输入传递给应用程序代码中的 eval 函数属于同一类风险。
为降低此风险,请遵循以下建议:
避免字符串连接:不要通过将不受信任的输入连接或插入到JavaScript字符串中来构建
$where表达式、$function主体或$accumulator函数。请改用标准查询运算符,因为MongoDB会在不执行JavaScript 的情况下对它们求值。禁用服务器端脚本:如果您的应用程序不使用
$where、$function、$accumulator或mapReduce,请禁用服务器端脚本。将security.javascriptEnabled配置选项设置为false,或者启动mongod或mongos进程并传递--noscripting选项。