前端安全面试题(含 XSS、CSRF、HTTPS 等)

129 阅读22分钟

一、XSS(跨站脚本攻击)

1. 什么是 XSS 攻击,它的危害有哪些?

XSS 是指攻击者在网页中注入恶意脚本(如 JavaScript),当用户浏览该网页时,脚本在用户浏览器执行,可窃取用户 cookie、冒充用户操作、篡改页面内容等,危害用户数据安全和网站正常使用 。

2. XSS 有哪些常见类型,分别如何产生?

  • 存储型 XSS:恶意脚本被存储到服务器(如论坛发帖、评论存入数据库 ),用户访问含该脚本页面时触发,影响范围广。
  • 反射型 XSS:通过 URL 参数等传递恶意脚本,服务器反射性地将脚本输出到页面,用户点击恶意链接(含脚本参数)时触发,一般一次性。
  • DOM 型 XSS:基于浏览器 DOM 解析,恶意脚本通过修改页面 DOM 结构执行,由前端 JavaScript 处理数据不当(如直接用 innerHTML 渲染含脚本内容 )导致,全程未经过服务器存储 / 反射。

3. 如何防范 XSS 攻击?

  • 输入过滤:对用户输入(如表单、URL 参数 )校验、转义,过滤特殊字符(<>script 等关键字 ),限制输入内容格式。
  • 输出编码:将动态内容输出到页面时,进行 HTML 编码(如把 < 转成 &lt; )、JS 编码等,防止脚本执行。
  • 使用安全的 API:用 textContent 替代 innerHTML 渲染文本内容;避免滥用 evalnew Function 等执行动态代码的函数。

二、CSRF(跨站请求伪造)

1. 简述 CSRF 攻击原理及危害

CSRF 利用用户已登录的身份,在用户不知情下,诱导其浏览器向目标站点发送恶意请求(如转账、修改资料 )。攻击者构造包含目标站点请求的链接 / 页面,用户触发后,站点因用户已登录的 cookie 自动携带,可能执行未授权操作,导致用户数据被篡改、资产损失等。

2. 如何识别 CSRF 攻击场景?

存在跨域请求(尤其涉及用户敏感操作,如 POST 方式的资金变动、权限修改 ),且请求可通过用户浏览器自动携带身份凭证(cookie ),同时攻击者可构造诱导用户触发该请求的场景(如钓鱼链接、嵌入第三方页面的表单 ),就可能存在 CSRF 风险。

3. 防范 CSRF 攻击的常用手段有哪些?

  • 验证码:敏感操作(如转账 )增加验证码,强制用户交互,攻击者无法自动触发。
  • Token 验证:服务端生成 CSRF Token 并存储,前端请求时携带,服务端校验 Token 有效性,确保请求由合法页面发起(如 Django、Spring 等框架可集成 CSRF Token 机制 )。
  • SameSite Cookie:设置 Cookie 的 SameSite 属性,限制跨站请求时 Cookie 发送,如 SameSite=Strict 完全禁止跨站携带,Lax 允许部分安全跨站请求(GET 且为顶级导航等 )。
  • Referer 校验:服务端校验请求的 Referer 头,确认请求来自本站可信页面,但若 Referer 被篡改或浏览器不发送,存在局限性。

三、HTTPS 相关

1. HTTPS 和 HTTP 的主要区别是什么?

  • 传输安全:HTTP 明文传输,数据易被截获、篡改;HTTPS 基于 SSL/TLS 加密,数据传输更安全。
  • 端口:HTTP 默认 80 端口,HTTPS 默认 443 端口。
  • 证书:HTTPS 需配置 SSL 证书(由 CA 机构颁发 ),验证服务器身份;HTTP 无需证书。
  • 性能:HTTPS 因加密、证书校验等,性能开销略高于 HTTP,可通过优化 TLS 配置、使用 CDN 等缓解。

2. 简述 HTTPS 的加密过程(SSL/TLS 握手 )

大致流程:

  1. 客户端发起请求,支持的 TLS 版本、加密套件等信息发送给服务端。
  2. 服务端选 TLS 版本、加密套件,返回自身证书(含公钥 )。
  3. 客户端验证证书有效性(校验 CA 签名、有效期等 ),生成随机数(预主密钥 ),用服务端公钥加密后发送。
  4. 服务端用私钥解密得到预主密钥,双方基于预主密钥等生成会话密钥(对称加密密钥 )。
  5. 后续数据通过会话密钥对称加密传输,完成握手,开始通信。

