评论

前端XSS攻击

本文主要是通过例子来介绍xss攻击类型,以及如何防御xss攻击。

一、前言

随着互联网的高速发展,信息安全问题已经成为企业最为关注的焦点之一,而前端又是引发企业安全问题的高危据点。在移动互联网时代,前端人员除了传统的 XSS、CSRF 等安全问题之外,又时常遭遇网络劫持、非法调用 Hybrid API 等新型安全问题。当然,浏览器自身也在不断在进化和发展,不断引入 CSP、Same-Site Cookies 等新技术来增强安全性,但是仍存在很多潜在的威胁,这需要前端技术人员不断进行“查漏补缺”。

二、XSS定义

在给大家介绍xss前,大家先来看一个例子:

<html>
    <title>Welcome!</title>
     Hi
    <script>
        var pos=document.URL.indexOf("name=")+5;
        document.write(document.URL.substring(pos,document.URL.length));
    </script>
    Welcome to you
</html>

这个例子是个欢迎页面,name是截取URL中get过来的name参数
正常操作:
http://域名A/welcome.html?name=Joe

非正常操作:
http://域名A/welcome.html?name=<script>alert(document.cookie)</script>

当执行非正常操作时:

完了,我们的cookie数据被截取了,XSS攻击出现了。

为什么会这样呢?我们来看一下:
1、受害者的浏览器接收到这个非正常操作的链接,发送HTTP请求到域名A并且接受到上面的HTML页;
2、受害者的浏览器开始解析这个HTML为DOM,DOM包含一个对象叫document,document里面有个URL属性,这个属性里填充着当前页面的URL;
3、当解析器到达javascript代码,它会执行它并且修改你的HTML页面。倘若代码中引用了document.URL,那么,这部分字符串将会在解析时嵌入到HTML中,然后立即解析,同时,javascript代码会找到(alert(…))并且在同一个页面执行它,这就产生了xss。

那么什么是XSS呢?
xss跨站脚本攻击(Cross Site Scripting),指攻击者在网页中嵌入脚本代码(例如js代码), 当用户浏览此网页时,脚本就会在用户的浏览器上执行,从而达到攻击者的目的。比如获取用户的Cookie,导航到恶意网站,携带木马等。
大部分的xss漏洞都是由于没有处理好用户的输入,导致攻击脚本在浏览器中执行,这就是跨站脚本漏洞的根源。

三、XSS攻击类型

XSS攻击分为存储型、反射型和 DOM 型三种。

1、存储型 XSS
a: 攻击者将恶意代码提交到目标网站的数据库中。
b: 用户打开目标网站时,网站服务端将恶意代码从数据库取出,拼接在 HTML 中返给浏览器。
c: 用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行。
d: 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。
简单例子:
表单中填写数据:

<input type=“text” name=“content” value=“这里是用户填写的数据”>

正常操作:
1、用户是提交相应留言信息;
2、将数据存储到数据库;
3、其他模块要显示保存的数据,从数据库查询出来并显示。
非正常操作:
1、攻击者在value填写<script>alert(‘foolish!’)</script>【或者html其他标签(破坏样式。。。)、一段攻击型代码】;
2、将数据存储到数据库中;
3、其他用户取出数据显示的时候,将会执行这些攻击性代码

这种攻击常见于带有用户保存数据的网站功能,如论坛发帖、商品评论、用户私信等。

2、反射型 XSS
a: 攻击者构造出特殊的 URL,其中包含恶意代码。
b: 用户打开带有恶意代码的 URL 时,网站服务端将恶意代码从 URL 中取出,拼接在 HTML 中返回给浏览器。
c: 用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行。
d: 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。
简单例子:
正常发送消息:
http://域名A/message.html?message=Hello,World!
接收者将会接收信息并显示Hello,Word
非正常发送消息:
http://域名A/message.html?message=<script>alert(document.cookie)</script>
接收者接收消息显示的时候将会弹出警cookie信息

反射型 XSS 跟存储型 XSS 的区别是:存储型 XSS 的恶意代码存在数据库里,反射型 XSS 的恶意代码存在 URL 里。
反射型 XSS 漏洞常见于通过 URL 传递参数的功能,如网站搜索、跳转等。由于需要用户主动打开恶意的 URL 才能生效,攻击者往往会结合多种手段诱导用户点击。POST 的内容也可以触发反射型 XSS,只不过其触发条件比较苛刻(需要构造表单提交页面,并引导用户点击),所以非常少见。

