使用PyMongo时如何正确sanitize含$in的查询以规避注入风险
解决mongosanitizer过滤合法MongoDB操作符的问题
问题根源
mongosanitizer的默认sanitize行为会过滤所有以$开头的键——这类键多为MongoDB操作符,工具默认认为用户输入中不应包含此类内容以防范NoSQL注入。但像$in这类合法查询操作符被误过滤后,就会导致数组查询失效。
解决方案
1. 显式指定允许保留的合法操作符
调用sanitize时,通过allowed_keys参数传入需要保留的操作符列表,让工具仅过滤非法键,保留合法的MongoDB操作符。
示例代码:
from mongosanitizer.sanitizer import sanitize from bson.objectid import ObjectId # 定义业务中需要用到的合法MongoDB操作符 ALLOWED_OPERATORS = {'$in', '$eq', '$ne', '$gt', '$lt'} # 处理用户输入的ID列表,先验证并转换为ObjectId valid_req_ids = [] for id_str in user_provided_ids: if ObjectId.is_valid(id_str): valid_req_ids.append(ObjectId(id_str)) # 非法ID可选择跳过或抛出错误处理 # 构造查询语句 find_query = {"_id": {"$in": valid_req_ids}} # 执行 sanitize,保留允许的操作符 sanitize(find_query, allowed_keys=ALLOWED_OPERATORS) # 执行数据库操作 e = client[db_name]['request'].find_one_and_update( filter=find_query, update={'$unset': reset_data}, return_document=ReturnDocument.AFTER )
2. 提前严格验证用户输入
无论是否使用sanitize,都要确保用户提供的ID是合法的ObjectId:
- 用
ObjectId.is_valid()验证格式合法性 - 非法ID直接过滤或抛出异常,避免恶意输入进入查询逻辑
3. 避免过度依赖sanitize
PyMongo本身支持参数化查询,只要不直接拼接查询字符串,而是使用PyMongo的查询对象(比如用ObjectId转换用户ID),就能有效防范NoSQL注入。原单条ID查询中ObjectId(request_id)的写法本身就是安全的,非法ID会直接抛出异常。
注意事项
allowed_keys只添加业务实际需要的操作符,不要盲目添加大量操作符,避免引入安全风险- 自定义的更新操作符(比如代码中的
$unset)属于固定逻辑,不是用户输入内容,无需用sanitize处理
内容的提问来源于stack exchange,提问作者rcs
相关产品推荐
相关产品推荐

