模板注入(SSTI):从页面渲染到代码执行
admin
2026-10-27 09:21
141人看过
免费
# SSTI 服务器端模板注入(软件设计师 / 安全考点)
全称:**Server-Side Template Injection,服务器端模板注入**
> 一句话核心:**服务器使用模板引擎渲染页面,把用户可控输入直接塞进模板,而非单纯传入变量,导致攻击者可以执行模板语法,最终读取文件、执行系统命令。**
## 一、正常页面渲染(安全,无SSTI)
模板文件:`hello.html`
```jinja2
<h1>Hello {{ name }}</h1>
```
后端代码(Python Flask/Jinja2)
```python
# 用户输入:name = request.args.get("name")
render_template("hello.html", name=name)
```
✅ 原理:模板文件固定写死,**用户输入只作为变量值传入**,`name`只是字符串,不会被解析为模板语法。
用户输入 `{{7*7}}`,页面只会原样输出字符串`{{7*7}}`,不会计算49。
## 二、存在SSTI漏洞(危险写法!)
后端直接**拼接字符串生成模板**,把用户输入嵌入模板源码:
```python
# 危险!直接字符串拼接
user_input = request.args.get("name")
tmpl = f"<h1>Hello {user_input}</h1>"
render_template_string(tmpl)
```
此时用户传入:`{{7*7}}`
服务器把它当成模板语法解析,执行表达式,页面输出:`Hello 49`
👉 这就是SSTI触发点:**用户可控内容被当作模板代码解析**
> 区分重点(考题常坑)
> - `render_template(模板文件,变量)`:一般安全
> - `render_template_string(用户拼接字符串)`:极易SSTI
## 三、漏洞利用链路:表达式 → 对象查找 → 代码执行(Jinja2为例)
1. 测试判断是否存在SSTI
payload:`{{7*7}}`
返回49 → 确认Jinja2 SSTI存在
2. 查找可用对象,python沙箱逃逸
```
{{''.__class__.__mro__[2].__subclasses__()}}
```
- `''.__class__`:空字符串的类(str)
- `__mro__`:继承链
- `__subclasses__()`:获取所有子类列表
找到`subprocess.Popen`类,就可以执行系统命令
3. 命令执行payload(读取文件 / 执行系统命令)
```jinja2
# 执行系统id命令
{{''.__class__.__mro__[2].__subclasses__()[xxx]('id',shell=True,stdout=-1).communicate()}}
```
## 四、模板引擎差异(选择题考点)
- Jinja2(Flask):`{{ 表达式 }}`,最常考SSTI
- Twig(PHP):`{{ }}`
- Smarty(PHP):`{$变量}`,老版本存在SSTI
- Django模板:**默认沙箱,不支持直接执行代码**,Django原生模板很难直接RCE(重要考点!Django模板和jinja2不一样)
> ⚠️高频考点:Django模板本身限制严格,单纯`{{}}`不能直接调用函数执行系统命令;Flask+Jinja2是SSTI重灾区。
## 五、漏洞成因总结
1. 使用服务器模板引擎
2. **用户可控数据,直接拼接进模板源代码**
3. 模板引擎解析了用户传入的语法表达式
## 六、防御手段(简答考点)
1. 严禁使用字符串拼接模板;用户输入**只作为模板变量传入**
2. 不要使用`render_template_string`接收外部输入
3. 沙箱加固,过滤危险属性`__class__`、`__subclasses__`、`__mro__`
4. 最小权限运行Web进程,即使被拿下,限制危害
5. 输入过滤、WAF拦截SSTI特征payload
## 七、一句话背诵
SSTI:**用户输入被服务器模板引擎解析执行,不是前端注入;和XSS区别:XSS在浏览器执行,SSTI在服务器执行**
> XSS:前端浏览器解析JS;SSTI:服务器解析模板代码。
版权声明:倡导尊重与保护知识产权。未经许可,任何人不得复制、转载或以其他方式使用本站原创内容。