3、DOM 型 XSS
a: 攻击者构造出特殊的 URL,其中包含恶意代码。
b: 用户打开带有恶意代码的 URL。
c: 用户浏览器接收到响应后解析执行,前端 JavaScript 取出 URL 中的恶意代码并执行。
d: 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网 站接口执行攻击者指定的操作。
简单例子:

<script>
document.body.innerHTML="<div style=visibility:visible;><h1>This is DOM XSS</h1></div>";
</script>

攻击者可以利用innerHTML来篡改页面
DOM 型 XSS 跟前两种 XSS 的区别:DOM 型 XSS 攻击中,取出和执行恶意代码由浏览器端完成,属于前端 JavaScript 自身的安全漏洞,而其他两种 XSS 都属于服务端的安全漏洞。

四、如何预防XSS攻击

1、输入过滤,对用户提交的数据进行有效性验证,仅接受指定长度范围内并符合我们期望格式的的内容提交,阻止或者忽略除此外的其他任何数据。比如:电话号码必须是数字和中划线组成,而且要设定长度上限。过滤一些些常见的敏感字符,例如:< > ‘ “ & # \ javascript expression  “onclick=”  “onfocus”;过滤或移除特殊的Html标签, 例如: <script>, <iframe> ,  < for <, > for >, &quot for;过滤JavaScript 事件的标签,例如 “onclick=”, “onfocus” 等等。

例子1:

<input  v-model="value"  type="text" />

Input输入值带有html标签时,如value=”<b>aaaaaaaa</b>”,调接口提交到后台的没有做HtmlEncode转码,那么面页输出的将会是: aaaaaaaa粗体。原理是因为提交的内容里带有html标签<b></b>。浏览器解析页面源码时把用户提交的内容当成了html代码。所以才会输出粗体的 aaaaaaaa
解决方案:
A:前端提交前转码:encodeHtml(value);
B:后端java转码:Encoder.encodeHtml(value);如果是Param类,直接使用.getHtmlString(key)。

例子2:
提交的数据url编码,数据提交时一定要对传参数的数进行URLencode处理,假如提交内容 aaaa&344353中文啊&&&&aaa=bbbb&&&fsdfsdsdf,如果没有通过 URLencode处理的话,那么提交的链接自然是http://www.baidu.com/?val=aaaa&344353中文啊&&&&aaa=bbbb&&&fsdfsdsdf
这样后台取得的val的值会是aaaa。并且还会有一个aaa=bbbb。主要造成这现象的原因是提交的内容包含了"&“和”=",没有对这些特殊的字符做转义处理,所以造成了后台取参错误。
解决方案:
A:前端提交参数前:encodeUrl(url);
B:后端拿到数据进行编码:Encoder.encodeURL(url);

其他例子解决方案:
A:对输入的数据限制长度范围;

<input v-model="value" maxlength="20" type="text" />

B:对输入的数据进行校验(正则表达式)

var re = /^[a-zA-z]\w{3,15}$/;
If(re.test(value)){
return true;
}else{
return false;
}

2、输出编码,当需要将一个字符串输出到Web网页时,同时又不确定这个字符串中是否包括XSS特殊字符(如< > &‘”等),为了确保输出内容的完整性和正确性,可以使用编码(HTMLEncode)进行处理。
例子1:
输出js数据时,要先编码,否则有可能因为"等造成截断。如var a = ‘<%=aString %>’;假如aString的值是"aa’;alert();’"。没有encodeJs的页面就会执行alert了。而有encodeJs的页面则会把输出内容里的单引号都替换成:\x22,双引号替换成\x27。这样就不会造成js里的引号截断了。
解决方案:
A:前端JS函数:$.toJSON(html);
B:后端java函数:Encoder.encodeJson(html);如果是Param类,直接使用.getJsonString(key)。

例子2:
<a href=”url”>跳转链接</a>
java处理代码时获取url参数并且不做任何处理,直接在html标签的事件中植入攻击代码。
当用户访问的链接是xxx/sigup.jsp?url=");alert(document.cookie)😭";
点击跳转链接按钮的时候,就会弹出cookie的信息

