前端XSS相关整理

当然了,也不是说要忽略其他安全问题:后端范畴、DNS劫持、HTTP劫持、加密解密、钓鱼等 CSRF主要是借用已登录用户之手发起“正常”的请求,防范措施主要就是对需要设置为Post的请求,判断Referer以及token的一致性,本文不展开 相对来说,XSS的内容就非常庞大了,下面就来整理一下一些XSS的知识点。比较匆忙,可能有点乱哈~ 一、XSS 恶意攻击者向页面中注入可执行的JS代码来实现XSS的攻击。 如常见的 复制代码 Payload:
[输出]
复制代码 这个 Payload 可以从编辑区域而来 当然,输入和输出的位置还可以出现在其他地方,根据输入输位置的不同,可以形成不同类型的XSS,相应的防范措施也不同。 1.1 XSS的分类 一般来说,可以将XSS分为三类:反射型XSS、存储型XSS、DOM-base 型XSS 1.1.1 反射型XSS 大多通过URL进行传播,发请求时,XSS代码出现在URL中,提交给服务端。服务端未进行处理或处理不当,返回的内容中也带上了这段XSS代码,最后浏览器执行XSS代码 比如在 php的smarty模板中直接获取url的参数值 复制代码 Payload: http://local.abc.com/main/?r=abc/index¶m=
<{$smarty.get.param}>
复制代码 X-XSS-Protection 新版Chrome和Safari中,已自动屏蔽了这种XSS,形如 这个屏蔽是由 XSS Auditor操作的,它由HTTP返回头部进行控制,有四个可选值 复制代码 X-XSS-Protection : 0 关闭浏览器的XSS防护机制 X-XSS-Protection : 1 删除检测到的恶意代码(如果不指定,IE将默认使用这个) X-XSS-Protection : 1; mode=block 如果检测到恶意代码,将不渲染页面 (如果不指定,Chrome将默认使用这个) X-XSS-Protection : 1; report= 删除检测到的恶意代码,并通过report-uri发出一个警告。 复制代码 前三个在IE和Chrome中有效,最后一个只在Chrome中有效 可以手动在设置请求头看看变化 header('X-XSS-Protection: 1; mode=block'); 建议配置为后两个的结合,禁止页面渲染并进行上报 header('X-XSS-Protection: 1; mode=block; report=www.xss.report'); 不建议仅仅配置为1,因为它删除恶意代码的功能有时比较鸡肋,可能会弄巧成拙。 另外,这个配置只能充当辅助作用,不能完全依赖,其也可能会产生一些问题 不过在Firefox中并未屏蔽 在IE中的XSS Filter也默认也开启了屏蔽,也可手动关闭试试,或者通过HTTP头部进行控制 1.1.2 存储型XSS 提交的XSS代码会存储在服务器端,服务端未进行处理或处理不当,每个人访问相应页面的时候,将会执行XSS代码 如本文开始的第一个例子 1.1.3 DOM-base 型XSS 这个类型和反射型的有点类似,区别是它不需要服务端参与 比如在JS中直接获取URL中的值 复制代码 Payload: alert('xss') http://local.abc.com/main/?r=abc/index#alert('xss') 复制代码 另外,有些攻击方式的类型是单一的,有些是混合的。防范攻击,不应仅根据类型来防范,而应根据输入输出的不同来应对。 在反射型和DOM-base型中,一般会通过设置一些有诱导性质的链接,用户点击链接后则触发链接中的XSS Content Security Policy(CSP)内容安全策略 为了防范XSS,CSP出现了。 CSP 的实质就是白名单制度,开发者明确告诉客户端,哪些外部资源可以加载和执行,提供了这种白名单之后,实现和执行则由浏览器完成 通过一系列的自定义配置,可以在很大程度上防止恶意脚本的攻击,建议进行配置。 不过策略比较新,在各浏览器也有一些兼容性的问题。另外,似乎还是可以通过一些手段绕过的,这里就不展开了 Cookie 配置 大多使用cookie来实现对用户的认证。如果攻击者拿到了这个认证cookie,就可以登录了用户的账号了 XSS的主要目的是为了得到cookie,当然也不仅是为了获取cookie cookie安全注意点 Httponly:防止cookie被xss偷 https:防止cookie在网络中被偷 Secure:阻止cookie在非https下传输,很多全站https时会漏掉 Path :区分cookie的标识,安全上作用不大,和浏览器同源冲突 通过设置 cookie的几个属性,可以在一定程度上保障网站的安全 不过并没有十全十美的东西,虽然攻击门槛提高了,但HttpOnly在某些特定情况下还是能绕过的,道高一尺魔高一点一尺呀 1.2 执行JS代码 XSS的目的一般是盗取cookie,一般需要通过JS 的 document.cookie来获取这个值。 所以要先思考的是:在什么地方可以执行JS相关的代码 然后要思考的是:攻击者能不能在这些地方构造出能够执行的脚本 1.2.1 1.2.2 HTML中的某些事件 复制代码 复制代码 1.2.3 javascript: 伪协议 复制代码 test location.href = 'javascript:alert(1)' 复制代码 对于事件的执行触发,是有机会防御的,围观 这篇文章 1.2.4 base64编码的 data: 伪协议 复制代码 Payload: ,它的base64编码为PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K test 复制代码 1.2.5 css中的expression表达式 仅在IE8以下才支持expression,可以忽略这个了 1.2.6 css中的src 很多文章都说到这个payload,然鹅并没有生效,不知真假 根据一些讨论,在css中是很难实现xss的 复制代码 .abc { background: url(...) } 复制代码 1.2.7 使用 eval、new Function、setTimeout 执行字符串时 复制代码 setTimeout('alert(1)'); eval('alert(2)'); var f = new Function('alert(3)'); f(); 复制代码 1.3 编码与解码 防范XSS,比较通用的做法是:提交保存前对特殊字符进行过滤转义,进行HTML实体的编码 复制代码 var escape = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''', '`': '`' }; 复制代码 事实上,仅仅这样做还是不够的 那为什么要进行HTML实体的编码呢? 这涉及到浏览器的解析过程。 浏览器在解析HTML文档期间,根据文档中的内容,会经过 HTML解析、JS解析和URL解析几个过程 首先浏览器接收到一个HTML文档时,会触发HTML解析器对HTML文档进行词法解析,这完成HTML解码工作并创建DOM树。 如果HTML文档中存在JS的上下文环境,JavaScript解析器会介入对内联脚本进行解析,完成JS的解码工作。 如果浏览器遇到需要URL的上下文环境,URL解析器也会介入完成URL的解码工作。 URL解析器的解码顺序会根据URL所在位置不同,可能在JavaScript解析器之前或之后解析 1.3.1 HTML实体编码 浏览器会对一些字符进行特殊识别处理,比如将 < > 识别为标签的开始结束。 要想在HTML页面中呈现出特殊字符,就需要用到对应的字符实体。比如在HTML解析过程中,如果要求输出值为 < > ,那么输入值应该为其对应的实体 < > 字符实体以&开头 + 预先定义的实体名称,以分号结束,如“<”的实体名称为< 或以&开头 + #符号 以及字符的十进制数字,如”<”的实体编号为< 或以&开头 + #x符号 以及字符的十六进制数字,如”<”的实体编号为< 字符都是有实体编号的但有些字符没有实体名称。 普通编码与实体编码的在线转换 1.3.2 Javascript编码 Unicode 是字符集,而 utf-8,utf-16,utf-32 是编码规则 最常用的如“\uXXXX”这种写法为Unicode转义序列,表示一个字符,其中xxxx表示一个16进制数字 如”<” Unicode编码为“\u003c”,不区分大小写 普通编码与Unicode转义序列的在线转换 Unicode字符集大全 1.3.3 URL编码 %加字符的ASCII编码对于的2位16进制数字,如”/”对应的URL编码为%2f 转换可以使用 JS 自带的 encodeURIComponent 和 decodeURLComponent 方法来对特殊字符进行转义,也可以对照ASCII表为每个字符进行转换 1.3.4 编码解码分析 复制代码 abc 等价于 abc 复制代码 上述代码中 编码顺序:HTML编码 解码顺序:HTML解码 复制代码 abc 等价于 abc 等价于 abc 复制代码 上述代码中 编码顺序:URL编码 -> HTML编码 解码顺序:HTML解码 -> URL解码 复制代码 abc 等价于 abc 等价于 abc 复制代码 上述代码中 编码顺序:Javascript编码 -> HTML编码 解码顺序:HTML解码 -> Javascript解码 需要注意的是,在JS的解码中,相关的标识符才能被正确解析(如这里的 alert 标识符), 像圆括号、双引号、单引号等等这些控制字符,在进行JavaScript解析的时候仅会被解码为对应的字符串文本(比如这里并未对 (1) 进行编码,如果对括号及括号里面内容做JS编码,将无法执行alert函数 ) 复制代码 abc 等价于 abc 等价于(使用JS的方法进行的URL编码) abc 等价于(使用转换成对应ASCII编码对应2位16进制数字的URL编码) abc 等价于 abc 复制代码 上述代码中 编码顺序:Javascript编码 -> URL编码 -> HTML编码 解码顺序:HTML解码 -> URL解码 -> Javascript解码 这里还需要注意的是,在URL的编码中,不能对协议类型(这里的 javascript: )进行编码,否则URL解析器会认为它无类型,导致无法正确识别 应用这个解析顺序,看以下这个例子 输入源 abc为URL中的值,如果后端仅进行了HTML的编码,还是有问题的 复制代码 Payload-0: http://local.abc.com/main/?r=abc/index&abc=');alert('11 test test 复制代码 解码顺序先是进行HTML解码,此时会将 '解析成 ' 号,接着进行Javascript的解码,识别到 ' 即可闭合test函数,调用成功 所以,这种情况下,后端需要先进行Javascript编码再进行HTML的编码 当然,还有其他顺序的混合。也需要考虑编码工作能不能正确地进行过滤 解码顺序: HTML解码 -> URL解码 -> Javascript解码 -> URL解码 引申出去,还有一些字符集的知识点,脑壳疼,就不在这整理了 1.4 常见XSS攻击方式 XSS的攻击脚本多种多样,在使用了模板(前端模板和后端模板)之后,需要格外注意数据的输入输出 下面列举几个常见的 1.4.1 PHP使用Yii框架中的Smarty模板 有时候会使用 $smarty.get.abc 获取URL中的参数,未经转义 复制代码 Payload-1: http://local.abc.com/main/?r=abc/index&abc= <{$smarty.get.abc}> Payload-2: http://local.abc.com/main/?r=abc/index&abc="> abc ">abc Payload-3: http://local.abc.com/main/?r=abc/index&abc=" onmouseover=alert(1) abc abc Payload-4: http://local.abc.com/main/?r=abc/index&urlTo=javascript:alert(1) urlTo urlTo Payload-5: http://local.abc.com/main/?r=abc/index&urlTo=data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pgo= urlTo urlTo Payload-6: http://local.abc.com/main/?r=abc/index&abc= Payload-7: http://local.abc.com/main/?r=abc/index&abc=alert(1) Payload-8: http://local.abc.com/main/?r=abc/index&abc='){}if(alert(1)){// Payload-9: http://local.abc.com/main/?r=abc/index&abc=');alert('1 Payload-10: http://local.abc.com/main/?r=abc/index&abc=%26%2339%3B);alert(%26%2339%3B1 对参数进行了HTML的实体编码 test test Payload-11: http://local.abc.com/main/?r=abc/index&abc=" onfocus="alert(1)" autofocus="autofocus" 复制代码 在线 base64编码解码 解决方式为: 不使用 $smarty.get 相关获取参数,改用后端过滤数据后再返回参数; Yii框架中相应位置配置:'escape_html' => true 在页面标签内嵌的脚本中直接使用后端返回的数据并不安全,后端可能过滤不完善(见Payload-7和Payload-0)避免直接使用 可以改用将数据存储在属性中,再通过脚本获取属性的方式 1.4.2 JS操作DOM的时候是否会有XSS隐患? 使用 jQuery的append相关方法时(比如 html方法)可能会 复制代码 // 执行 $($0).html(''); // 执行 $($0).html('\u003cscript\u003ealert(1);\u003c/script\u003e'); // 执行 $($0).append(''); // 不执行 $0.innerHTML = ''; 复制代码 原因是在jQuery中使用了eval方法执行相应的脚本,需要注意的是,Unicode编码的字符在运算中会被解析出来 所以,要注意的是 使用jQuery设置DOM内容时,记得先对内容进行转义 对于设置输入框的值,是安全的 复制代码 复制代码 对于设置属性的值,是安全的 复制代码 复制代码 1.4.3 前端Handlebars模板中的安全问题 后端有Smarty模板,前端也可以有Handlebars模板,使用模板有利于开发维护代码。不过和后端一样,使用模板也要考虑到XSS的问题 Handlebars模板中可选择是否开启转义 复制代码 {{name}} {{{name}}} 复制代码 所以要注意的第一点是: 如果使用了转义占位符,就需要先进行还原;如果不使用转义,就不要还原,否则将造成XSS 另外,Handlebars模板可以自定义helper,helper有两种使用方式,直接返回数据或返回子层 复制代码 复制代码 进入页面后,将会执行 alert(1) ,然后鼠标滑过span或input元素,将会执行 alert(2) 这是因为Handlebars在处理helper时,如果是返回数据,将不进行转义过滤 解决方案为: 如果使用了自定义的helper直接返回数据,先转义一遍,即取消注释[1] 处 代码 或者不直接返回数据,即注释模板[A],[1] 和[2]处,取消注释模板[B],[3]处 代码 另外,前端模板会频繁和JS进行交互,在前端直接使用JS获取URL参数并放到模板中时,要格外注意防止产生DOM-base型XSS,如下面这段代码 复制代码 Payload: http://local.abc.com/main/?r=abc/index¶m=%22%20onmouseover=%22alert(2)%22 function getUrlParam(name) { let value = window.location.search.match(new RegExp('[?&]' + name + '=([^&]*)(&?)', 'i')); return value ? decodeURIComponent(value[1]) : ''; } var attrData = getUrlParam('param'); 复制代码 1.4.4 React JSX模板中的 dangerouslySetInnerHTML alert(1);'}}>
这段代码会执行么 事实上,并不会。与模板不同,它使用的是 innerHTML来更新DOM元素的内容,所以不
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信