【问题标题】:Transparently encoding/decoding `$` and `.` when inserting/retrieving documents in MongoDB在 MongoDB 中插入/检索文档时透明地编码/解码 `$` 和 `.`
【发布时间】:2016-11-18 06:56:05
【问题描述】:

我正在开发一个用 Python 编写的 API,它接受来自客户端的 JSON 负载,应用一些验证并将负载存储在 MongoDB 中,以便可以异步处理它们。

但是,对于(合法地)包含以$ 开头和/或包含. 的密钥的有效负载,我遇到了一些问题。 According to the MongoDB documentation,我最好的办法是避开这些字符:

在某些情况下,您可能希望使用用户提供的密钥构建 BSON 对象。在这些情况下,密钥需要替换保留的$. 字符。任何字符都足够,但请考虑使用 Unicode 全宽等效字符:U+FF04(即“$”)和U+FF0E(即“.”)。

很公平,但这就是有趣的地方。我希望这个过程对应用程序是透明的,所以:

  • 检索文档时,密钥应该是非转义的...
  • ...但只有首先需要转义的键。

例如,假设一个(邪恶的)用户发送了一个 JSON 有效负载,其中包含一个像 \ff04mixed.chars 这样的密钥。当应用程序从存储后端获取此文档时,应将此密钥转换回\ff04mixed.chars不是 $mixed.chars

我主要关心的是信息泄露;我不希望有人发现应用程序需要对 $. 字符进行特殊处理。坏人可能比我知道如何保护它更好地利用 MongoDB,我不想冒险。

【问题讨论】:

    标签: python mongodb escaping pymongo


    【解决方案1】:

    这是我最终采用的方法:

    • 在将文档插入 Mongo 之前,通过 SONManipulator 运行它,以搜索并转义文档中的任何非法键。
      • 原始密钥作为单独的属性存储在文档中,以便我们以后可以恢复它们。
    • 从 Mongo 检索文档后,通过 SONManipulator 运行它以提取原始密钥并恢复它们。

    这是一个简短的例子:

    # Example of a document with naughty keys.
    document = {
        '$foo': 'bar',
        '$baz': 'luhrmann'
    }
    
    ##
    # Before inserting the document, we must first run it through our
    #   SONManipulator.
    manipulator = KeyEscaper()
    escaped = manipulator.transform_incoming(document, collection.name)
    
    # Now we can insert the document.
    document_id = collection.insert_one(escaped).inserted_id
    
    ##
    # Later, we retrieve the document.
    raw = collection.find_one({'_id': document_id})
    
    # Run the document through our KeyEscaper to restore the original
    #   keys.
    unescaped = manipulator.transform_outgoing(raw, collection.name)
    
    assert unescaped == document
    

    存储在 MongoDB 中的实际文档如下所示:

    {
      "_id": ObjectId('582cebe5cd9b344c814d98e3')
    
      "__escaped__1": "luhrmann",
      "__escaped__0": "bar",
    
      "__escaped__": {
        "__escaped__1": ["$baz", {}],
        "__escaped__0": ["$foo", {}]
      }
    }
    

    注意包含原始键的__escaped__ 属性,以便在检索文档时可以恢复它们。

    这使得查询转义键有点棘手,但这比无法存储文档要好得多。

    带有单元测试和示例用法的完整代码:
    https://gist.github.com/todofixthis/79a2f213989a3584211e49bfba582b40

    【讨论】:

      猜你喜欢
      • 2011-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-25
      • 2012-06-12
      • 1970-01-01
      相关资源
      最近更新 更多