3. 为什么需要 CA 证书,自签名证书有什么问题?

CA 证书由受信任的证书颁发机构签发,用于验证服务器身份合法性,客户端浏览器内置 CA 根证书,可自动校验。自签名证书未经过 CA 机构认证,浏览器会提示证书不可信,用户需手动信任,实际场景(尤其公网 )中会导致访问警告,影响用户体验且存在安全风险(无法证明服务器身份真实性 )。

四、风控策略与可信前端

1. 前端在风控策略中可承担哪些角色?

  • 行为采集:收集用户操作行为数据(如点击频率、滑动轨迹、停留时间 ),上传服务端辅助分析是否为异常操作(如暴力破解密码时的高频错误尝试 )。
  • 设备指纹:生成设备唯一标识(结合浏览器特征、硬件信息等 ),标记设备风险状态,服务端基于设备指纹识别恶意设备(如频繁注册账号的设备 )。
  • 实时校验:前端对部分简单规则(如验证码输入格式、交易金额范围 )本地校验,快速拦截明显异常请求,减轻服务端压力。

2. 如何理解 “可信前端”,实现可信前端面临哪些挑战?

“可信前端” 指前端环境、代码、交互可被信任,能有效抵御篡改、伪造等攻击。挑战包括:

  • 环境不可控:用户浏览器可被调试、篡改(如通过浏览器开发者工具修改前端代码、数据 ),难确保前端逻辑完全按预期执行。
  • 代码逆向:前端代码(尤其单页应用打包后的 JS 文件 )易被反编译,攻击者分析逻辑后伪造请求、绕过校验。
  • 数据伪造:即使前端有校验,攻击者可直接构造 HTTP 请求绕过,需结合服务端校验、加密等手段协同防护。

五、前端 - 服务端安全策略协同

1. 前端和服务端在安全防护上如何分工与协同?

  • 前端:聚焦输入输出安全(如 XSS 防护的输入过滤、输出编码 )、基础行为校验(简单风控规则 )、用户交互安全(如防止点击劫持 ),快速拦截部分明显风险。
  • 服务端:承担核心校验(如 CSRF Token 验证、业务逻辑权限校验 )、数据存储安全(防止 SQL 注入等 )、复杂风控策略(结合多维度数据分析异常 ),对前端传来的数据二次验证,确保安全边界。
  • 协同:前端传递必要安全凭证(如 CSRF Token、设备指纹 ),服务端校验并反馈;双方共享安全规则(如敏感操作的验证码要求 ),形成完整防护体系。

2. 举例说明前端 - 服务端配合防范安全风险的场景(以登录为例 )

  • 前端:校验用户名、密码格式(如长度、字符规范 ),防止无效请求;若启用图形验证码,前端验证输入是否与服务端下发的一致(简单校验 ),同时采集用户登录时的设备指纹、操作行为数据。
  • 服务端:校验用户名密码正确性;验证前端传来的验证码有效性(对比服务端存储的验证码 );结合设备指纹、行为数据判断是否为异常登录(如异地登录、短时间高频尝试 ),触发二次验证(如短信验证码 )或直接拦截。通过前后端配合,多层防护登录安全。

安全攻防

​安全策略

如何通过CSP策略防御基于SVG的XSS攻击?给出包含nonce与hash白名单的配置方案

为了防御基于SVG的XSS攻击,可通过以下CSP(Content Security Policy)策略配置方案,结合 nonce 和 hash 白名单机制:

​CSP 配置示例 http Content-Security-Policy: default-src 'none'; script-src 'nonce-{{RANDOM_NONCE}}' 'sha256-{{HASH_OF_TRUSTED_SCRIPT}}'; img-src 'self' data:; object-src 'none'; style-src 'self' 'unsafe-inline'; base-uri 'self'; form-action 'self'; frame-src 'none'; connect-src 'self'; font-src 'self'; report-uri /csp-report-endpoint; ​关键配置解析 ​script-src 指令

nonce-{{RANDOM_NONCE}} 为合法的内联脚本添加动态生成的随机数(nonce)。 服务器每次响应时生成唯一nonce,并注入到合法的

