文件对话框

文件上传对话框是一直以来就存在的网页控件。

到了 HTML5 时代,增加了更多的功能,例如支持文件多选。Chrome 甚至还支持「上传文件夹」这一私有特征:

<input type="file" webkitdirectory />

在给用户方便的同时,其安全隐患也逐渐出现。用户平时在下载时,理所当然的弹出的是保存对话框,因此常常不仔细看就做出了选择。

这极有可能被攻击者所利用。一些恶意网站在用户点击下载时,故意弹出一个上传对话框。只要用户一疏忽,就把选中的文件夹给上传了!

下载对话框

上传对话框

当然,仅仅依靠默认的上传,这种攻击方式仍有较大难度。因为整个文件夹可能非常大,上传需要很久的时间。

如果用户等了半天也没看见下载进度,或许就会刷新重试,甚至放弃了。

选择即授权

然而,HTML5 带来了一个新的规范 —— File API,允许脚本访问文件。

但由于沙箱限制,脚本无法访问任何一个本地文件,除非用户主动授权。如何授权?最常见的,就是「上传对话框」了。

事实上,如今的上传对话框,早已不是从前「选择哪个文件」的功能,而是「允许脚本访问哪个文件」的权限申请!只不过界面上没有提示罢了。

例如,一个传统的文件上传控件。当用户选中文件后,即可通过 File API 读取文件内容:

<input id="dialog" type="file" />
<script>
dialog.onchange = function(e) {
var reader = new FileReader();
reader.onload = function() {
console.log(this.result);
};
reader.readAsText(this.files[0]);
};
</script>

或许你已注意到,File 位于files[]而不是file,这正是给文件夹预留的!

在 Chrome 里,上传控件只要加上 webkitdirectory 属性,就变成文件夹选择框。这时一旦用户选中某个文件夹,瞬间就赐予脚本访问整个文件夹的权限!

<input id="dialog" type="file" webkitdirectory />
<script>
dialog.onchange = function(e) {
var files = this.files;
var table = {}; for (var i = 0; i < files.length; i++) {
var f = files[i];
var dt = new Date(f.lastModified); table[i] = {
path: f.webkitRelativePath,
size: f.size,
modified: dt.toLocaleString()
};
} console.table(table);
};
</script>

演示

于是,用户本想将文件保存在桌面上,结果却将桌面上的所有资料,被攻击者的脚本拿到!

优化上传

一旦脚本可主动访问,我们可以用更灵活的方式处理这些文件,无需再用传统落后的方式上传。我们可以直接在前端分析出「有价值」的文件,例如:

  • 备注文件、脚本、批处理、电子表格等,很可能存有一些敏感信息,而且体积小价值大,优先将其上传;

  • 图片则可通过 canvas 缩放,先传较小的缩略图。当接收端发现有意义时,再传输原文件。

  • 对于一些体积较大但意义不大的文件,则可以直接忽略。

由于 HTTP 上传是没有压缩的,因此在传输文本文件时效率很低。我们可以借助 Flash 内置的LZMA压缩算法,极大提升传输效率。如果不支持 Flash,也可以使用asm.js版的 LZMA 压缩器,配合Worker线程在后台压缩和传输。

同时,将多个小文件合并后再压缩,可进一步提高压缩率。再多开几个连接,上传速度即可大幅提升。

续点上传

不过即使再优化,仍有传不完的可能。因此,我们得将没传完的内容储存起来,当用户再次回来时,继续传输。

得益于 HTML5 的 Storage API,这不难实现。

事实上,当用户授权了某个文件夹时,我们首先要做的不是发送,而是读出文件夹内容,立即备份到 Storage 里。毕竟,文件的读取需要用户主动配合,是非常珍贵的;而访问 Storage 则无需任何条件。

当备份完成后,再从 Storage 里读取、发送、删除。这样,即使中途页面刷新或关闭了,下次回来时,仍能从 Storage 中继续。

考虑到每个域的 Storage 容量有限,我们可以使用iframe嵌入多个不同域的页面,然后通过postMessage进行数据的分发和汇总,这样就不受容量限制了。

当然,能不能无限容量还得看浏览器策略,不然硬盘会被撑满

将数据存放在 Storage 里还有另一个好处,即使用户永不回来,但数据仍持久保存着。只要以后一旦进入其他的站点,只要是我们可控的,仍有机会继续上传。(例如将用户引到我们布置了 XSS 的站点上)

延长上传

在之前《延长 XSS 生命期》 中介绍过,可以使用各种黑魔法来提升脚本有效期。

利用这个原理,即使当前页面关闭,其他关联的页面也能继续上传。事实上,除了文中提到的方法,如今还有一个新的 API —— SharedWorker,它可以让 Worker 共享于多个页面,只要有一个存在,线程就不会停止。可以让续点时丢失的数据更少。

视觉欺骗

由于上传控件有着独特的界面,如何才能让用户主动去点呢?万能的方法是点击劫持(Clickjacking)。

不过本场景无需这么麻烦,只需简单的调用控件的click方法就可以了。

<a href="ed2k://|file|xxxxxxxxxx.avi" id="download">高速下载</a>
<script>
var uploader = document.createElement('input');
uploader.type = 'file';
uploader.webkitdirectory = true; download.onclick = function(e) {
uploader.click(); // 弹出授权对话框
e.preventDefault(); // 屏蔽下载对话框
};
</script>

演示

