当前位置: 首页 > news >正文

web安全代码基础-PHP(模板组件插件安全)

存在安全问题的模板

模板引擎基本概念

模板引擎核心目标:前后端代码分离。在开始介绍模板框架之前先了解一下模板引擎,模板引擎是为了让前端界(html)与程序代码(php)分离而产生的一种解决方案,简单来说就是html文件里再也不用写php代码了。

模版使用案例

Php模版框架:Smarty、Twig,codeeval等

python模版框架:jinja2、mako、tornad、Django等

Java模版框架:Thymeleaf、jade、velocity、FreeMarker等

JavaScript模版框架:doT,Nunjucks,Pug,Marko,EJS,Dust等

Smarty 实现思路

1、模板文件(.tpl):纯 HTML + Smarty 标签{$变量},无 PHP 代码

2、PHP 程序文件:只负责业务逻辑、查询数据、赋值变量,不写页面

3、底层原理:Smarty 读取模板,将 PHP 传入的变量替换模板标签,生成静态 HTML 输出浏览器

Smarty的原理是变量替换原则,我们只需在html文件写好Smarty的标签即可,例{name},然后调用Smarty的方法传递变量参数即可。

简单演示Smarty

环境说明:

composer require smarty/smarty //需提前安装 Smarty(Composer 一键安装)

1. 目录结构规范

project/ ├── templates/ # 存放模板文件(html/tpl) │ └── index.tpl ├── templates_c/ # 编译缓存目录(需设置读写权限777) ├── cache/ # 页面缓存目录 └── index.php # PHP后端逻辑

2. 后端文件 index.php(PHP 逻辑)

<?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(纯 HTML+Smarty 标签,无 PHP)

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Smarty模板示例</title> </head> <body> <h3>普通变量输出</h3> 姓名:{$name} <br> 年龄:{$age} <hr> <h3>数组输出</h3> 手机号:{$user.phone} <br> 地址:{$user.address} <hr> <h3>循环遍历数组</h3> {foreach from=$fruitList item=val} 水果:{$val} <br> {/foreach} <hr> <h3>对象属性输出</h3> 学号:{$student->stuId} <br> 学生名:{$student->stuName} </body> </html>

4、页面最终渲染结果

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Smarty模板示例</title> </head> <body> <h3>普通变量输出</h3> 姓名:张三 <br> 年龄:22 <hr> <h3>数组输出</h3> 手机号:13800138000 <br> 地址:北京市朝阳区 <hr> <h3>循环遍历数组</h3> 水果:苹果 <br> 水果:香蕉 <br> 水果:橙子 <br> <hr> <h3>对象属性输出</h3> 学号:1001 <br> 学生名:李四 </body> </html>

5、运行过程解析

访问index.php,PHP 不会直接输出 HTML;-->Smarty 读取index.tpl模板文件;-->内部自动将assign()赋值的变量,替换模板中{$xxx}标签;-->生成编译后的 HTML 缓存文件,输出到浏览器展示最终页面。

