把页面做成 HTML 缓存,为什么会变成可执行代码的入口
把前台页面做成 HTML 静态缓存,为什么反而可能变成可执行代码的入口?因为缓存把访问者能影响的输出落成了一个真实存在的文件。动态渲染时带参数的内容只在响应里一闪而过;写进缓存文件后,它就成了会被再次读取的源文件。若写入时没过滤、解析时又把缓存目录当脚本目录,反射进去的可执行标签就会被引擎跑起来,这条提速的路就成了代码执行入口。边界只有两条:写入时剥离可执行标签,解析时不把缓存目录当脚本目录。修复之后还要清历史缓存、核对伪静态规则,动手前先做备份。
缓存产物为什么危险
风险来自反射与落盘这两步的叠加。反射是页面把访问者提交的参数原样回显到 HTML 里,地址栏、表单、爬虫识别用的蜘蛛标签都能把它带进去。落盘是这段回显被缓存机制写进了文件。单独看每一步都不致命,回显靠输出转义收口,落盘靠解析策略收口,危险在于两侧都以为对方管了。于是攻击者用一段拼好的参数请求页面,触发一次缓存写入,把内容钉在服务器上;再请求同一个缓存产物,这段内容就被脚本引擎解析执行。一次输入变成持久化的代码,属存储型执行路径;匿名访问就能触发写入,攻击面等于公开入口。
当天口径的修复说明
以同类国产建站程序里被公开修复的一例为口径:PbootCMS 在 3.2.14 版本(2026-06-15 构建)的更新日志中列了两条安全修复,一条是修复访问参数经蜘蛛标签反射写入 HTML 缓存导致的代码执行漏洞,另一条是 HTML 页面缓存写入时剥离可执行脚本标签,杜绝缓存被当作脚本执行。它的价值是把边界拆成两半:一半管写进去的内容,一半管写出来的文件怎么被对待。同类国产建站程序和外购程序遇到同类问题,也只能在这两处同时收口,加一道输入过滤不算修完。
两条写入边界
第一条是写入边界。缓存落盘前要把可执行标签、模板表达式与脚本片段剥掉,只留纯文本和白名单标签;对反射进来的参数统一转义;对缓存产物做文件名与后缀约束,不让请求内容决定它叫什么。意义是,就算上游过滤漏了,落盘产物本身也不含可执行语句。第二条是解析边界。缓存目录不该有执行权限:不给它脚本解析的处理器,不让它继承上传或模板目录的规则,公开可访问的缓存子目录单独收紧,只按预设路由读取。意义是,就算产物混进可疑字节,服务器也不会把它当代码跑。两条边界互补,只做其一,另一条就是缺口。
自建程序怎么对照自查
自建或二次开发的站点按这个顺序自查。先拉出参数反射点清单,把所有回显请求内容的位置登记下来,含列表筛选参数、站内搜索词、蜘蛛标签。再检查缓存目录的权限与解析策略,确认它没有执行权、产物后缀固定。改代码之前先做备份,数据与静态文件都要备份到可回滚的位置,安企CMS 的备份能力正好覆盖这两者,回滚时一起回。改完必须清掉全部历史缓存,含增量缓存与临时产物;旧缓存不清,过滤只对新生成的文件生效,风险仍在原地。最后核对伪静态规则:改写后指向的真实路径要与缓存产物一致,安企CMS 支持自定义伪静态规则,若某条改写把地址解析到脚本或缓存目录,等于自造一条执行通道,改完要逐条验证访问结果,而不是只看页面能不能打开。
常见问题
问:前台开了静态缓存,怎么判断有没有被执行的风险? 答:看两点:缓存产物落在哪个目录、有没有脚本解析权;页面是否把访问者可控的参数原样写进缓存。两条同时成立就立刻处理。
问:清缓存会不会把网站内容清掉? 答:不会。正文在数据库与附件里,缓存只是渲染产物,删掉后会重新生成。但动手前仍要做一次备份。
问:伪静态规则和缓存风险有什么关系? 答:改写规则决定一个友好网址最终落到哪个真实文件。规则与缓存目录叠加时,改写路径可能被交给脚本引擎处理,所以改完要逐条核对解析结果。
问:只加输入过滤,不做目录隔离行不行? 答:不建议。过滤管写入侧,隔离管解析侧,缺一侧就等于把防线交给一次漏判。