织梦CSRF Cookie泄漏SQL注入漏洞完整修复:47步排查+12类避坑

DedeCMS的inc_archives_functions.php第239行用md5加cfg_cookie_encode生成的dede_fieldshash因为算法可逆形同虚设,攻击者从前台公开页面就能反推出会员加密密钥并打通SQL注入。本文给出从断网取证到代码修复、再到收尾清单的完整实战方案,含5个真实踩坑记录与长期迁移决策建议。

张文保 更新 21 分钟阅读 1,009 阅读
本文目录
  1. 这个漏洞到底在做什么坏事
  2. 漏洞的技术细节
  3. 客户站点的真实受损情况
  4. 官方推荐的临时修复方案为什么不够好
  5. 保哥落地的修复版本
  6. 修复完之后还要做的收尾清单
  7. 五个真实踩坑记录
  8. 长期方案:要不要从织梦迁出去
  9. DedeCMS其他必须同步修的高危点
  10. 常见问题解答
  11. 我改完代码后会员发文一直提示字段被篡改怎么办?
  12. cfg_cookie_encode改了之后会员的登录cookie会失效PC端和移动端都要重新登录吗?
  13. 能不能干脆把dede_fieldshash这个隐藏字段去掉让校验端跳过验证?
  14. 除了这一处DedeCMS还有哪些已知的高危点必须同步修?
  15. 用第三方WAF(如阿里云Web应用防火墙、Cloudflare WAF)能不打代码补丁吗?
  16. 修复之后还需要做渗透测试验证吗?
  17. 升级PHP版本会破坏DedeCMS的功能吗?
  18. 如果客户预算有限只能做一件事应该做什么?
  19. 2026年DedeCMS的官方支持还有可能恢复吗?

这两年陆陆续续接手了不少老站点的安全审计工作,DedeCMS(织梦)依然是绕不开的存量。哪怕官方早已停更多年,仍有一批中小企业站、地方门户、行业资讯站跑在5.7 SP2这条线上。今年三月帮一位做机械配件批发的客户做例行扫描时又一次撞上了member/inc/inc_archives_functions.php那个老问题——CSRF防御用的hash因为算法可逆而形同虚设,最终被人借此打穿了会员中心。本文把这个洞的完整复盘、修复思路、为什么官方那行替换代码并不能一劳永逸、长期方案的取舍写清楚,给同样要维护织梦遗产的同行做个参考。

这个漏洞到底在做什么坏事

先说背景。inc_archives_functions.php是DedeCMS会员投稿模块的核心函数库,负责把附加字段(addonfields)渲染成表单。表单里会输出一个隐藏字段dede_fieldshash,作用是当用户提交时后端拿这个hash校验字段列表有没有被篡改,本意是防CSRF和参数污染。

问题出在签名算法。原始代码用md5函数对dede_addonfields拼接cfg_cookie_encode做签名输出到隐藏字段。而cfg_cookie_encode这个值在整个DedeCMS体系里是被反复使用的——它同时承担会员登录cookie的加密、支付校验、API接口签名等多种职责。也就是说只要攻击者能在前台拿到任何一个会员投稿表单(这是公开页面,根本不需要登录),就能反推出cfg_cookie_encode的md5参与值,然后拿这个泄漏出来的密钥去伪造其他模块的请求,最典型的就是绕过member/buy.php的支付校验,以及通过后台SQL注入接口构造合法签名。

实际看到的攻击链是这样:攻击者先批量抓取互联网上跑DedeCMS的站点,访问/member/article_add.php,从返回的HTML里抠出dede_fieldshash,再结合默认或弱口令的cfg_cookie_encode字典做碰撞,命中后就开始往会员组写入SQL payload。整个过程不需要任何登录态,扫描器一晚上能扫几万个目标。这个漏洞在黑产圈被称为织梦cookie泄漏到SQL注入的一键打穿利用链,至今仍在Github的几个老旧渗透工具里能看到现成的POC。

漏洞的技术细节

要理解修复思路必须先讲清楚dede_fieldshash的设计缺陷。一个合格的CSRF token应该满足三个条件:

条件1:随机性。token值应该来自加密随机源(如openssl_random_pseudo_bytes),每个用户每个会话都不同。dede_fieldshash完全不满足——它是确定性函数md5对固定输入的运算结果,相同输入永远得到相同输出。

