Mongo C++ 驱动程序能够绕过文档结构规则(关于键不以 $ 开头的规则)
Mongo C++ driver is able to bypass document structure rules (the one about keys not starting with $)
如果我尝试在 MongoDB 中插入一个文档,其中的某个键以 $
开头,我会收到一条错误消息:
> db.x.insert({"a": {"$b": "1"}})
2016-09-29T21:14:23.078+0200 E QUERY [thread1] Error: field names cannot start with $ [$b] :
...
(我有观察者使用 Node.js 驱动程序有类似的行为)
但是,运行 下面的 C++ 程序:
#include <cstdlib>
#include <iostream>
#include "mongo/client/dbclient.h" // for the driver
// compile with: g++ test.cpp -pthread -lmongoclient -lboost_thread -lboost_system -lboost_regex -o test
void run() {
mongo::DBClientConnection c;
c.connect("localhost");
mongo::BSONObj doc = BSON("a" << BSON("$b" << 1));
c.insert("test.x", doc);
}
int main() {
mongo::client::initialize();
try {
run();
} catch( const mongo::DBException &e ) {
std::cout << "caught " << e.what() << std::endl;
}
return EXIT_SUCCESS;
}
我可以插入它,如 find()
所示:
> db.x.find()
{ "_id" : ObjectId("57ed67fdbf3a716e16f6d102"), "a" : { "$b" : 1 } }
由此看来,C++驱动程序似乎能够"bypass"描述in MongoDB documentation的文档结构规则。这种行为有什么解释吗?它可以 "break" MongoDB 数据库以某种方式(我想这个限制是有充分理由的,数据库中的文档不遵守它可能会有问题)
我观察到只有当 $
的键不在第一级时才会发生这种情况。例如,如果我使用
mongo::BSONObj doc = BSON("$b" << 1);
然后我得到一个一致的错误
caught OperationException: { index: 0, code: 2, errmsg: "Document can't have $ prefixed field names: $b", op: { _id: ObjectId('57ed6a015365c193cbbb3231'), $b: 1 } }
为了以防万一,我使用的是 MongoDB 3.2.0 和旧版 C++ 驱动程序 1.0.7
从 MongoDB 3.2 开始,服务器会在文档的顶层对键名执行一些插入时验证(包括禁止它们以美元符号字符开头),但它不会验证子文档中的任何键名。请参阅 https://jira.mongodb.org/browse/SERVER-10987 跟踪请求以验证子文档中的键名。
一些驱动程序执行额外的键名称验证(例如,shell 和 Node.js 驱动程序检查文档中所有键开头的美元符号字符以进行插入),但是设置目前,驱动程序之间的验证规则不一致。巧合的是,在 https://jira.mongodb.org/browse/DRIVERS-308 的 JIRA 中,DRIVERS 项目(用于以一致的方式协调所有驱动程序的新功能和改进)中有一个相对较新的票证,其中包括尝试指定客户端验证应在插入时执行。如果该票证最终得到推进,那么肯定会在最新版本的 C++ 驱动程序中进行修复(请注意,遗留驱动程序最近只收到关键错误修复)。
就带美元符号的键名而言:服务器可以很好地存储和检索它们,但它们不能很好地与其他数据库功能配合使用。参见,例如:
> db.version()
3.2.10
> db.collection.find()
{ "_id" : 1, "a" : { "$b" : 1 } }
> db.collection.update({_id: 1}, {$set: {"a.$b": 2}})
WriteResult({
"nMatched" : 0,
"nUpserted" : 0,
"nModified" : 0,
"writeError" : {
"code" : 52,
"errmsg" : "The dollar ($) prefixed field '$b' in 'a.$b' is not valid for storage."
}
})
如果我尝试在 MongoDB 中插入一个文档,其中的某个键以 $
开头,我会收到一条错误消息:
> db.x.insert({"a": {"$b": "1"}})
2016-09-29T21:14:23.078+0200 E QUERY [thread1] Error: field names cannot start with $ [$b] :
...
(我有观察者使用 Node.js 驱动程序有类似的行为)
但是,运行 下面的 C++ 程序:
#include <cstdlib>
#include <iostream>
#include "mongo/client/dbclient.h" // for the driver
// compile with: g++ test.cpp -pthread -lmongoclient -lboost_thread -lboost_system -lboost_regex -o test
void run() {
mongo::DBClientConnection c;
c.connect("localhost");
mongo::BSONObj doc = BSON("a" << BSON("$b" << 1));
c.insert("test.x", doc);
}
int main() {
mongo::client::initialize();
try {
run();
} catch( const mongo::DBException &e ) {
std::cout << "caught " << e.what() << std::endl;
}
return EXIT_SUCCESS;
}
我可以插入它,如 find()
所示:
> db.x.find()
{ "_id" : ObjectId("57ed67fdbf3a716e16f6d102"), "a" : { "$b" : 1 } }
由此看来,C++驱动程序似乎能够"bypass"描述in MongoDB documentation的文档结构规则。这种行为有什么解释吗?它可以 "break" MongoDB 数据库以某种方式(我想这个限制是有充分理由的,数据库中的文档不遵守它可能会有问题)
我观察到只有当 $
的键不在第一级时才会发生这种情况。例如,如果我使用
mongo::BSONObj doc = BSON("$b" << 1);
然后我得到一个一致的错误
caught OperationException: { index: 0, code: 2, errmsg: "Document can't have $ prefixed field names: $b", op: { _id: ObjectId('57ed6a015365c193cbbb3231'), $b: 1 } }
为了以防万一,我使用的是 MongoDB 3.2.0 和旧版 C++ 驱动程序 1.0.7
从 MongoDB 3.2 开始,服务器会在文档的顶层对键名执行一些插入时验证(包括禁止它们以美元符号字符开头),但它不会验证子文档中的任何键名。请参阅 https://jira.mongodb.org/browse/SERVER-10987 跟踪请求以验证子文档中的键名。
一些驱动程序执行额外的键名称验证(例如,shell 和 Node.js 驱动程序检查文档中所有键开头的美元符号字符以进行插入),但是设置目前,驱动程序之间的验证规则不一致。巧合的是,在 https://jira.mongodb.org/browse/DRIVERS-308 的 JIRA 中,DRIVERS 项目(用于以一致的方式协调所有驱动程序的新功能和改进)中有一个相对较新的票证,其中包括尝试指定客户端验证应在插入时执行。如果该票证最终得到推进,那么肯定会在最新版本的 C++ 驱动程序中进行修复(请注意,遗留驱动程序最近只收到关键错误修复)。
就带美元符号的键名而言:服务器可以很好地存储和检索它们,但它们不能很好地与其他数据库功能配合使用。参见,例如:
> db.version()
3.2.10
> db.collection.find()
{ "_id" : 1, "a" : { "$b" : 1 } }
> db.collection.update({_id: 1}, {$set: {"a.$b": 2}})
WriteResult({
"nMatched" : 0,
"nUpserted" : 0,
"nModified" : 0,
"writeError" : {
"code" : 52,
"errmsg" : "The dollar ($) prefixed field '$b' in 'a.$b' is not valid for storage."
}
})