html

攻击者无法猜测或伪造此nonce,因此恶意SVG中的内联脚本将被CSP拦截。

sha256-{{HASH_OF_TRUSTED_SCRIPT}} 允许通过哈希白名单执行特定的静态内联脚本。 对已知安全的脚本内容计算哈希值(如 sha256),并添加到策略中。例如:

javascript // 计算哈希的命令(假设脚本内容为 'alert("safe");') echo -n 'alert("safe");' | openssl dgst -sha256 -binary | openssl base64 ​object-src 'none' 禁止通过 、、 加载外部资源,防止恶意SVG通过嵌套对象执行代码。

img-src 'self' data: 限制图片资源仅允许同源('self')和 data: URI(某些合法的Base64 SVG可能使用此协议),阻止加载外部恶意SVG。

style-src 'self' 'unsafe-inline' 允许同源样式表和内联样式(某些SVG依赖内联样式渲染)。若无需内联样式,可移除 'unsafe-inline' 并改用哈希或nonce。

​其他安全指令

default-src 'none':默认禁止所有未明确允许的资源。 base-uri 'self':防止通过 标签篡改资源路径。 form-action 'self':限制表单提交目标地址。 report-uri:收集CSP违规报告,便于监控攻击尝试。 ​防御原理 ​阻止恶意内联脚本 CSP默认禁止内联脚本(如 或 javascript: 协议),除非脚本满足以下任一条件:

包含有效的 nonce 属性且值与CSP策略匹配。 内容哈希值与CSP策略中的 sha256-... 等哈希白名单匹配。 ​限制SVG动态行为

SVG中嵌入的

每次HTTP响应需生成唯一且不可预测的nonce(如32字节随机Base64字符串)。 Nonce需注入到所有合法的内联脚本标签中,且不可重复使用。 ​哈希白名单维护

仅对静态且必要的内联脚本使用哈希白名单,避免滥用导致策略失效。 动态生成的脚本应改用nonce。 ​测试与监控

使用 Content-Security-Policy-Report-Only 模式先观察策略影响。 通过 report-uri 收集实际环境中的CSP违规报告,持续优化策略。 ​扩展防御措施 ​SVG文件上传过滤 在上传SVG时,后端应删除所有 通过上述配置,可有效防御基于SVG的XSS攻击,同时保持合法功能的正常运行。

实现CSRF Token的动态注入方案,需处理CDN缓存页面的令牌同步问题

为了实现CSRF Token的动态注入并解决CDN缓存页面的令牌同步问题,可采用以下分步方案:

  1. 动态Token获取与注入 ​页面缓存:CDN缓存不含CSRF Token的静态HTML页面,页面中预留Token占位符或包含动态获取Token的JavaScript代码。 ​异步请求Token:页面加载时,JavaScript发起请求(如GET /csrf-token)获取Token,该请求携带用户会话Cookie以确保会话关联性。 ​生成签名Token:服务器使用HMAC签名生成Token,包含会话ID、时间戳和签名,避免服务器存储Token。 javascript // 示例:生成Token(Node.js) const crypto = require('crypto'); app.get('/csrf-token', (req, res) => { const { id: sessionId } = req.session; const timestamp = Date.now(); const hmac = crypto.createHmac('sha256', process.env.CSRF_SECRET); hmac.update(${sessionId}:${timestamp}); const signature = hmac.digest('hex'); res.json({ token: ${sessionId}:${timestamp}:${signature} }); });
  2. Token验证机制 ​嵌入请求:JavaScript将Token注入表单隐藏字段(如)或AJAX请求头(如X-CSRF-Token)。 ​服务器验证:验证Token签名、时效性及会话匹配。 javascript // 示例:验证中间件(Node.js) function verifyCsrfToken(req, res, next) { const submittedToken = req.body._csrf || req.headers['x-csrf-token']; const [sessionId, timestamp, signature] = submittedToken.split(':'); const hmac = crypto.createHmac('sha256', process.env.CSRF_SECRET); hmac.update(${sessionId}:${timestamp}); const expectedSig = hmac.digest('hex'); if (signature !== expectedSig) return res.status(403).send('Invalid Token'); if (Date.now() - timestamp > 5 * 60 * 1000) return res.status(403).send('Token Expired'); if (sessionId !== req.session.id) return res.status(403).send('Session Mismatch'); next(); }
  3. CDN缓存策略优化 ​避免缓存Token端点:配置/csrf-token接口的Cache-Control为no-store, private,确保每个请求直达服务器。 ​分离静态与动态内容:CDN缓存页面主体,动态Token通过AJAX加载,减少服务器负载。
  4. 安全增强措施 ​HttpOnly Cookie:会话Cookie标记为HttpOnly,防止XSS窃取。 ​加密强度:使用强加密算法(如SHA-256)和妥善保管密钥,防止Token伪造。 ​时效性控制:Token有效期宜短(如5分钟),减少重放攻击窗口。
  5. 异常处理 ​提交前校验:确保表单提交前Token已加载,否则提示用户刷新页面。 ​错误响应:Token无效时返回403,前端可引导用户重新获取Token。 此方案通过动态注入与会话绑定的加密Token,既利用CDN缓存优化性能,又确保CSRF防护有效。异步获取机制避免了缓存导致的Token冲突,签名验证兼顾安全性与无状态服务需求。

