注入网站模板
模板注入,注入说白了就是网站网站把用户输入直接塞进模板引擎里执行了。攻击者不用碰数据库,模板不用猜后台路径,注入只要在输入框里敲几行特殊语法,网站就能让服务器乖乖交出源码、模板配置文件,注入甚至直接拿下管理员权限。网站
我见过最典型的模板案例,是注入一个跨境电商站点的搜索框。那个搜索框把关键词原封不动地拼进邮件模板里,网站用来给用户发送“搜索结果已生成”的模板通知。测试时输入${7*7},注入结果邮件标题赫然显示“49”。网站这已经不是模板漏洞了,这是网站把钥匙挂在门把手上。
问题根源在于,很多开发者把模板引擎当成单纯的字符串拼接工具。他们觉得用户输入无非是几个字符,能有什么危险?实际上,像Freemarker、Velocity、Thymeleaf这类引擎,都内置了强大的表达式语言,能调用底层Java对象的方法。一旦输入被当作模板语法解析,${T(java.lang.Runtime).getRuntime().exec('id')}这种代码就能让服务器执行任意命令。
更隐蔽的是存储型注入。攻击者把payload写进用户昵称、商品描述这些看似无害的字段,只要后台管理员一预览商品页面,恶意模板就被触发。我做过一次渗透测试,发现目标站点的商品图片URL参数存在注入点,但直接测试会被WAF拦截。后来我把payload拆成多段,分别存在不同字段里,再通过模板的字符串拼接功能重组——WAF只盯着单个请求,完全没察觉到数据在服务器内部已经悄悄完成了“拼图”。
修复方式其实不复杂,核心就两条:一是对用户输入做严格过滤,把${、{{、<%这类模板特征字符全部转义;二是别让用户输入直接决定用哪个模板文件,改用白名单映射。但现实中很多团队只做了第一层,以为过滤了尖括号就万事大吉,结果忘了模板引擎还有别的语法变体。
有个细节很少被人提起——模板注入的检测难度和开发框架的版本强相关。老版本Spring Boot默认开启模板缓存,你注入的payload要等缓存刷新才能生效,导致测试时总以为没中招。而新版框架改成实时渲染,反而让漏洞更容易暴露。这种“版本差异带来的不确定性”,才是安全测试里最磨人的地方。
说到底,模板注入不是某个框架的专利,而是“信任用户输入”这种惯性思维的必然产物。每次看到有人吹嘘自己用了最前沿的前后端分离架构,我就想笑——只要后端还在用模板拼接HTML,前端框架再华丽也挡不住这记闷棍。