我们将屏蔽超链接的默认行为,将其传递给上传控件,即可召唤出「文件夹授权」对话框了!

同时,为了不让眼亮的人发现对话框上的破绽,我们使用一些第三方的下载方式,例如电驴、迅雷等等,让人们误以为就是这样的。

当然,这只是一个小例子。只要页面做的真实,下载内容引人入胜,用户自然就会中招。

后记

本以为 webkitdirectory 的这个私有属性很快就会放弃,至少是更强的安全提示。不过至少现在也没更新,因此上网时还是要多加留心,看清楚了再做决定。

当然,这篇只是最早的「交互欺骗」探索。事实上,深入挖掘会发现可利用点远不仅此。

如今的浏览器在视觉、音频上的体验已经非常完善,攻击者甚至可以在网页里,高度模拟一个本地应用的交互效果。让用户误以为是浏览器之外的程序弹出的界面,从而进行钓鱼。

参考:http://www.cnblogs.com/index-html/p/dialog-phishing.html

H5危险的文件上传对话框的更多相关文章

  1. H5+JAVA的文件上传,断点续传

    这里只写后端的代码,基本的思想就是,前端将文件分片,然后每次访问上传接口的时候,向后端传入参数:当前为第几块文件,和分片总数 下面直接贴代码吧,一些难懂的我大部分都加上注释了: 上传文件实体类: 看得 ...

  2. nodemailer + express + h5 拖拽文件上传 实现发送邮件

    一.部署 1.部署Express 2.准备一个邮箱并开始SMTP服务 二.服务器端 三.客户端 四.效果:

  3. selenium之 文件上传所有方法整理总结【转】

    本文转自:https://blog.csdn.net/huilan_same/article/details/52439546 文件上传是所有UI自动化测试都要面对的一个头疼问题,今天博主在这里给大家 ...

  4. selenium之 文件上传方法

    文件上传是所有UI自动化测试都要面对的一个头疼问题 首先,我们要区分出上传按钮的种类,大体上可以分为两种,一种是input框,另外一种就比较复杂,通过js.flash等实现,标签非input 我们分别 ...

  5. 富文本编辑器 KindEditor 的基本使用 文件上传 图片上传

    富文本编辑器 KindEditor 富文本编辑器,Rich Text Editor , 简称 RTE , 它提供类似于 Microsoft Word 的编辑功能. 常用的富文本编辑器: KindEdi ...

  6. selenium之 文件上传所有方法整理总结

    本文转载“灰蓝”的原创博客.http://blog.csdn.net/huilan_same/article/details/52439546 文件上传是所有UI自动化测试都要面对的一个头疼问题,今天 ...

  7. web自动化之selenium(三)文件上传

    1.上传标签为input #若上传文件的标签为<input>可以直接定位标签,然后send_keys(文件路径)可以直接上传 2.利用第三方软件Autoit上传 1.下载Autoit:ht ...

  8. Atitit .h5文件上传 v3

    Atitit .h5文件上传 v3 1. 上传原理1 2. V3版新特性1 3. Html1 4. Js2 5. uploadV2.js2 6. upServlet & FileUploadS ...

  9. Atitit .h5文件上传

    Atitit .h5文件上传 1. 上传原理1 2. Html1 3. Js2 4. uploadV2.js2 5. upServlet & FileUploadService {3 6. 注 ...

随机推荐

  1. java获取本月或某月的第一天和最后一天

    获取某月的第一天和最后一天的日期 Calendar calendar = Calendar.getInstance(); calendar.setTime(date); calendar.set(Ca ...

  2. BestCoder22 1003.NPY and shot 解题报告

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5144 题目意思:有个人抛物体,已知抛的速度和高度,问可以抛到的最远距离是多少.即水平距离. 做的时候是 ...

  3. JS中数组Array的用法示例介绍 (转)

    new Array() new Array(len) new Array([item0,[item1,[item2,...]]] 使用数组对象的方法: var objArray=new Array() ...

  4. [Python] dir() 与 __dict__,__slots__ 的区别

    首先需要知道的是,dir() 是 Python 提供的一个 API 函数,dir() 函数会自动寻找一个对象的所有属性,包括搜索 __dict__ 中列出的属性. 不是所有的对象都有 __dict__ ...

  5. TFS强制解除签入签出锁定

    首先你要知道你服务器的用户名和登录密码 看被别人签出了的文件

  6. October 13th 2016 Week 42nd Thursday

    If the world seems cold to you, kindle fires to warm it. 若世界以寒相待,请点燃火堆以温暖相报. Kindle fires to warm th ...

  7. c语言if语句

    #include<stdio.h>#include<windows.h>#include <limits.h>#include <math.h>int ...

  8. Retrofit学习入门

    Retrofit的使用 设置权限与添加依赖 定义请求接口 通过创建一个retrofit生成一个接口的实现类(动态代理) 调用接口请求数据 设置权限与添加依赖 权限:首先确保在AndroidManife ...

  9. hdu 2546饭卡

    用5块钱去买最贵的物品,用剩下的m-5块去买尽量多的物品 #include<stdio.h> #include<math.h> #include<vector> # ...

  10. 【数据库】 Sqlserver 2008 error 40出现连接错误的解决方法

    经常要连接到远程数据库上,因此常常碰到这个错误,然后又屡次忘记解决方法,所以今天坐下笔迹,好下次能快速回忆起来. 一.首先检查数据库的TCP/TP是否启动 1.启动Sql server配置管理器 2. ...