如何通过CSP防御SVG的XSS攻击?配置包含nonce与hash白名单的混合策略

了通过CSP防御SVG中的XSS攻击,并配置包含nonce和hash的混合策略,可按照以下步骤进行:

​1. 理解CSP对SVG脚本的约束 SVG中的内联脚本(直接嵌入HTML或通过/加载)受script-src指令控制。 通过标签加载的SVG通常不会执行脚本(现代浏览器默认行为),但仍需限制img-src来源。 ​关键指令:script-src(核心)、object-src(限制/加载资源)、default-src(全局回退)。 ​2. 配置混合CSP策略 ​基本结构示例 http Content-Security-Policy: script-src 'nonce-{随机值}' 'sha256-{哈希值}' 'strict-dynamic'; object-src 'none'; img-src 'self'; default-src 'none'; ​script-src:允许带特定nonce的脚本和已知哈希的脚本。 ​object-src 'none':阻止通过加载外部SVG(减少攻击面)。 ​img-src 'self':仅允许同源图片,防止恶意SVG通过加载(尽管脚本通常不执行,仍需谨慎)。 ​3. 实现Nonce动态脚本 ​生成Nonce:服务器为每个请求生成唯一随机数(如nonce="ABC123")。 ​注入Nonce到内联SVG: html

​CSP头:包含script-src 'nonce-ABC123',匹配内联脚本的nonce属性。 ​4. 使用Hash白名单静态脚本 ​计算脚本哈希:对已知安全的静态脚本内容生成SHA256哈希。 bash 示例:计算哈希 echo -n "console.log('安全脚本');" | openssl dgst -sha256 -binary | openssl base64 ​将哈希加入CSP: http script-src 'sha256-基64哈希值' ​5. 处理外部SVG文件 ​避免执行脚本:通过CSP禁止高危加载方式: http object-src 'none'; # 阻止/ ​内容校验:上传的SVG文件应经过服务器端检查,移除所有脚本(正则匹配<script>标签)。 ​强制静态资源:若必须加载外部SVG,使用<img>标签并限制img-src为受信任源。 ​6. 严格限制其他指令 ​禁止内联事件和eval: http script-src 'unsafe-inline' 'unsafe-eval'; 切勿使用! ​正确做法:完全避免这些关键字,依赖nonce和hash。 ​7. 测试与验证 ​浏览器控制台:检查CSP违规报告。 ​在线工具:使用CSP Evaluator分析策略强度。 ​自动化测试:模拟恶意SVG上传和加载,确认脚本被阻止。 ​示例完整配置 http Content-Security-Policy: script-src 'nonce-ABC123' 'sha256-基64哈希值'; object-src 'none'; img-src 'self'; style-src 'self'; default-src 'none'; ​注意事项 ​浏览器兼容性:确保目标浏览器支持nonce和hash(现代浏览器均支持)。 ​动态Nonce:每次页面加载需更换Nonce,防止猜测攻击。 ​最小化权限:仅允许必要的脚本,避免过度依赖hash白名单。 通过结合nonce(动态脚本)和hash(静态脚本),并严格限制资源加载策略,可有效防御SVG中的XSS攻击。 实现CSRF Token的动态注入方案,解决CDN缓存页面的令牌同步问题