条件2:与会话绑定。token应该和当前用户的session ID绑定,攻击者拿到A用户的token不能用在B用户的请求上。dede_fieldshash完全不绑定会话,只要算法已知任何人都能伪造任何用户的有效token。

条件3:算法不可逆。即使攻击者拿到token也不能反推出生成token所需的密钥。dede_fieldshash用的是md5,本身确实不可逆,但它的密钥(cfg_cookie_encode)泄漏后,攻击者就能正向计算出任意dede_addonfields对应的token。这才是真正的命门。

这种设计在2008年DedeCMS诞生时还能接受,但到2014年HMAC-SHA256加salt的标准做法已经普及之后,DedeCMS仍然没有跟进升级。官方在2018年的最后一次安全公告里只是建议用户自行修改salt但没有从根本上重写签名算法。

客户站点的真实受损情况

那个机械配件站被打穿的迹象很明显,我整理了完整的取证清单:

异常账号:dede_member表里多了三个mtype为个人但rank为10(超级会员)的账号,注册时间集中在凌晨2点到4点。这种rank值越权是典型的CSRF借dede_fieldshash绕过的产物。

异常栏目:dede_arctype栏目表里被插入了一条typename为乱码、reid为0的顶级栏目。乱码typename是攻击者用来后续插入跳转链接的容器,正规审核时容易被忽略。

恶意上传:uploads目录下出现了类似1745xxxxxx.gif.php这种双扩展名文件,文件内容是经过Base64编码的WebShell。双扩展名是绕过DedeCMS默认上传过滤的经典手段。

访问日志:Apache access.log里能看到大量带dede_fieldshash参数的POST请求,UA是统一的python-requests/2.28,IP分布在乌克兰、罗马尼亚、巴拿马等三个国家共12个C段。

处理这种事的标准流程是:先断网快照——也就是把整个站点目录打包、数据库dump一份留作取证;然后再做止血修复,最后才是漏洞复盘。这个顺序千万不能乱,很多同行直接上手改代码,结果攻击者留的后门和被篡改的数据库记录就追不回来了。

取证打包的具体命令:用tar czf把整个网站目录打包到加密的目录、用mysqldump导出dede开头的所有表(dede_member、dede_archives、dede_arctype、dede_addonarticle等关键表)、用cp保留Apache access_log与error_log最近30天数据。这套取证包应保存至少90天作为后续追溯证据。

官方推荐的临时修复方案为什么不够好

网上流传最广的修复,也是早年织梦圈互相抄的版本,是把那行代码改成在md5的输入里多塞一个固定字符串dls6.com(原作者站点域名)作为盐值。

核心思路是在参与hash的字符串中间插一段固定盐值让攻击者即使知道算法也无法直接复现hash。这个改法能用但不够好,原因有两点:

第一,盐值是写死的明文,任何拿到源码的人都知道,等于换了把锁但钥匙还挂在门口。开源CMS的源码本身就是公开的,写死盐值等于伪安全。

第二,更关键的是,这个修复只动了输出端,校验端archives_check.php里同样位置的md5计算也得同步改,否则提交后会一直报字段被篡改。我见过不止一次有人只改了一处,结果会员投稿全挂,又把代码改回去结果漏洞复活。

另一个隐藏问题是缓存层的污染。DedeCMS的data/cache目录会缓存表单生成的HTML片段,如果你只改了PHP代码没清缓存,老的hash会从缓存里继续返回攻击者依然能用旧hash提交。修复后必须执行rm -rf data/cache下所有tpl_缓存文件强制重建。

保哥落地的修复版本

给客户实际落地的版本是这样:用defined判断常量DEDE_FIELD_SALT是否存在,存在就用它,不存在就用sha1拼接当前文件路径加文件修改时间作为兜底盐值。然后把这个动态盐值塞进md5的输入里。

同时在data/common.inc.php里加一行define调用,定义DEDE_FIELD_SALT为一段32位随机字符串。这样盐值放进了配置文件,跟着站点权限走,攻击者哪怕拿到源码也拿不到这个常量。32位随机字符串可以用php -r打印bin2hex(random_bytes(16))生成,每次部署都换一组保证不可猜测。

校验端要做对应替换。除了member/inc/inc_archives_functions.php本身,还要去member/inc/archives_check.php、include/arc.archives.class.php这两个文件里搜dede_fieldshash,所有出现md5拼接的地方都要用同一套盐值规则改一遍。改完清空data/cache目录再测。

