直接回答:SSTI 指用户输入被拼进模板内容本身、而非仅作为渲染数据传入,攻击者注入模板语法(Jinja2 的 {{7*7}}、Freemarker 的 ${7*7})让服务端在渲染阶段执行恶意表达式。它与 XSS 的本质区别在于执行位置:XSS 在受害者浏览器里执行 JS,SSTI 在服务器上执行——轻则读取配置与环境变量,重则沿模板引擎的对象链(如 Python 的 __class__.__mro__.__subclasses__())拿到 RCE。

展开解析:根源几乎都是同一个反模式——先拼接、后渲染,如 Template("你好 " + name).render()。正确用法是把用户输入只作为渲染上下文的数据:Template(tpl).render(name=name),引擎会自动转义,输入永远到不了模板语法层。防御上:杜绝用户可控内容进入模板字符串;业务确实需要用户自定义模板时(如邮件模板场景),使用沙箱模式(如 Jinja2 的 SandboxedEnvironment)并收敛可用对象与过滤器,最好在低权限、禁外联的隔离环境渲染。检测可注入算术表达式观察是否被求值。

追问方向:Jinja2 沙箱历史上的绕过思路?为什么"过滤花括号"防不住 SSTI?Twig 与 Freemarker 的利用链有何差异?

(约 410 字)