设计前端灰度发布方案,支持AB测试与异常流量自动熔断

为了设计一个支持AB测试与异常流量自动熔断的前端灰度发布方案,以下是分阶段的实施方案:

​一、核心架构设计 ​流量分配层

使用动态路由策略(如用户ID哈希、设备类型、地域)分配用户到不同版本。 支持按比例分配(如5%流量到新版本)或定向规则(如特定用户群体)。 ​AB测试分组:通过一致性哈希算法确保用户固定分组,避免数据偏差。 ​版本管理

​动态配置中心:存储版本规则(如版本号、白名单、流量比例),实时推送到前端。 ​特性开关(Feature Toggle)​:前端通过API获取当前用户的版本配置,动态渲染对应UI。 ​数据监控与埋点

​前端埋点:在关键节点(如页面加载、按钮点击)上报数据,包含版本标识、用户ID、时间戳。 ​监控指标: 性能指标(加载时间、JS错误率) 业务指标(转化率、点击率) 异常指标(HTTP错误码、接口超时率) ​熔断机制

​阈值设置:定义熔断触发条件(如错误率>5%、流量突增200%)。 ​自动熔断:监控系统实时检测异常,触发流量切换至稳定版本。 ​回滚策略:自动回退到上一个稳定版本,并通知运维团队。 ​二、技术实现细节 ​流量分配实现

​前端SDK:封装分组逻辑,根据用户ID哈希或Cookie分配版本。 javascript // 示例:根据用户ID哈希分配AB组 function getABGroup(userId) { const hash = hashCode(userId) % 100; return hash < 10 ? 'A' : 'B'; // 10%流量到A组 } ​Nginx/API网关:后端路由层支持按Header或Cookie转发请求。 ​动态配置下发

​配置中心:使用Consul、Apollo或自建服务,前端定期轮询或WebSocket监听更新。 ​本地缓存:前端缓存配置,避免接口不可用导致页面崩溃。 ​异常检测与熔断

​实时监控:集成Prometheus + Grafana,设置报警规则。 ​熔断执行:通过API网关或服务网格(如Istio)动态修改路由规则。 yaml Istio VirtualService 示例:熔断时切换流量 http:

  • route:
    • destination: host: stable-service weight: 100
    • destination: host: canary-service weight: 0 ​数据上报与分析

​日志收集:使用ELK(Elasticsearch+Logstash+Kibana)或埋点SDK(如Sentry、Google Analytics)。 ​AB测试分析:通过SQL或BI工具(如Looker)对比版本效果。 ​三、操作流程 ​灰度发布流程

发布新版本到预发环境,配置5%流量进入灰度。 监控性能及业务指标,逐步放大流量至50%。 若数据达标,全量发布;否则回滚。 ​熔断流程

监控系统检测到错误率超过阈值。 自动将流量切回至稳定版本,触发告警通知。 开发团队排查问题,修复后重新发布。 ​四、注意事项 ​用户体验一致性:同一用户始终访问同一版本(通过Cookie/localStorage持久化分组)。 ​降级策略:熔断时展示友好提示(如“系统维护中”)。 ​安全与合规:确保用户数据隐私,埋点脱敏处理。 ​五、示例工具链 ​流量分配:Nginx, AWS Route53, Cloudflare Workers ​配置中心:AWS AppConfig, Apollo, Firebase Remote Config ​监控告警:Datadog, New Relic, Prometheus + AlertManager ​AB测试分析:Optimizely, Google Optimize, 自建分析平台 通过以上方案,可实现安全可控的灰度发布,快速验证功能效果,并在异常时自动熔断保障系统稳定性。

Service Worker离线降级策略,实现关键资源预缓存与API请求队列重试

为了实现Service Worker的离线降级策略,包括关键资源预缓存和API请求队列重试,可以按照以下步骤进行设计和实现:

​一、关键资源预缓存

  1. ​缓存策略设计 ​预缓存核心资源:在Service Worker安装阶段,将HTML、CSS、JS、字体、图标等静态资源提前缓存。 ​版本控制:使用缓存版本号(如CACHE_NAME = 'v1'),确保资源更新时能触发缓存刷新。 ​增量更新:每次发布新版本时,更新缓存版本号并重新缓存资源。
  2. ​实现步骤 ​Install阶段:在install事件中,使用Cache.addAll()预缓存资源。

