2026-07-02 01:26:23
SSTI漏洞浅析
SSTI(Server-Side Template Injection,服务端模板注入)是一种常见的Web安全漏洞,攻击者通过注入恶意模板代码,在服务端执行任意操作,可能导致数据泄露、代码执行甚至服务器控制。以下从漏洞原理、利用方式及防御措施展开分析。
一、漏洞原理SSTI漏洞的核心在于模板引擎未对用户输入进行安全处理,导致攻击者注入的模板代码被服务端解析执行。常见场景包括:
用户输入直接拼接模板例如,Flask的render_template_string直接使用用户输入的name参数:
template = '<h1>Hello {{name}}!</h1>'return render_template_string(template, name=name)若用户输入{{7*7}},服务端会计算表达式并返回结果(如Hello 49!)。
模板引擎功能被滥用模板引擎通常支持逻辑操作(如循环、条件判断)、函数调用甚至文件读写(如{{config}}暴露Flask配置)。攻击者可利用这些功能执行恶意代码。
基础代码执行注入数学表达式或字符串操作:
敏感信息泄露访问模板引擎的上下文变量(如Flask的config):
{{config}} → 暴露数据库密码、SECRET_KEY等远程代码执行(RCE)通过模板语法调用系统命令(如Python的os.popen):
{{''.__class__.__mro__[1].__subclasses__()[401]('ls',shell=True,stdout=-1).communicate()}}(注:具体利用方式因模板引擎而异,如Jinja2、Twig、FreeMarker等)
文件操作读取或写入服务器文件:
{{open('/etc/passwd').read()}}禁用动态模板渲染避免直接使用用户输入拼接模板,改用静态模板+参数传递:
# 错误方式render_template_string(f"<h1>{user_input}</h1>")# 正确方式render_template("static_template.html", content=user_input)启用模板安全模式
Flask:使用render_template而非render_template_string,并避免|safe过滤器(除非内容已消毒)。
其他引擎:如Jinja2可设置autoescape=True自动转义。
输入过滤与转义
对用户输入进行白名单校验(如仅允许字母数字)。
使用HTML转义库(如Python的html.escape)。
最小权限原则限制模板引擎的访问权限,避免暴露敏感对象(如Flask的config)。
沙箱环境使用沙箱化的模板引擎(如限制可用的内置函数和模块)。
漏洞代码(Flask):
from flask import Flask, render_template_string, requestapp = Flask(__name__)@app.route('/')def index(): name = request.args.get('name', 'Guest') return render_template_string(f"<h1>Hello {{name}}!</h1>", name=name)修复后代码:
from flask import Flask, render_template, requestfrom markupsafe import escapeapp = Flask(__name__)@app.route('/')def index(): name = escape(request.args.get('name', 'Guest')) # 转义用户输入 return render_template("index.html", name=name) # 使用静态模板五、总结SSTI漏洞的根源是模板与代码的混淆,防御的关键在于:
通过严格限制用户输入的影响范围,可有效阻断此类攻击链。