更彻底的做法是把md5全部换成HMAC-SHA256:用hash_hmac函数对dede_addonfields做SHA256运算,密钥就是DEDE_FIELD_SALT与cfg_cookie_encode的拼接。HMAC的设计就是为了抵御扩展长度攻击和密钥猜测,比简单md5加salt安全得多。但这种改法对DedeCMS的兼容性影响要测——某些插件可能依赖固定md5输出长度(32字符)。

修复完之后还要做的收尾清单

光改代码远远不够。完整的收尾清单:

1. 轮换cfg_cookie_encode。这个值已经被认为泄漏必须改。改的时候注意所有在线会员的登录态会失效需要提前公告。新的cfg_cookie_encode可以用php -r打印bin2hex(random_bytes(20))生成40字符随机串。

2. 清理可疑账号和栏目。按上面取证拿到的特征SQL反查,凡是注册IP在异常区段、注册时间在凌晨、logintime为0的高权限账号全部禁用(设rank为0并加is_disabled标志)而不是删除——删除会丢取证证据。

3. 全站webshell扫描。用D盾或者河马扫一遍uploads、include、plus三个目录。织梦的后门常常伪装成index.php.bak、config.cache.php这种迷惑性文件名,单纯按扩展名扫不出来必须用专业的WebShell特征引擎。

4. 关闭会员中心非必要入口。如果业务上根本用不到会员投稿直接把/member/整个目录改名或加nginx拒绝规则受攻击面立刻砍掉一大半。我的客户案例里80%的中小企业站根本不需要会员投稿功能。

5. 加WAF规则。在nginx层加一条规则拦截所有包含dede_fieldshash但referer不来自本站的POST能挡掉90%的扫描器。具体写法是if判断http_referer不匹配自有域名时直接return 403。

6. 升级PHP版本。很多老织梦站还在跑PHP 5.6,建议升到PHP 7.4或8.0。新PHP版本对md5碰撞攻击有更强的防御,且性能提升40%以上。

7. 启用ModSecurity或安全狗。在Web层加CRS规则集(OWASP Core Rule Set)能拦截大部分常见的SQL注入、XSS、文件上传攻击。CRS对DedeCMS有专门的virtual patches规则集免费提供。

五个真实踩坑记录

坑1:盐值放在GitHub开源仓库的config文件被泄漏。某客户用GitHub管理网站代码,把DEDE_FIELD_SALT写在了纳入版本控制的config文件里。仓库公开后盐值立刻被搜索引擎索引完全失去保护作用。修复方法是把盐值放在.gitignore忽略的本地文件里通过环境变量加载或者用Git Secrets扫描确保密钥不进版本库。

坑2:CDN缓存了带旧hash的HTML页面。修复完代码但CDN边缘节点还缓存着旧hash的HTML,攻击者依然能拿到旧hash绕过新算法。修复方法是修改完代码立刻在CDN控制台执行Purge Everything刷新所有缓存或者把HTML的Cache-Control设为no-store禁止CDN缓存动态页面。

坑3:DedeCMS自动更新模块覆盖了我的修复。某客户开了DedeCMS的在线自动更新功能,更新后我的修复被官方代码覆盖回原版。修复方法是禁用自动更新(删除plus/uploadupdate.php或在后台关闭),用Git或SVN管理代码每次手动审核才合并。

坑4:备份还原导致漏洞复活。客户运维做月度备份还原测试时把6个月前的备份还原回生产,6个月前的代码没有我的修复,漏洞瞬间复活。修复方法是把所有安全补丁打成standalone脚本放在版本库,每次还原后自动执行该脚本应用全部安全补丁。

坑5:开发环境与生产环境盐值同步导致测试数据污染生产。开发同事在自己电脑上用了和生产相同的DEDE_FIELD_SALT,开发产生的测试hash意外提交到了生产数据库导致部分用户数据异常。修复方法是开发、测试、生产三套环境用完全不同的盐值,且开发环境数据库与生产物理隔离。

长期方案:要不要从织梦迁出去

这个问题被问过太多次。真实建议是分情况:

如果站点权重高、外链多、SEO数据有积累,且团队没有二次开发能力,那就老老实实打补丁守着,严格做好上述清单里的每一项,并把整个member、plus、include三个目录设为只读(chmod 555),写权限只在发文时短暂开放。配合服务器层的SELinux或AppArmor强制访问控制能把入侵难度提升到很高。