javascript const CACHE_NAME = 'v1'; const PRE_CACHE_RESOURCES = ['/', '/styles.css', '/app.js'];

self.addEventListener('install', (event) => { event.waitUntil( caches.open(CACHE_NAME) .then(cache => cache.addAll(PRE_CACHE_RESOURCES)) ); }); ​Activate阶段:清理旧缓存。

javascript self.addEventListener('activate', (event) => { event.waitUntil( caches.keys().then(cacheNames => { return Promise.all( cacheNames.map(name => { if (name !== CACHE_NAME) return caches.delete(name); }) ); }) ); }); ​Fetch阶段:优先返回缓存的核心资源,其他资源尝试网络请求。

javascript self.addEventListener('fetch', (event) => { // 核心资源:缓存优先 if (PRE_CACHE_RESOURCES.some(url => event.request.url.includes(url))) { event.respondWith( caches.match(event.request).then(cachedResponse => { return cachedResponse || fetch(event.request); }) ); } else { // 非核心资源:网络优先,失败后降级到缓存(如有) event.respondWith( fetch(event.request).catch(() => caches.match(event.request)) ); } }); ​二、API请求队列重试

  1. ​请求队列设计 ​存储方式:使用IndexedDB存储失败的请求,记录方法、URL、headers、body等信息。 ​幂等性处理:仅重试GET请求,或确保后端支持幂等性POST/PUT。 ​网络检测:通过navigator.onLine和定期心跳检测网络状态。 ​重试限制:为每个请求设置最大重试次数(如3次)。
  2. ​实现步骤 ​拦截并存储失败请求:

javascript self.addEventListener('fetch', (event) => { if (isApiRequest(event.request)) { event.respondWith( fetch(event.request.clone()).catch(async () => { // 存储请求到队列 const requestData = await serializeRequest(event.request); await storeFailedRequest(requestData); return Response.error(); // 返回错误或降级数据 }) ); } });

async function serializeRequest(request) { return { url: request.url, method: request.method, headers: [...request.headers.entries()], body: await request.clone().json(), }; } ​网络恢复后重试请求:

javascript function retryFailedRequests() { let db; const request = indexedDB.open('requestsDB'); request.onsuccess = () => { db = request.result; const tx = db.transaction('requests', 'readwrite'); const store = tx.objectStore('requests'); const getAll = store.getAll();

getAll.onsuccess = async () => {
  for (const requestData of getAll.result) {
    try {
      await fetch(requestData.url, {
        method: requestData.method,
        headers: new Headers(requestData.headers),
        body: JSON.stringify(requestData.body),
      });
      store.delete(requestData.id); // 成功则删除
    } catch (error) {
      requestData.retries++;
      if (requestData.retries < 3) store.put(requestData);
      else store.delete(requestData.id); // 超过重试次数
    }
  }
};

}; }

// 监听网络恢复 self.addEventListener('message', (event) => { if (event.data === 'online') retryFailedRequests(); }); ​前端触发网络状态检测:

javascript // 前端代码 window.addEventListener('online', () => { if (navigator.serviceWorker.controller) { navigator.serviceWorker.controller.postMessage('online'); } }); ​三、优化与注意事项 ​缓存更新:在Service Worker中使用stale-while-revalidate策略,优先返回缓存并后台更新资源。 ​请求过滤:避免缓存用户敏感数据或个性化内容。 ​错误降级:对于API请求失败,返回预定义的降级数据(如本地存储的默认数据)。 ​安全处理:重试请求时携带最新的身份验证Token(可从IndexedDB获取)。 ​性能监控:记录缓存命中率和请求重试成功率,优化策略。 ​四、完整示例代码 ​Service Worker (sw.js):

javascript const CACHE_NAME = 'v1'; const PRE_CACHE_RESOURCES = ['/', '/styles.css', '/app.js']; const API_CACHE_NAME = 'api-data';

self.addEventListener('install', (event) => { event.waitUntil( caches.open(CACHE_NAME) .then(cache => cache.addAll(PRE_CACHE_RESOURCES)) ); });

self.addEventListener('activate', (event) => { event.waitUntil( caches.keys().then(keys => Promise.all(keys.map(key => key !== CACHE_NAME && caches.delete(key))) ) ); });

self.addEventListener('fetch', (event) => { // 关键资源:缓存优先 if (PRE_CACHE_RESOURCES.some(url => event.request.url.includes(url))) { event.respondWith( caches.match(event.request).then(cached => cached || fetch(event.request)) ); } // API请求:网络优先,失败后入队 else if (event.request.url.startsWith('/api/')) { event.respondWith( fetch(event.request).catch(async () => { const requestData = await serializeRequest(event.request); await storeFailedRequest(requestData); return Response.error(); }) ); } // 其他资源:网络优先,失败后降级 else { event.respondWith( fetch(event.request).catch(() => caches.match(event.request)) ); } });

self.addEventListener('message', (event) => { if (event.data === 'online') retryFailedRequests(); }); ​前端触发网络检测:

javascript // 主线程代码 if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js'); window.addEventListener('online', () => { navigator.serviceWorker.controller?.postMessage('online'); }); } 通过以上步骤,可以实现一个健壮的离线优先应用,确保核心资源始终可用,并在网络恢复后自动同步用户操作

攻击防御(XSS/CSRF、CSP策略)

攻击防御(XSS/CSRF、CSP策略)详解 ​1. XSS(跨站脚本攻击)​ 类型:

​存储型 XSS:恶意脚本持久化存储在服务器(如数据库),用户访问时加载执行(如评论区注入)。 ​反射型 XSS:恶意脚本通过URL参数传递,服务器返回时未转义直接输出(如钓鱼链接)。 ​DOM型 XSS:前端脚本直接操作DOM时触发,无需经过服务器(如document.write)。 防御措施:

​输入验证与过滤:对用户输入进行严格校验(如正则表达式),但避免依赖此作为唯一防线。 ​输出转义:根据上下文(HTML/JS/URL)使用合适的编码(如HtmlEncode、JavaScriptEncode)。 ​CSP(内容安全策略)​:限制脚本来源,禁止内联脚本(见下文)。 ​安全API:使用textContent代替innerHTML,利用现代框架(React/Vue)的自动转义机制。 ​HTTP-only Cookie:防止XSS窃取Cookie(减轻影响,非根治)。 ​2. CSRF(跨站请求伪造)​ 攻击原理:利用用户已登录状态,诱导其触发恶意请求(如自动发送转账请求)。

防御措施:

​CSRF Token: 服务器生成唯一Token,嵌入表单或请求头。 验证请求时检查Token合法性(需确保随机性且保密)。 ​SameSite Cookie属性: Strict:完全禁止跨站请求携带Cookie。 Lax(默认):允许安全HTTP方法(如GET)跨站携带Cookie(适用于导航跳转)。 None:需配合Secure(仅HTTPS)。 ​二次验证:敏感操作需重新输入密码或验证码。 ​避免副作用GET请求:遵循REST规范,仅用POST/PUT修改数据。 ​3. CSP(内容安全策略)​ 作用:通过HTTP头限制资源加载,减少XSS和数据泄露风险。

配置示例:

http Content-Security-Policy: default-src 'self'; script-src 'self' trusted.cdn.com 'nonce-abc123'; style-src 'self'; img-src *; frame-src 'none' ​常用指令: default-src:默认资源加载策略。 script-src:控制脚本来源('self'、'unsafe-inline'、nonce、哈希)。 style-src:样式表来源。 img-src:图片来源。 frame-src:限制嵌入框架(防点击劫持)。 高级用法:

​Nonce/Hash:允许特定内联脚本执行(nonce="随机值"或哈希值)。 ​报告机制:通过report-uri收集违规日志,逐步优化策略。 注意事项:

避免过度宽松配置(如script-src *)。 分阶段实施,利用Content-Security-Policy-Report-Only测试。 ​4. 其他关键点 ​XSS与CSRF关联:XSS漏洞可能绕过CSRF Token(因攻击者可窃取Token)。 ​浏览器安全机制: 弃用X-XSS-Protection,优先使用CSP。 正确设置Content-Type防止MIME混淆攻击。 ​CSP防数据泄露:限制图片/字体等资源的来源,防止数据外泄。 总结:

​XSS防御:转义 + CSP + 安全API。 ​CSRF防御:Token + SameSite + 敏感操作验证。 ​CSP配置:最小化资源权限,监控违规报告。 通过综合策略和持续测试,可显著提升Web应用安全性。