安全漏洞影响
SSTI(Server 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?payload=testuser渲染逻辑: 模板字符串,无模板语法,直接输出文本。

运行结果:欢迎你: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}&cmd=system('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 仅做输出转义,不会将变量内容解析为模板语法。

模板探针

寻找所有可控输入点(测试点位)

  1. GET 参数:?name=xxx?content=xxx?title=xxx
  2. POST 表单:留言、昵称、简介、搜索框、评论
  3. Cookie 值:Cookie: user=xxx
  4. 请求头:User-Agent、Referer、X-Forwarded-For(页面会打印 UA/IP 时)
  5. 文件上传文件名、自定义页面标题、自定义模板名称

关键判断前提:输入内容会在页面展示(回显型点位最容易测 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 特殊字符,避免同时触发 XSS;

6、严格过滤模板文件名:

若必须动态加载模板,白名单限制文件名,禁止用户传入任意路径。

存在安全问题的组件插件

一、富文本编辑器插件(高危攻击面:上传漏洞、XSS、SSTI、文件包含)

1、CKEditor / UEditor(百度编辑器):文件上传漏洞(最常见)、存储型XSS、路径遍历(图片预览、文件下载接口)等

黑盒探针点:

/ueditor/php/upload.php、ckeditor/image_upload.php、dialogs/filemanager

2、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、文件读取、SSRF)

1、ImageMagick / PHP 扩展 Imagick(经典 Imagetragick CVE-2016-3714)

漏洞原理:

处理用户上传图片时解析 SVG/MVG/PS 指令,可嵌入系统命令,调用curl/wget/rm上传一张图片即可拿服务器权限

攻击方式:

  • 伪装 jpg 的恶意 SVG,内含url("|ls /")管道命令;
  • 依赖 Ghostscript,未禁用 PS/PDF 格式时持续爆出新 RCE(CVE-2025-57807)。

黑盒探针:

上传恶意 svg 图片,观察页面处理图片是否超时、是否泄露目录内容。

2. GD 库(PHP 原生)

风险较低,但存在:

  • 图片水印、远程图片下载产生SSRF
  • 解析恶意 GIF 产生内存耗尽 DOS。

3. 第三方图片压缩 / 裁剪插件

如 WP 媒体库、Discuz 图片处理:文件名可控拼接系统命令,命令注入。

三、邮件发送组件(高危:命令注入 RCE、CRLF 邮件注入、文件写入)等等,还有很多存在安全问题的模板、组件、插件等等。

http://www.jsqmd.com/news/1099843/

相关文章:

  • FastAPI 基础篇:类型注解驱动的 Python Web 开发范式
  • OpenHarness源码研究-4-AgentLoop对话引擎与工具系统
  • 如何深度掌控AMD Ryzen处理器:专业硬件调试工具完全指南
  • ros2 humble安装anaconda
  • 机器人-混合关节架构
  • Certbot:免费自动化 HTTPS 证书管理工具
  • 2026年桌面风扇推荐:三款不同功能定位机型,按需选择不踩坑
  • 【毕设级】SpringBoot + MySQL + Thymeleaf 实现高校教材征订管理系统(班级统订+个人补订)
  • Linux生产环境硬盘挂载:告别盘符漂移,使用UUID实现稳定自动挂载
  • 手把手教你用SM2259XT2开卡工具修复固态硬盘(附B0KB颗粒实测)
  • 小学期记录
  • Awesome LLM Skills:给 AI 编程助手装上各种技能包
  • 3分钟掌握深度学习漫画翻译神器:BallonsTranslator完全指南
  • 机器人-从“性能参数领先”转向“工业化能力领先”
  • 效率够高吗?8款AI论文网站排行榜,毕业季救星!
  • Docker部署-非root用户openEuler 20.03部署
  • How To Secure A Linux Server:一份持续更新的服务器安全加固手册
  • 2026年6月个人工作生活总结
  • Linux Page Cache 导致视频解码第一次慢、第二次快的原因分析与缓存清理方法
  • PYTHON+AI LLM DAY NINTY-TWO
  • vmware安装win10教程(保姆级图文):VMware16虚拟机部署Windows10,附win10镜像iso文件下载
  • OpenHarness源码研究-3-codex配置到输出对话
  • PDF转Excel免费工具推荐,批量转换不收费绿色版
  • Windows 11本地部署GLM-5.2大模型:集成Claw工具调用与Agent知识库实战
  • 零基础自学C++逆向学习日记 Day.5
  • 【题解-信息学奥赛一本通】1224:最大子矩阵
  • 【数仓避坑04】金额换算精度踩坑:先除后乘导致大额资金隐性资损,先乘后除精度最优详解
  • 当企业应用AI销冠系统时,如何利用数字员工提升工作效率?
  • 数据库工程:生产级查询优化全案例拆解‌
  • 企业级离线翻译架构重构:LibreTranslate 1.9.6如何实现数据主权与性能突破