string.Template 更安全因其仅支持 $name 和 ${name} 语法,不解析表达式、属性或嵌套结构,杜绝代码注入;需配合白名单变量与 safe_substitute() 使用。

string.Template 为什么比 % 和 f-string 更安全
因为 string.Template 默认只支持 $name 和 ${name} 两种变量语法,不执行任意 Python 表达式,也不解析嵌套结构或属性访问。比如传入 ${__import__('os').system('rm -rf /')} 会被原样保留为字面量,不会触发执行 —— 这是它防注入的核心机制。
而 % 格式化和 f-string 在拼接用户输入时,若未严格过滤,极易导致代码执行、路径遍历或 SQL 注入等风险(尤其当模板逻辑混入动态计算时)。
正确用法:只允许白名单变量名 + 显式 safe_substitute()
必须用 safe_substitute() 而非 substitute(),前者对缺失键静默跳过,后者抛 KeyError,而异常可能暴露内部结构或被用于探测变量名。
-
Template实例化后,变量名只能是字母、数字、下划线,且不能以数字开头;$1var或${.attr}会直接报ValueError: Invalid placeholder - 传入的 mapping 必须是 dict 或支持
.get()的对象,推荐用dict.fromkeys(whitelist, '')初始化再更新可信值 - 避免把用户原始输入直接塞进 mapping —— 应先清洗:例如用
re.sub(r'[^a-zA-Z0-9_]', '_', user_input)规范化键名
from string import Template
<p>tpl = Template('Hello $name, welcome to ${site}!')</p><div class="aritcle_card flexRow">
<div class="artcardd flexRow">
<a class="aritcle_card_img" href="/xiazai/skill11458" title="librosa Python 音频与音乐分析库"><img
src="https://img.php.cn/upload/skill/001/246/273/6adaf20d79f23518.jpg" alt="librosa Python 音频与音乐分析库" ></a>
<div class="aritcle_card_info flexColumn">
<a href="/xiazai/skill11458" title="librosa Python 音频与音乐分析库">librosa Python 音频与音乐分析库</a>
<p>librosa 是一个用于音频和音乐分析的 Python 库。它提供了特征提取、频谱分析、节拍跟踪、起始检测和音频可视化的工具,基于 NumPy 和 SciPy 构建,用于科学音频计算。</p>
</div>
<a href="/xiazai/skill11458" title="librosa Python 音频与音乐分析库" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</div>
</div><p><span>立即学习</span>“<a href="https://pan.quark.cn/s/00968c3c2c15" style="text-decoration: underline !important; color: blue; font-weight: bolder;" rel="nofollow" target="_blank">Python免费学习笔记(深入)</a>”;</p><h1>安全:只提供白名单键,多余键被忽略</h1><p>result = tpl.safe_substitute({
'name': 'Alice',
'site': 'example.com',
'<strong>import</strong>': 'blocked' # 不会被使用,也不会报错
})</p><h1>→ 'Hello Alice, welcome to example.com!'</h1>常见误用:试图绕过限制的典型失败场景
有人尝试用 ${name.__class__} 或 $name[0] 访问属性/切片,但 Template 解析器根本不识别点号或方括号 —— 它只认 $xxx 和 ${xxx} 中的纯标识符。
- 错误写法:
Template('${user.__dict__}')→ 报ValueError: Invalid placeholder - 错误写法:
Template('$data[0]')→ 同样报Invalid placeholder,不是运行时报错,是解析阶段就拒绝 - 危险写法:
tpl.substitute({'name': user_input})且未清洗user_input→ 如果模板里有$name,输出就是原始字符串,但若后续逻辑再对结果做 eval() 就崩了 ——Template只管自己这一层,不保证下游安全
与 format() / f-string 对比时的关键取舍
string.Template 的代价是功能受限:不支持格式说明符(如 :.2f)、不支持位置参数、不支持表达式。所以它只适合「纯变量替换」场景,比如邮件模板、配置生成、日志消息组装。
- 需要格式化数字/日期?先用
format()处理值,再把结果传给Template—— 切勿在模板字符串里写${price:.2f} - 要动态决定用哪个键?用 if/else 构造 mapping 字典,别指望
${'price' if flag else 'discount'}—— 这语法无效 - 性能差异微乎其微,但可读性更高:看到
$就知道“这里只是插值,没逻辑”
真正容易被忽略的是:Template 不处理编码,如果变量含非 ASCII 字符且模板字符串是 bytes 类型,会直接报 TypeError;务必统一用 str。

















