Flask中不能直接在路由里做敏感词过滤,因重复代码多、易漏检、难统一响应格式,且无法覆盖所有入口;应使用WSGI中间件或before_request钩子在请求进入视图前拦截,中间件更底层可靠,职责仅为阻断而非清洗。

Flask 中为什么不能直接在路由里做敏感词过滤
因为重复代码多、易漏检、难统一响应格式。比如每个 @app.route 都要写一遍 check_sensitive_words(text),一旦新增接口或修改策略就得逐个改,还容易忘记加。更麻烦的是,前端可能通过不同入口(表单、API、WebSocket 代理)提交数据,光靠路由层覆盖不全。
真正该拦截的位置是请求刚进来、还没进视图函数之前——也就是 WSGI 层或 Flask 的请求钩子。中间件(Middleware)在这里比装饰器更底层、更可靠。
用 Werkzeug Middleware 实现轻量级敏感词过滤
Flask 基于 Werkzeug,可以直接包装 app.wsgi_app。这种方式不依赖 Flask 扩展,兼容所有 Flask 版本(包括 2.x / 3.x),且对请求体(request.get_data())、JSON、form-data 都能统一处理。
- 只在
Content-Type为application/json、application/x-www-form-urlencoded或multipart/form-data时触发过滤 - 对 JSON 请求:递归遍历字典/列表中的字符串值,替换或标记
- 对 form-data:检查
request.form和request.files的文件名(常被用来传恶意 payload) - 命中敏感词后,返回
400 Bad Request并附带错误字段,不进业务逻辑
示例中间件核心逻辑:
立即学习“Python免费学习笔记(深入)”;
class SensitiveWordMiddleware:
def __init__(self, app, words=None):
self.app = app
self.words = words or ["admin", "passwd", "sqlmap"]
<pre class="brush:php;toolbar:false;">def __call__(self, environ, start_response):
# 只处理 POST/PUT/PATCH 请求
if environ.get("REQUEST_METHOD") not in ("POST", "PUT", "PATCH"):
return self.app(environ, start_response)
# 尝试解析 body(注意:不能多次调用 get_data())
try:
data = environ.get("wsgi.input").read(int(environ.get("CONTENT_LENGTH", 0)))
environ["wsgi.input"] = io.BytesIO(data)
# 后续 request.get_data() 仍可正常工作
except Exception:
return self.app(environ, start_response)
# 检查 data 是否含敏感词(按需实现检测逻辑)
if self._contains_sensitive(data):
start_response("400 Bad Request", [("Content-Type", "application/json")])
return [b'{"error": "sensitive word detected"}']
return self.app(environ, start_response)
火焰围攻 授权: q15040409-creator.功能概述火焰围攻 授权: q15040409-creator.是一项面向实际任务的技能,主要用于Description.;Flask Web. - Python.;核心要点HTTP?;.Version.1.0.tags. wrap.github.automation.。它将相关步骤、工具调用和结果整理方式集中到统一流程中,帮助使用者更快完成目标并减少重复操作。使用与执行使用时应结合输入条件选择合适的执行方式,核对必要参数、依赖环境与输出内容,并按原始要
用 before_request + request.get_json() 做快速兜底方案
如果项目已上线、不敢动 WSGI 层,可用 Flask 自带的 @app.before_request 钩子,但要注意它无法拦截 request.files 的原始二进制内容,也不能阻止文件上传完成——只适合文本类校验。
- 必须在
request.get_json()或request.form.to_dict()之后检查,否则会触发ValueError: request.get_json() not supported - 不要在钩子里调用
request.get_data(),会导致后续视图函数读不到 body - 敏感词库建议预编译成
re.compile('|'.join(map(re.escape, words))),避免每次匹配都重编译 - 对中文场景,记得加
re.UNICODE标志,否则\w不匹配汉字
典型误用:if "password" in request.get_json().values() —— 这种写法漏掉嵌套字段、不支持列表、且没做大小写/全角半角归一化。
敏感词替换与响应控制的边界在哪
中间件的职责是「阻断」,不是「清洗」。很多团队想让中间件自动把 "fuck" 替成 "f**k" 再放行,这会导致两个问题:
- 替换后的数据和原始请求不一致,审计日志、签名验证、幂等性校验全失效
- 前端传的是 base64 图片,中间件误把 base64 字符串当文本过滤,导致图片损坏
真要替换,请在业务逻辑层(如 model.save() 前)做,且必须明确记录“该字段已被脱敏”。中间件只做判断和拦截,这是职责分离的关键分界线。
另外,正则匹配性能差、AC 自动机又太重,中小项目用前缀树(Trie)+ Python 字典实现即可,10 万词下平均匹配耗时在 0.02ms 级别,远低于一次数据库查询。

