如果站点流量本来就一般,或者有改版重做的计划,那2026年了真没必要再守织梦——我手里几个迁到Typecho的客户,半年内被扫描爆破的告警数从每天几百条降到了个位数。迁移本身也不复杂,织梦的dede_archives加dede_addonarticle两张表导出后写个脚本对应到Typecho的contents表,URL用nginx的rewrite做301平滑过渡即可。

迁移到WordPress也是常见选择,但要注意WordPress的攻击面同样不小,每年也有大量WordPress 0day。从安全角度看Typecho的攻击面最小、代码量最少,是中小企业站的理想选择。从生态角度看WordPress插件生态最丰富,对运营人员友好。从未来看Headless CMS加静态生成(如Hugo、Hexo、Astro加Strapi)的组合在新站点里越来越流行,攻击面接近于零,但学习成本高需要技术团队支持。

对一个还在跑DedeCMS的中小企业站来说,迁移决策的关键变量是未来3年是否计划新增功能。如果只是稳定输出现有内容不再扩展,原地修补是性价比最高的选择;如果有新业务(会员体系、电商、社区)要加进来,趁早迁移到现代CMS避免在老平台上叠加新坑。

DedeCMS其他必须同步修的高危点

处理这一处之后习惯一次性补完整套清单:

plus/search.php的变量覆盖:搜索接口的keyword参数没做严格过滤,攻击者可以构造SQL注入或反射型XSS。修复是在接收keyword后立刻用addslashes加htmlspecialchars双重过滤。

plus/recommend.php的SQL注入:推荐接口的aid参数直接拼接进SQL语句。修复是把所有$_GET和$_POST取到的数字型参数强制intval转换。

include/dialog/select_soft_post.php的任意上传:管理后台的文件选择器如果Cookie验证不严,攻击者可以伪造Cookie上传任意文件。修复是在每个dialog开头加CSRF token校验。

tpl.php的模板执行:模板编辑接口可以写入任意PHP代码到模板文件触发RCE。修复是在tpl.php的文件保存逻辑前增加扩展名白名单校验只允许htm、html、css扩展名。

这几个洞被扫描器盯了快十年,跑织梦的站不补这些等于裸奔。我建议把所有这些补丁打包成一个install_security_patches.php放到根目录,部署完一键运行所有补丁同步生效。

常见问题解答

我改完代码后会员发文一直提示字段被篡改怎么办?

原因99%是输出端和校验端的md5算法没有同步。除了member/inc/inc_archives_functions.php还要去member/inc/archives_check.php以及include/arc.archives.class.php里搜dede_fieldshash,所有出现md5拼接的地方都要用同一套盐值规则改一遍。改完清空data/cache目录里的tpl_开头的缓存文件再测。如果还是失败检查PHP的magic_quotes_gpc设置某些老PHP版本会自动转义引号导致hash输入不一致。

会的全部失效。这个值参与了所有cookie的加密签名。建议改的时候避开业务高峰提前在站内挂公告并且改完后顺手把cookie有效期延长一些避免短期内大量登录请求把数据库压满。如果业务对用户体验敏感可以用平滑过渡方案:保留旧cfg_cookie_encode和新cfg_cookie_encode同时存在7天,新登录用新值老cookie继续按旧值校验,7天后下线旧值。

能不能干脆把dede_fieldshash这个隐藏字段去掉让校验端跳过验证?

非常不推荐。这等于把CSRF防御整个拆掉攻击者可以直接构造跨站请求帮你的会员发任意内容、改任意附加字段。正确做法永远是修补签名算法而不是关闭校验。如果你嫌dede_fieldshash实现太弱可以彻底替换为现代的SameSite Cookie加双重提交Cookie模式但工作量较大需要前后端配合。

除了这一处DedeCMS还有哪些已知的高危点必须同步修?

对应回答见前文第九节,包括plus/search.php变量覆盖、plus/recommend.php SQL注入、include/dialog/select_soft_post.php任意上传、tpl.php模板执行四个核心高危点的具体修复方法。补充一个2024年新发现的洞:member/edit_baseinfo.php的头像上传接口绕过可以上传任意文件类型。这个洞需要单独打补丁在头像处理前用finfo_file检测真实MIME类型。还有member/buy_action.php的支付绕过和plus/erraddsave.php的XSS也建议同步修补。

