应禁用原始html并用bleach二次清洗:先用markdown库渲染,再以白名单过滤标签和属性,如['p','h1','h2','code','pre','ul','li'],并限制rel、class等属性,避免依赖已弃用的safe_mode参数。

Flask 中如何安全地将 Markdown 渲染为 HTML?
直接用 markdown 库(如 markdown 或 markdown2)渲染用户输入的 Markdown 是危险的——它默认允许 HTML 标签,可能引发 XSS。必须禁用原始 HTML 并启用安全扩展。
- 推荐使用
markdown+markdown.extensions.extra+markdown.extensions.codehilite,但务必设置safe_mode=True(旧版)或更可靠的extensions=['extra', 'codehilite']配合output_format='html'和extension_configs控制输出 - 更稳妥的做法是用
bleach二次清洗:先渲染,再用bleach.clean()白名单过滤标签和属性,例如只保留['p', 'h1', 'h2', 'code', 'pre', 'ul', 'li'],并限制rel、class等属性 - 别依赖
markdown的safe_mode参数(已弃用),新版markdownv3.0+ 不再支持,硬写会静默失效
如何在 Flask 路由中动态渲染 Markdown 文件?
常见做法是把文章存为 .md 文件,读取后渲染。但路径处理和编码容易出错。
- 用
os.path.join(app.root_path, 'posts', filename)拼接路径,避免硬编码或相对路径越界(比如用户传../../etc/passwd) - 校验文件名:只接受字母、数字、下划线、短横线,拒绝含
..、/、\0的输入,可用正则re.match(r'^[a-zA-Z0-9_-]+\.md$', filename) - 读取时显式指定
encoding='utf-8',否则 Windows 下可能报UnicodeDecodeError - 渲染后塞进 Jinja2 模板时,用
{{ content|safe }}—— 但前提是前面已确保内容可信,否则仍会执行恶意脚本
怎样让代码块支持语法高亮且不崩样式?
codehilite 扩展依赖 Pygments,但默认生成的 CSS 类名(如 highlight)和你的前端样式不匹配,导致代码块空白或错位。
- 启用
codehilite时加配置:extension_configs={'codehilite': {'css_class': 'highlight', 'guess_lang': False}},确保类名可控 - 手动导出 Pygments CSS:
pygmentize -S default -f html -a .highlight > static/css/pygments.css,然后引入该 CSS - 若用 Tailwind 或其他原子 CSS 框架,别指望
codehilite自动适配;改用highlight.js客户端渲染,服务端只保留<pre class="brush:php;toolbar:false;"><code class="python"></code> 结构,不生成内联样式</pre>
为什么编辑保存后页面没更新?缓存和模板怎么协同?
Markdown 文件变更后,Flask 开发服务器不会自动重载渲染结果,因为读取文件是运行时行为,不是模板热重载范畴。
- 开发阶段可在视图函数里加
if app.debug:判断,每次请求都重新读取文件(线上关掉) - 生产环境建议加一层简单缓存键,比如
cache_key = f'md_{filename}_{os.path.getmtime(filepath)}',用flask-caching缓存渲染结果,文件变动时键自动失效 - Jinja2 模板本身不缓存 Markdown 内容,但若用了
@app.template_filter('markdown')自定义过滤器,注意该函数不能缓存跨请求数据(比如全局 dict 存渲染结果),否则并发下会脏读
真正麻烦的不是渲染逻辑,而是 Markdown 输入的边界控制——比如缩进四个空格触发代码块、列表嵌套层级、HTML 实体转义是否保留。这些细节不测到真实用户输入,很容易漏掉。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