解决方案:
A:前端把href换成onclick方法:
Html:

<a onclick=”openUrl(url)”>跳转链接</a>

Js:

Function openUrl(url) {
url = encodeUrl(url);
Window.location.href = url;
}

B:后台调用方法: Encoder.encodeURL(value2);
如果是Param类,直接使用.getUrlString(key)。

其他案例:
A:把字符串转换为写在html标签中属性值:
字符串是输出在html标签中的属性里,所以首先要防止字符串里的引号造成属性的引号截断。所以至少字符串里的引号就要转义了。当然,还有额外的一些特殊字符也是要转义的。
解决方案:
js函数:encodeHtmlAttr(html);
 java函数 :Encoder.encodeHtmlAttr(html);如果是Param类,直接使用getHtmlAttrString;
如果是输出在js里初始化的话,尽量使用jquery的attr/val等函数来赋值( encode json 数据 ),降低复杂度。
B: input-text用例  :<s>a&aa</s>'b"c
在页面中直接初始化时,要使用:<input value="<%=Encoder.encodeHtml(str)%>"/>
在JS中初始化时,要使用:$("#xxx").val("<%=Encoder.encode.Json(str)%>");
C:  textarea用例 :
<textarea><s>a&aa</s>'b"c</textarea>bbb,不在页面中直接初始化textarea。
在JS中初始化:$("#xxx").val("<%=Encoder.encodeJson(str)%>")

3、DOM型的XSS攻击防御,把变量输出到页面时要做好相关的编码转义工作,如要输出到 <script>中,可以进行JS编码;要输出到HTML内容或属性,则进行HTML编码处理。根据不同的语境采用不同的编码处理方式。
例子:
当用户访问路径为xxx/pr.jsp?keywordCond=aaa");alert(document.cookie)😭"时候,直接scripts.append输出:scripts.append(keywordCond),就会弹出cookie的信息。

解决方案:
A:在append前,将keywordCond进行编码

keywordCond = encodeUrlComponent(keywordCond);
scripts.append(keywordCond)

B:后台调用方法:

String keywordCond = Encoder.encodeHtmlJs(keywordCond);

1、将重要的cookie标记为http only,   这样的话当浏览器向Web服务器发起请求的时就会带上cookie字段,但是在脚本中却不能访问这个cookie,这样就避免了XSS攻击利用JavaScript的document.cookie获取cookie。
例子:
A:Tomcat服务器,在Tomcat下的conf的web.xml设置如下信息。

<session-config>
<cookie-config>
<http-only>true</http-only>
</cookie-config>
<session-config>

B:resin服务器,在resin.conf下设置session信息。

<session-config>
<enable-cookies>true</enable-cookies>
<cookie-config>
<http-only>true</http-only>
</cookie-config>
</session-config>
五、总结

XSS的攻击五花八门,毕竟那么多情况场景,开发人员无法一一照顾过来,我们前端和后端尽可能对提交数据做好过滤。开发人员要注意在正确的地方使用正确的编码方式,有时为了防御XSS,在一个地方我们需要联合HTMLEncode、JavaScriptEncode、URLEncode进行编码,甚至是叠加,并不是固定一种方式编码,具体情况具体分析。

针对XSS攻击类型,我们日常开发需要做好以下部分:
1.在HTML标签、属性中输出时,用HTMLEncode。
2.在script标签中输出时,用JavaScriptEncode。
3.在地址中输出一般如果变量是整个URL,则用URLEncode。
4.在提交数据前,做一些正则校验,或者在输入框中做一些限制。

六、参考资料

1、http://it.faisco.cn/page/forum/articleDetail.jsp?articleId=1656
2、http://web.jobbole.com/95312

点赞 3
收藏
评论

3 个评论

  • ㅤ
    2019-06-12

    受教了

    2019-06-12
    赞同
    回复
  • 圆。
    圆。
    2019-06-11

    小程序是无 document 概念吧

    2019-06-11
    赞同
    回复
  •   Fast Light  
      Fast Light  
    2019-06-10

    普通H5会受到XSS影响,小程序不会。

    2019-06-10
    赞同
    回复
登录 后发表内容