Flask中如何通过数组查询参数构造NoSQL注入?
Flask中构造MongoDB NoSQL注入的问题解答
Flask完全支持构造MongoDB NoSQL注入,你遇到的问题只是参数解析方式的差异,而非语言本身限制——NoSQL注入本质是应用将用户可控输入直接作为查询条件使用,和开发语言无关,Python/Flask、NodeJS、PHP等都可能存在这类漏洞。
问题原因
Flask的request.args默认会将URL参数解析为扁平的键值对,不会自动识别name["$ne"]这种格式的嵌套结构。当你访问http://localhost:3214/get_test?name["$ne"]=test时,实际拿到的参数键是字符串"name['$ne']",而非嵌套的name.$ne,所以用request.args.get("name")会返回None。
解决方法:手动解析嵌套参数
要实现预期的嵌套查询结构,你需要手动解析参数键,将类似name[$ne]的格式转换为MongoDB可识别的嵌套字典。示例代码如下:
from flask import Flask, request from pymongo import MongoClient app = Flask(__name__) client = MongoClient("mongodb://localhost:27017/") db = client["test_db"] collection = db["test_col"] def parse_nested_query(args): query = {} for raw_key, value in args.items(): # 处理形如key[operator]的参数格式 if "[" in raw_key and "]" in raw_key: main_field, op = raw_key.split("[", 1) op = op.rstrip("]") # 构建嵌套查询条件 if main_field not in query: query[main_field] = {} query[main_field][op] = value else: query[raw_key] = value return query @app.route("/get_test") def get_test(): # 解析用户传入的参数为MongoDB查询格式 user_query = parse_nested_query(request.args) # 直接将用户查询传入MongoDB(这就是存在注入风险的写法) result = collection.find_one(user_query) return str(result) if result else "No data found" if __name__ == "__main__": app.run(port=3214)
当你访问http://localhost:3214/get_test?name[$ne]=test时,parse_nested_query会生成{'name': {'$ne': 'test'}},直接传入find_one后,就会返回所有name不等于test的文档——这就是典型的NoSQL注入场景。
补充说明
request.args.to_dict()同样返回扁平结构,无法直接得到嵌套字典,必须手动处理。mongo-query-manager这类库通常需要特定的参数格式配合,手动解析反而更直接可控。- 实际开发中绝对禁止直接将用户输入作为MongoDB查询条件,必须对输入进行过滤、验证,或使用参数化查询方式避免注入风险。
内容的提问来源于stack exchange,提问作者Dump Eldor
相关产品推荐
相关产品推荐

