网站资源加载过程,本质上就是浏览器向服务器请求HTML文档,解析后遇到CSS、JavaScript、图片、字体等引用,再次发起请求的过程。这个链条上任何一个环节被恶意利用,都可能导致页面被劫持、用户数据泄露或服务器过载。资源加载漏洞不像SQL注入那样被反复提及,但它的破坏力丝毫不弱,而且往往更隐蔽。常见的攻击面包括:CDN劫持与供应链污染、子资源完整性缺失、跨域配置错误、资源枚举与信息泄露、以及未限制的资源大小与超时导致的拒绝服务。下面直接进入具体的识别方法和修复方案。
CDN劫持与第三方资源供应链污染的防御很多网站引用了托管在公共CDN上的JavaScript库或CSS文件,比如BootCDN、Staticfile等。攻击者如果控制了CDN节点,或者通过DNS劫持将请求指向恶意服务器,注入的代码就能直接在你的域名下执行,窃取Cookie、劫持登录态、甚至发起XSS攻击。这种攻击绕过了服务端的所有安全防护,因为恶意代码是在浏览器端加载的。修复方案的核心是子资源完整性校验,也就是SRI。在script或link标签中添加integrity属性,浏览器会计算下载资源的哈希值,与属性值比对,不匹配则拒绝执行。
<script src="https://cdn.example.com/library.js"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
crossorigin="anonymous"></script>
生成integrity哈希值可以用OpenSSL命令行工具:openssl dgst -sha384 -binary library.js | openssl base64 -A,然后拼接前缀sha384-。crossorigin="anonymous"属性必须加上,否则浏览器不会发送CORS请求,SRI对跨域资源将失效。如果CDN不支持CORS,就考虑将关键资源回源到自己服务器,或者使用支持CORS的CDN。另一个容易被忽略的点是动态加载的脚本。如果代码里用document.createElement('script')动态创建标签,同样要设置integrity属性。对于第三方广告、统计代码这类无法添加SRI的资源,建议通过iframe隔离,限制其权限,使用sandbox属性禁止脚本执行或表单提交,配合Content-Security-Policy头限制iframe内的行为。
跨域资源共享配置错误与信息泄露修复CORS配置不当是资源加载中最常见的高危漏洞。典型错误包括:Access-Control-Allow-Origin设置为*,同时Access-Control-Allow-Credentials设置为true。这种组合下,任何网站都可以携带用户凭证发起跨域请求,相当于把用户数据完全暴露。更隐蔽的是,Access-Control-Allow-Origin反射请求中的Origin头而不做白名单校验,效果等同于*。修复时,必须严格校验Origin头,只允许受信任的域名。服务端代码逻辑应该这样写:读取请求头中的Origin,与白名单数组比对,匹配成功才将Origin值原样返回给Access-Control-Allow-Origin,不匹配则返回403或干脆不设置CORS头。不要图省事直接返回*。另外,Access-Control-Allow-Methods和Access-Control-Allow-Headers也要最小化,只开放业务需要的HTTP方法和请求头。对于不需要跨域访问的资源,直接不输出任何CORS响应头,这是最安全的状态。
资源枚举漏洞与路径遍历的加固很多网站把用户上传的文件、静态资源放在可预测的路径下,比如/upload/avatar/1.jpg、/static/backup/database.sql这类命名方式。攻击者通过暴力枚举路径,可能发现未授权访问的备份文件、配置文件或包含敏感信息的日志。修复分几个层面:第一,资源存储使用随机化的文件名,比如用UUID或内容哈希命名,彻底消除可预测性。第二,静态资源目录禁止目录列表功能,Nginx里设置autoindex off,Apache里设置Options -Indexes。第三,对于需要权限控制的资源,不要直接暴露静态路径,而是通过后端脚本读取文件并输出,在脚本中做权限校验。第四,配置Web服务器限制对敏感文件类型的直接访问,比如Nginx中可以这样禁止访问特定后缀:
location ~* \.(sql|log|ini|conf|bak|swp)$ {
deny all;
return 404;
}
第五,也是最容易被忽视的,检查资源请求的Referer头。如果你的静态资源只应该被自己的页面引用,可以配置服务器拒绝来自外部域名的直接请求。但Referer可以被伪造,只能作为纵深防御的一层,不能依赖它做核心鉴权。
资源加载超时与尺寸限制防止拒绝服务如果你的网站允许用户提交URL,然后服务端去抓取(比如头像链接、文章中的外部图片),攻击者可以提交一个指向巨大文件或者慢速响应的URL,耗尽服务器内存或连接池。这种漏洞叫做SSRF资源耗尽或慢速HTTP攻击的变种。修复方案:第一,设置请求超时,包括连接超时和读取超时,通常连接超时3秒,读取超时5到10秒足够。第二,限制响应体的最大尺寸,比如下载图片限制在10MB以内,超过则中断连接。第三,限制允许的URL协议,只允许http和https,禁止file、ftp、gopher等协议,防止读取本地文件或内网探测。第四,对请求的目标IP做内网地址段过滤,禁止访问127.0.0.0/8、10.0.0.0/8、172.16.0.0/12、192.168.0.0/16等私有地址,防止攻击者利用你的服务器探测内网。第五,对用户提交的URL做域名解析白名单校验,只允许访问公网域名,或者更严格地只允许访问特定域名后缀。这些限制要在代码层面实现,不能只依赖防火墙。
前端资源加载的安全头配置HTTP安全响应头是防御资源加载攻击的最后一道防线,但很多网站配置不完整或者配错了。Content-Security-Policy头可以精确控制浏览器加载资源的来源。一个生产环境可用的策略示例:default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://trusted-cdn.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com; connect-src 'self' https://api.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'。这个策略禁止了frame嵌套、限制了表单提交目标、指定了脚本和样式的合法来源。'unsafe-inline'和'unsafe-eval'是妥协,如果业务允许,尽量使用nonce或hash替代unsafe-inline,彻底禁止内联脚本,这是防御XSS的最强手段。X-Content-Type-Options设置为nosniff,防止浏览器MIME嗅探,避免攻击者上传一个伪装成图片的HTML文件,浏览器却当作HTML解析执行。Strict-Transport-Security头强制HTTPS,max-age设置至少半年,includeSubDomains和preload标记也加上,彻底杜绝SSL剥离攻击。Referrer-Policy设置为strict-origin-when-cross-origin,在跨域时只发送域名不发送完整路径,减少信息泄露。Permissions-Policy头限制浏览器特性的使用,比如禁用麦克风、摄像头、定位等不必要的能力,缩小攻击面。
资源压缩与格式转换中的安全陷阱网站为了性能,通常会对用户上传的图片进行压缩、裁剪、格式转换。这个过程如果使用了存在漏洞的库,比如旧版本的ImageMagick、GraphicsMagick,攻击者可以上传特制的图片文件,触发远程命令执行。这个漏洞编号CVE-2016-3714,影响深远。修复方案:第一,升级图片处理库到最新版本,或者切换到更安全的替代方案,比如使用libvips、Sharp这类内存安全的库。第二,在处理用户上传文件前,先做格式校验,不仅检查文件扩展名,还要检查文件头魔数。比如PNG文件的头是89 50 4E 47,JPEG是FF D8 FF。第三,使用沙箱环境处理文件,比如Docker容器或独立的处理服务,限制网络访问和系统调用,即使被攻破也无法进一步渗透。第四,限制处理超时和内存使用,防止解压炸弹攻击,一个几KB的压缩文件解压后可能膨胀到几GB。设置最大输出尺寸和像素数,超过阈值直接拒绝。第五,剥离文件的元数据,Exif信息中可能包含GPS坐标、设备信息等隐私数据,使用工具如ExifTool清理后再存储。
WebSocket与长连接资源的安全加固WebSocket连接建立后,客户端和服务端可以双向推送数据,常用于实时通信。但WebSocket的握手阶段是通过HTTP升级完成的,如果CORS配置不当或者没有验证Origin头,任意网站都可以建立WebSocket连接,冒充用户操作。修复时,服务端在WebSocket握手阶段必须验证Origin头,只允许受信任的域名建立连接。同时,WebSocket消息的负载也要做严格的输入验证和输出编码,防止在页面中渲染时造成XSS。另外,WebSocket连接本身是长连接,如果没有心跳机制和超时断开,攻击者可以建立大量空闲连接耗尽服务器文件描述符。设置空闲超时,比如60秒无消息就断开,并限制单个IP的连接数。对于需要广播消息的场景,做好权限控制,确保用户只能订阅自己有权限的频道,防止越权获取数据。
自动化监控与回归检测修复漏洞只是第一步,持续监控才能防止问题复发。在CI/CD流水线中集成安全扫描,检查HTML文件中外部资源是否都添加了SRI属性,可以用脚本解析HTML,提取所有跨域script和link标签,检查integrity属性是否存在。CSP头可以用自动化测试验证,确保没有出现unsafe-inline或unsafe-eval等宽松指令,除非经过特殊审批。静态资源目录的目录列表功能,用curl或wget模拟请求,检查响应中是否包含Index of字样。对于CORS配置,编写测试用例,用非白名单Origin头发起请求,验证是否返回403或者不包含Access-Control-Allow-Origin头。这些检查都应该集成到代码提交前的检查中,阻断不合规的变更合并到主分支。生产环境部署后,使用Content-Security-Policy的report-only模式收集违规报告,分析是否有漏网之鱼,逐步收紧策略,最终切换到强制模式。
