子网站的安全问题从来不是孤立事件。一个看似不起眼的子站被挂马、被注入恶意代码、被提权,往往就是攻击者打进整个主站体系的跳板。很多企业把主站防护做得密不透风,却在子站上栽了跟头,原因就在于子站和主站之间共享了太多底层资源:同一套数据库账号、同一个服务器目录、同一组Cookie域、甚至同一台物理机上的相邻虚拟主机。攻击者一旦拿下子站,横向移动的成本极低,而防守方往往因为子站“不重要”而疏于监控,最终导致全站沦陷。
要解决这个问题,必须从架构层面切断子站与主站之间的信任链,而不是简单地给子站加个防火墙或者装个安全插件。核心思路是:假设子站一定会被攻破,然后在这个前提下设计隔离方案,让子站的沦陷无法波及主站和其他子站。
第一层隔离:域名与Cookie作用域彻底分离很多公司为了省事,把子站挂在主站的子域名下,比如blog.example.com、shop.example.com,同时Cookie的作用域设置为.example.com。这意味着主站的登录凭证会被浏览器自动发送到所有子站。攻击者只要在子站页面里插入一段XSS代码,就能直接读取到主站用户的会话Cookie,进而冒充用户登录主站后台。这种攻击成本极低,但破坏力极大。
正确的做法是让每个子站使用完全独立的域名,而不是子域名。例如主站用www.example.com,子站用example-blog.com或者example-shop.cn。Cookie的Domain属性严格限制在各自域名内,绝不设置跨站共享。如果业务上确实需要单点登录,应该采用OAuth2或SAML这类基于令牌的授权协议,通过独立的认证中心来颁发短期有效的访问令牌,而不是依赖Cookie的跨域共享。这样即使子站被攻破,攻击者拿到的也只是子站自己的会话,无法直接冒用主站身份。
第二层隔离:数据库账号与权限最小化子站和主站共用同一个数据库账号是极其危险的做法。很多中小型项目为了部署方便,直接用一个root账号连接所有库,子站程序一旦出现SQL注入,攻击者就能通过这个高权限账号读取、修改甚至删除主站的全部数据。即便不用root,用一个拥有跨库权限的普通账号,同样可以让攻击者在拿下子站后直接跨库查询主站的用户表、订单表。
必须为每个子站创建独立的数据库账号,并且只授予该子站对应数据库的增删改查权限,禁止跨库访问。同时要关闭账号的FILE权限、PROCESS权限等危险权限,防止攻击者通过子站数据库账号读取服务器文件系统或者查看其他连接中的敏感信息。对于需要读写文件的功能,比如上传图片、生成静态页,应该通过应用层封装专门的接口,由主站服务端统一处理,而不是让子站直接操作文件系统。
第三层隔离:服务器与运行环境物理或容器级分离如果子站和主站部署在同一台服务器上,仅仅靠虚拟主机目录隔离是远远不够的。攻击者一旦在子站上传了一个WebShell,就可以利用服务器上的本地文件包含漏洞、内核提权漏洞或者不安全的文件权限配置,尝试读取主站的配置文件、源代码甚至直接控制整台服务器。共享的操作系统、共享的临时目录、共享的计划任务,都是横向移动的通道。
条件允许的情况下,子站应该部署在独立的服务器或者独立的云主机上,与主站之间没有任何文件系统层面的交集。如果资源有限必须共用服务器,至少要用Docker容器或者虚拟机进行隔离,每个子站跑在独立的容器里,限制容器的CPU、内存、网络和文件系统访问范围。容器之间默认网络不通,只有明确声明需要通信的端口才开放。同时要禁用容器内的特权模式,防止容器逃逸。
第四层隔离:反向代理与流量入口统一管控把所有子站的流量入口统一收敛到一个反向代理层,是控制风险扩散的有效手段。主站和子站对外只暴露反向代理的IP,真实的服务器IP隐藏在后端。反向代理层可以统一执行WAF规则、限流策略、IP黑名单、请求体大小限制等安全策略。即使某个子站被攻破,攻击者也无法直接访问到子站的真实服务器,因为流量必须经过代理层的过滤。
更重要的是,反向代理层可以根据Host头或者URL路径做精细的路由隔离。比如将/api/开头的请求路由到主站后端,将/blog/开头的请求路由到子站后端,并且在后端服务器上配置防火墙,只允许来自反向代理IP的访问。这样攻击者即使拿到了子站的WebShell,也无法直接连接主站的内网地址,因为主站后端根本不接受来自非代理IP的请求。
第五层隔离:文件上传与静态资源独立存储子站被攻破最常见的入口就是文件上传漏洞。攻击者上传一个包含恶意代码的图片、压缩包或者脚本文件,然后通过路径遍历或者解析漏洞让服务器执行这个文件。如果子站的文件存储目录和主站在同一个文件系统里,攻击者就可以尝试写入主站的目录,篡改主站的页面或者植入后门。
解决这个问题的方法是让子站的文件上传全部走独立的对象存储服务,比如云厂商提供的OSS或S3兼容存储。子站上传的文件直接写入对象存储的独立Bucket,不经过子站服务器本地磁盘。对象存储的Bucket权限设置为公共读私有写,子站服务器只负责生成上传凭证,不直接持有存储的写权限。这样即使子站被攻破,攻击者也无法通过子站服务器向主站的文件目录写入任何内容。
第六层隔离:监控与告警独立运行子站的安全监控不能依赖主站的监控系统。如果主站的监控系统本身被攻破,或者子站被攻破后攻击者关闭了子站上的监控代理,那么整个安全态势感知就失效了。应该为每个子站部署独立的监控代理,监控数据上报到独立于业务系统的安全运营平台。监控内容包括文件完整性变化、异常进程启动、异常网络连接、登录失败次数激增等。
同时要设置基于行为的告警规则,比如子站服务器在非工作时间出现对外扫描行为、子站数据库账号在短时间内执行大量SELECT语句、子站目录下出现以.php为后缀的可疑文件等。这些告警要直接推送到安全团队的即时通讯工具,而不是仅仅记录在日志里等人去翻。
第七层隔离:代码与配置管理分离子站的代码仓库和主站的代码仓库应该分开管理,CI/CD流水线也要独立。很多公司把主站和子站的代码放在同一个Git仓库的不同目录下,用同一个部署脚本发布。这意味着任何一个有子站代码提交权限的开发人员,理论上都可以修改主站的部署配置。一旦子站的代码仓库被攻击者控制,攻击者就可以通过修改部署脚本向主站注入恶意代码。
正确的做法是每个子站拥有独立的代码仓库、独立的部署密钥、独立的CI/CD流水线。部署密钥的作用域严格限制在子站对应的服务器或容器集群上,不允许跨环境使用。同时代码仓库的访问权限要按最小必要原则分配,子站的开发人员只能访问子站的仓库,主站的仓库权限单独管理。
第八层隔离:数据备份与恢复独立执行如果子站和主站的数据备份放在同一个备份系统里,攻击者一旦拿到备份系统的访问权限,就可以同时删除或加密主站和子站的所有备份,让灾难恢复变成空谈。子站的数据备份应该独立存储,备份文件的访问凭证与主站备份完全分离。备份恢复演练也要分开进行,确保子站被勒索软件加密后,可以在不影响主站的情况下单独恢复子站数据。
另外要注意备份数据的版本隔离。攻击者可能会在子站被攻破后潜伏数周甚至数月,期间子站的备份文件里已经包含了后门代码。如果恢复时直接使用最新的备份,等于把后门又装了回去。应该保留足够长时间的历史备份版本,并且在恢复前对备份文件进行恶意代码扫描。
实际落地中的常见误区很多团队在实施子站隔离时,会把重点放在购买安全设备或者安装安全软件上,却忽略了架构层面的信任链切断。比如给子站装了WAF,但子站和主站仍然共用同一个数据库账号;比如给子站上了HTTPS,但Cookie域仍然是跨站共享的。这些表面功夫无法阻止攻击者从子站横向移动到主站。
另一个误区是认为子站流量小、用户少,不值得投入太多安全资源。实际上攻击者根本不在乎子站的业务价值,他们在乎的是子站作为跳板的价值。一个没有任何敏感数据的子站,只要和主站有网络连通性,就是攻击者眼中的宝藏。很多大型企业的数据泄露事件,最初的突破口恰恰是一个无人维护的旧版子站。
还有团队在隔离方案上走极端,把子站完全物理隔离,导致业务系统之间的正常数据交互变得极其复杂,最后不得不开各种例外通道,反而增加了攻击面。隔离的目标不是让子站变成孤岛,而是在保证业务可用性的前提下,让攻击者无法利用子站作为跳板。这需要在安全性和业务效率之间找到平衡点,而不是一刀切地断开所有连接。
子网站的安全防护,本质上是一个架构设计问题,而不是一个简单的安全产品选型问题。只有从域名、Cookie、数据库、服务器、文件存储、监控、代码管理、备份等各个层面切断子站与主站之间的隐式信任关系,才能真正避免单点风险牵连全站。每一个共享的资源、每一个默认的信任、每一个省事的配置,都可能是攻击者横向移动的通道。把子站当成一个完全不可信的第三方系统来对待,才是正确的防护心态。
