HTML5技术

【前端安全】JavaScript防http劫持与XSS - ChokCoco

字号+ 作者:H5之家 来源:博客园 2016-08-19 17:00 我要评论( )

作为前端,一直以来都知道HTTP劫持与XSS跨站脚本(Cross-site scripting)、CSRF跨站请求伪造(Cross-site request forgery)。但是一直都没有深入研究过,前些日子同事的分享会偶然提及,我也对这一块很感兴趣,便深入研究了一番。 最近用 JavaScript 写了

作为前端,一直以来都知道HTTP劫持与XSS跨站脚本(Cross-site scripting)、CSRF跨站请求伪造(Cross-site request forgery)。但是一直都没有深入研究过,前些日子同事的分享会偶然提及,我也对这一块很感兴趣,便深入研究了一番。

最近用 JavaScript 写了一个组件,可以在前端层面防御部分 HTTP 劫持与 XSS。

当然,防御这些劫持最好的方法还是从后端入手,前端能做的实在太少。而且由于源码的暴露,攻击者很容易绕过我们的防御手段。但是这不代表我们去了解这块的相关知识是没意义的,本文的许多方法,用在其他方面也是大有作用。

已上传到 Github – httphijack.js ,欢迎感兴趣看看顺手点个 star ,本文示例代码,防范方法在组件源码中皆可找到。

接下来进入正文。

  HTTP劫持、DNS劫持与XSS

先简单讲讲什么是 HTTP 劫持与 DNS 劫持。

HTTP劫持

什么是HTTP劫持呢,大多数情况是运营商HTTP劫持,当我们使用HTTP请求请求一个网站页面的时候,网络运营商会在正常的数据流中插入精心设计的网络数据报文,让客户端(通常是浏览器)展示“错误”的数据,通常是一些弹窗,宣传性广告或者直接显示某网站的内容,大家应该都有遇到过。

DNS劫持

DNS劫持就是通过劫持了DNS服务器,通过某些手段取得某域名的解析记录控制权,进而修改此域名的解析结果,导致对该域名的访问由原IP地址转入到修改后的指定IP,其结果就是对特定的网址不能访问或访问的是假网址,从而实现窃取资料或者破坏原有正常服务的目的。

DNS 劫持就更过分了,简单说就是我们请求的是  ,直接被重定向了 ,本文不会过多讨论这种情况。

XSS跨站脚本

XSS指的是攻击者漏洞,向 Web 页面中注入恶意代码,当用户浏览该页之时,注入的代码会被执行,从而达到攻击的特殊目的。

关于这些攻击如何生成,攻击者如何注入恶意代码到页面中本文不做讨论,只要知道如 HTTP 劫持 和 XSS 最终都是恶意代码在客户端,通常也就是用户浏览器端执行,本文将讨论的就是假设注入已经存在,如何利用 Javascript 进行行之有效的前端防护。

  页面被嵌入 iframe 中,重定向 iframe

先来说说我们的页面被嵌入了 iframe 的情况。也就是,网络运营商为了尽可能地减少植入广告对原有网站页面的影响,通常会通过把原有网站页面放置到一个和原页面相同大小的 iframe 里面去,那么就可以通过这个 iframe 来隔离广告代码对原有页面的影响。

这种情况还比较好处理,我们只需要知道我们的页面是否被嵌套在 iframe 中,如果是,则重定向外层页面到我们的正常页面即可。

那么有没有方法知道我们的页面当前存在于 iframe 中呢?有的,就是 window.self 与 window.top 。

window.self

返回一个指向当前 window 对象的引用。

window.top

返回窗口体系中的最顶层窗口的引用。

对于非同源的域名,iframe 子页面无法通过 parent.location 或者 top.location 拿到具体的页面地址,但是可以写入 top.location ,也就是可以控制父页面的跳转。

两个属性分别可以又简写为 self 与 top,所以当发现我们的页面被嵌套在 iframe 时,可以重定向父级页面:

if (self != top) { // 我们的正常页面 var url = location.href; // 父级页面重定向 top.location = url; }

  

使用白名单放行正常 iframe 嵌套

当然很多时候,也许运营需要,我们的页面会被以各种方式推广,也有可能是正常业务需要被嵌套在 iframe 中,这个时候我们需要一个白名单或者黑名单,当我们的页面被嵌套在 iframe 中且父级页面域名存在白名单中,则不做重定向操作。

上面也说了,使用 top.location.href 是没办法拿到父级页面的 URL 的,这时候,需要使用document.referrer。

通过 document.referrer 可以拿到跨域 iframe 父页面的URL。

// 建立白名单 var whiteList = [ 'www.aaa.com', 'res.bbb.com' ]; if (self != top) { var // 使用 document.referrer 可以拿到跨域 iframe 父页面的 URL parentUrl = document.referrer, length = whiteList.length, i = 0; for(; i<length; i++){ // 建立白名单正则 var reg = new RegExp(whiteList[i],'i'); // 存在白名单中,放行 if(reg.test(parentUrl)){ return; } } // 我们的正常页面 var url = location.href; // 父级页面重定向 top.location = url; }

 

更改 URL 参数绕过运营商标记

这样就完了吗?没有,我们虽然重定向了父页面,但是在重定向的过程中,既然第一次可以嵌套,那么这一次重定向的过程中页面也许又被 iframe 嵌套了,真尼玛蛋疼。

当然运营商这种劫持通常也是有迹可循,最常规的手段是在页面 URL 中设置一个参数,例如 ?iframe_hijack_redirected=1 ,其中 iframe_hijack_redirected=1 表示页面已经被劫持过了,就不再嵌套 iframe 了。所以根据这个特性,我们可以改写我们的 URL ,使之看上去已经被劫持了:

var flag = 'iframe_hijack_redirected'; // 当前页面存在于一个 iframe 中 // 此处需要建立一个白名单匹配规则,白名单默认放行 if (self != top) { var // 使用 document.referrer 可以拿到跨域 iframe 父页面的 URL parentUrl = document.referrer, length = whiteList.length, i = 0; for(; i<length; i++){ // 建立白名单正则 var reg = new RegExp(whiteList[i],'i'); // 存在白名单中,放行 if(reg.test(parentUrl)){ return; } } var url = location.href; var parts = url.split('#'); if (location.search) { parts[0] += '&' + flag + '=1'; } else { parts[0] += '?' + flag + '=1'; } try { console.log('页面被嵌入iframe中:', url); top.location.href = parts.join('#'); } catch (e) {} }

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • web前端之HTML中元素的区分 - 紫竹六月

    web前端之HTML中元素的区分 - 紫竹六月

    2016-08-18 16:00

  • web前端之HTML的大框架(body元素与frameset元素) - 紫竹六月

    web前端之HTML的大框架(body元素与frameset元素) - 紫竹六月

    2016-08-14 17:00

  • CSS3 时钟 - 前端爱好者

    CSS3 时钟 - 前端爱好者

    2016-08-14 10:01

  • 移动端UC /QQ 浏览器的部分私有Meta 属性 - 前端小超人

    移动端UC /QQ 浏览器的部分私有Meta 属性 - 前端小超人

    2016-07-29 15:00

网友点评
e