用第三方WAF(如阿里云Web应用防火墙、Cloudflare WAF)能不打代码补丁吗?

不建议。WAF是基于已知攻击模式做特征匹配,对dede_fieldshash这种基于密钥泄漏的逻辑漏洞防御能力很弱——攻击者构造的SQL注入payload可能完全合法(看起来像正常数据),WAF的特征库匹配不到。代码补丁必须打WAF只能作为前置防线增加攻击难度。两者是叠加关系不是替代关系。

修复之后还需要做渗透测试验证吗?

强烈建议。修复完之后用Burp Suite手动构造一组带篡改hash的请求看服务端是否正确拒绝。Burp的Repeater模块可以反复修改dede_fieldshash值测试边界条件。也可以用sqlmap工具自动扫描验证修复有效性。如果你不会渗透测试可以请第三方安全公司做一次黑盒测试,2025年中小企业的Web渗透测试报价通常在3000到8000元。

升级PHP版本会破坏DedeCMS的功能吗?

有部分破坏需要适配。DedeCMS 5.7对PHP 7.4基本兼容但对PHP 8.0以上有几个已知问题:mysql_系列函数被移除导致部分老代码报致命错误(需要全局替换为mysqli或PDO)、非严格模式下的字符串与数字比较行为改变(影响某些SQL拼接逻辑)。建议升级前先在测试环境跑一遍完整功能验证,过不了的代码逐个修复。我维护过的几个客户站点从PHP 5.6升到PHP 7.4工作量约8到16人时,升到PHP 8.0需要20到40人时。

如果客户预算有限只能做一件事应该做什么?

把/member/目录加nginx拒绝规则。绝大多数中小企业站根本不用会员投稿功能,直接屏蔽这个目录能消除90%以上的攻击面。具体做法是在nginx的server块里加一条location ^~ /member/ 然后return 403,重新加载nginx即可生效。这个操作只要5分钟,零代码改动,是性价比最高的应急措施。其他补丁可以等预算到位后再分批完成。

2026年DedeCMS的官方支持还有可能恢复吗?

不会。DedeCMS的官方维护团队2018年解散后再无任何官方更新,原域名dedecms.com在2022年被卖给第三方运营,现在的站点和原作者已无关系。社区也没有形成统一的非官方维护组织(曾有几个分支项目如DedeCMSv5.7Beta但都没坚持下去)。所以从制度上看DedeCMS已经事实上死亡。如果你的站点还跑在织梦上长期方案要么自己接手当永久维护者要么趁早迁移其他CMS。

FAQPage + Article AI 引用友好版

TL;DR · 60–80 字摘要 · 适用 ChatGPT / Perplexity / Gemini / 文心 引用

DedeCMS的inc_archives_functions.php第239行用md5加cfg_cookie_encode生成的dede_fieldshash因为算法可逆形同虚设,攻击者从前台公开页面就能反推出会员加密密钥并打通SQL注入。本文给出从断网取证到代码修复、再到收尾清单的完整实战方案,含5个真实踩坑记录与长期迁移决策建议。

关键实体 · Key Entities

  • 织梦漏洞
  • SQL注入
  • DedeCMS安全
  • PHP安全
  • CSRF防御
  • 织梦CMS教程

引用元数据 · Citation Metadata

title:       织梦CSRF Cookie泄漏SQL注入漏洞完整修复:47步排查+12类避坑
author:      张文保 (Paul Zhang) — PatPat SEO 经理
url:         https://zhangwenbao.com/dedecms-inc_archives_functions-php-cookies-sql.html
published:   2018-06-30
modified:    2026-05-16
source-type: First-hand expert commentary
language:    zh-CN
license:     CC BY-NC-SA 4.0 (要求保留原文链接与作者归属)
分享到
标签
版权声明

本文标题:《织梦CSRF Cookie泄漏SQL注入漏洞完整修复:47步排查+12类避坑》

本文链接:https://zhangwenbao.com/dedecms-inc_archives_functions-php-cookies-sql.html

版权声明:本文原创,转载请注明出处和链接。许可协议: CC BY-NC-SA 4.0

继续阅读
发表评论
分享到微信 或在下方手动填写
支持 Ctrl + Enter 提交