背景与价值
NoSQL注入常通过构造非法算子与键。统一白名单与键过滤可防止绕过与非法查询。
统一规范
- 算子白名单:仅允许受控算子如 `$eq/$in/$gte/$lte`。
- 键过滤:拒绝包含 `.` 或以 `$` 开头的键。
- 分页限制:统一页大小与最大偏移,防止资源耗尽。
核心实现
算子与键过滤
```ts
type Query = Record
const allowOps = new Set(['$eq','$in','$gte','$lte','$ne'])
function validKey(k: string): boolean { return !k.startsWith('$') && !k.includes('.') && /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(k) }
function filterQuery(q: Query): Query {
const out: Query = {}
for (const [k, v] of Object.entries(q)) {
if (!validKey(k)) continue
if (v && typeof v === 'object' && !Array.isArray(v)) {
const sub: Record = {}
for (const [op, val] of Object.entries(v)) if (allowOps.has(op)) sub[op] = val
out[k] = sub
} else {
out[k] = v
}
}
return out
}
```
分页限制与类型校验
```ts
type Page = { page: number; size: number }
function normalizePage(p: Page): Page { const size = Math.min(100, Math.max(1, Math.floor(p.size || 20))); const page = Math.max(1, Math.floor(p.page || 1)); return { page, size } }
function validValue(v: any): boolean { if (typeof v === 'string') return v.length <= 1024; if (typeof v === 'number') return Number.isFinite(v); if (Array.isArray(v)) return v.length <= 100; return true }
function sanitize(q: Query): Query { const out: Query = {}; for (const [k, v] of Object.entries(filterQuery(q))) { if (validValue(v)) out[k] = v }; return out }
```
落地建议
- 在入口统一执行键过滤与算子白名单,拒绝非法键与算子。
- 执行分页与类型限制,避免超大数组与过长字符串造成资源耗尽。
- 审计拒绝查询与异常输入,便于优化与防御策略迭代。
验证清单
- 查询是否仅包含白名单算子与合法键。
- 分页与类型是否在限制范围内。
发表评论 取消回复