Aiur

zellux 的博客

跨站脚本攻击和 BluePrint

Blueprint: Robust prevention of cross-site scripting attacks for existing browsers 这篇论文提出了一种防范是跨站脚本攻击(XSS)的新的方法,发在IEEE S&P 2009上,作者是UIUC的Mike Ter Louw。 所谓跨站脚本攻击,简单地说就是在网页中注入非法的脚本代码,从而达到攻击的效果。比较著名的例子有当年在MySpace上泛滥的Samy蠕虫,通过特殊的脚本注入手段,每一位访问Samy主页的用户,他们的主页都会被修改加上一段Samy is my hero文字,并且他们的主页也会被植入攻击代码,从而把这段脚本扩散给更多的用户。 通常防范跨站脚本攻击的方式有两种。一种做在服务器端,为每一段用户上传的内容做检查,并剔除恶意代码。但这种方式很难保证能过滤掉所有的恶意字符串,一方面攻击方法防不甚防,有兴趣的朋友可以参考下XSS Cheat Sheet,上面给出了很多一般人很难想到的攻击代码的组合方式。另一方面由于现在大多数论坛和博客都支持一些基本的文本修饰标签,所以简单的标签剔除或者重新编码都不可行。 另一种方法是做在浏览器端,但是由于浏览器无法区分某一段脚本到底是来源于不可信的用户还是可信的站点,所以这种方法实现起来也有很大的困难。 这里实现防范措施的一个难点在于,Web应用把生成HTML的返回给浏览器后,就不参与浏览器的HTML解析工作了。这样浏览器就不知道哪部分出现脚本是安全的,哪部分出现是不安全的。 BluePrint就着眼于这个点,提出了一种让Web应用“参与”HTML解析工作的设计。下面通过论文里面的一个例子,简单介绍下它的防范机制。 假如一位恶意的用户在一个博客上上传了这样一段含有恶意代码的留言: <p> Here is a page you might find <b """><script>doEvil(. . .)</script>">very</b> interesting: <a href=" &#14; javasc&#x0A;ript:doEvil(. . .);"> Link</a> </p><p style="nop:expres/*xss*/sion(doEvil(. . .))"> Respectfully, Eve </p> 可以看到,这段代码里包含了很多可能引发脚本执行的代码,而要在服务器端把这些所有隐藏的攻击可能找出来是一件比较困难的事。那么BluePrint是怎么在不知道这段代码是否含有恶意代码的前提下处理的呢? 首先,这种由用户上传的不可信的字符串会先在服务器端被解析成一棵树,就像HTML在浏览器中被解析一样,这棵HTML解析树可以用一些简单的DOM API来生成,例如appendChild, createElement等。这些描述如何生成HTML解析树的方法会和数据值(URL、标签属性等)一起,通过特殊的编码(Base64)传递给浏览器。例如上面这段代码,最后在浏览器接收到的HTML中,会变成这样: <code style="display:none;" id="__bp1"> =Enk/sCkhlcmUgaXMgYSBwYWdlIHlvdSBta... =SkKICAgICI+dmVyeQ===C/k/QIGhlbHBmd... =ECg===C/Enk/gCiAgUmVzcGVjdGZ1bGx5L... </code><script id="__bp1s"> __bp__.cxPCData("__bp1", "__bp1s"); </script> 在浏览器端,这段特殊的代码会被JS库解析成自定义的命令和数据格式,并由前面提到的DOM API动态生成这些HTML结点,从而达到和传统的方式一样的显示效果。当然可信的HTML代码,例如文章正文,还是按传统的方式传输的。 阅读全文 →

云计算

某门课程的Open Topic,我的话题是关于云计算的,读了一篇技术报告 Above the Clouds: A Berkeley View of Cloud Computing。 这是 UCB 的 RAD(Reliable Adaptive Distributed) 实验室花了六个月时间 brainstorm 总结出来的 paper,介绍了云计算的概念、现状及未来展望。以下内容主要来自于我上交的文档,做了一些修改,欢迎大家指正。 虽然现在对云计算这个概念的炒作大于实际研究,以至于很多人听到云计算这个名词就想到忽悠,但这里面还是很多东西需要好好考虑和设计的。云计算和以前的 cluster computing 等概念虽有相同之处,区别也有不少,它涉及了经济学、虚拟化技术、安全等诸多领域的内容。 何谓云计算? 云计算包含两方面内容,一是在网络上提供的为计算服务的应用,例如以前被称为 SaaS(Software as a Service) 的那一类应用;二是提供这些服务的在数据中心的硬件和系统软件,这部分也就是我们通常所称呼为「云」的东西。 云计算平台的优势 云计算带来了三个新颖的观点: 提供了看起来没有上限的可用计算资源,用户不需要提前考虑设备的需求量; 免去了云计算用户的前期投入,使得公司可以从一个规模较小的硬件资源起家,并根据自己的需要增加资源; 细粒度的计费手段,例如按每小时使用处理器数或者每天使用的存储空间计算,并在暂时不需要机器和存储空间时即时减免费用。 云计算资源拥有很好的弹性,以 Amazon EC2 为例,用户可以在几分钟内完成硬件资源的添加或者减少操作,这在传统的应用程序部署中是很难做到的。文中提到了 Facebook 上的一个应用 Animoto,这个应用的资源需求在三天内从 50 台服务器上升到了 3500 台服务器。在传统的部署情景中,这样的需求是很难通过预先准备好硬件来满足的。另外还有一个问题,当资源需求下降时,传统方式部署的服务器资源就被闲置了,而通过云计算部署的资源则灵活很多,例如一个网站到了深夜访问量下降,此时就可以通过减少占用的计算资源从而降低支出。 平台分类 现在的云计算平台提供了不同粒度的 API。Amazon EC2 是一个底层的极端,它提供了类似物理硬件的接口,用户可以几乎控制从内核开始的整个软件栈。通过虚拟技术提供的 CPU、块设备、IP 级别的连通技术使得开发人员几乎可以做任何事情。高度的灵活性带来的是可控性的损失,在自动伸缩性 (automatic scalability) 和容错转移 (failover) 方面,服务商就力不从心了。而 Google AppEngine 则提供了比较高层的 API,主要面向传统的 web 应用,在牺牲灵活性之后能很好的实现自动伸缩和转移,并对用户完全透明。而微软的 Azure 则介于这两者之间,提供了接近 CLR 字节码的接口,用户可以通过 . 阅读全文 →

ISCA 09 - Multi-Execution

Multi-Execution: Multicore Caching for Data-Similar Executions 这篇paper针对以multi-execution这种模式运行的程序提出了一种新的cache手段。 所谓multi-execution,指的是同时运行同一个程序的多个进程,而它们的输入数据又互不相同。这种模式在machine-learning领域比较常见,一些相对独立的learner可以以并行的方式被训练,而它们的结果可以通过一种叫做boosting的方式合并起来。给我的感觉似乎有点像mapreduce? 然后呢,作者们发现以这种方式运行的程序进程的数据有很大一部分是相同的,在合并cache数据上可以做一下文章,节省cache的使用。 于是这篇paper提出了一种叫做mergeable cache的架构,用于代替传统的L2 cache,L1 cache还是传统的cache架构。首先假设相同的数据的虚拟地址往往也是相同的(应该去掉了address space randomization的影响),以类似Page Coloring的策略进行物理页的分配,使得不同进程同一虚拟地址所对应的物理页都是相邻的。然后把虚拟地址的头9位作为cache tag,再为每个cache line记录一个bit vector用以表示某个processor的数据是否保存在这条cache line中。于是L2 cache hit当且仅当: 1. 虚拟地址的头9位等于cache line的tag 2. cache line中的bit vector的processor对应的位被置上 另外为了简化cache策略,L1和L2的数据内容是互斥的,或者说一段被cache的数据要么在L1,要么在L2,不可能同时存在于两者中。这样一来L2就只有从L1淘汰出来的数据了,而L2中的数据修改分三步完成: 1. 把数据从L2中标记为不存在(对应processor的bit vector位置0) 2. 数据进入L1 3. 修改数据 这就是这篇paper提出的cache架构的主要内容,后面的evaluation部分做的也很不错。从数据中可以看出合并的cache里面dirty cache占了比较大的比例,从而说明简单的copy-on-write策略的效果不会很好,因为copy-on-write只能合并clean cache。最后平均的speedup提升在2.5x左右,很不错。但是对于数据无关的并行程序运行,会产生一定的overhead,此时可以选择传统的L2 cache机制。 阅读全文 →

EuroSys 09 - Orchestra

吴总讲的一篇paper,题目是Orchestra: Intrusion Detection Using Parallel Execution and Monitoring of Program Variants in User-Space,发在EuroSys ‘09上,UCI的。 这篇paper提出了一种检测栈上buffer overflow攻击的方法。想法很有意思,它运行两个孪生进程,这两个进程的唯一的区别就是一个进程的栈往上长而另一个进程的栈往下长,这样在大多数情况下如果没有出现buffer overflow的问题的话那么两者的行为应该是一致的。 栈的增长行为是由编译器控制的,作者修改了gcc的代码使之生成的代码的栈增长方向相反,关于这个编译器他们之间发过一篇paper在一个叫CATARS的workshop上,题目是Reverse stack execution in a multi-variant execution environment。 “行为一致”的精确定义是两者的system call的调用方式、参数都一样,也就是说这里system call成了两个进程运行的synchronization point。如果某个点上两个进程调用的syscall不同或者调用参数不同就认为它已经被buffer overflow攻击了。 整个monitor都是跑在user态的,主要利用了ptrace,使两者的行为尽可能的一致。这里要做的事情很多,比如要保证进程调用getpid()的得到返回值一样才能使得后面的其他系统调用的参数相同,又比如一个进程调用write写入文件时不能影响到另一个进程,此外还要保证两个进程获得的file descriptor、随机数、时间、信号等信息都相同,甚至在进程创建子进行的时候也要保证所有子线程关系的同构。 用ptrace能够解决上面的大多数问题,但还有一些open problem以及false positive。如这篇paper无法解决进程用MAP_SHARED方式打开一个文件并修改的情况,尽管作者说这种mmap的用例很少见;此外由于两个进程的同步并不是原子性的,中间可能被第三方的程序干扰(比如进程A读入某个文件开头后,该文件被其他进程修改,进程B再读取就和进程A读到的不一样了),这就造成了false positive;另外由于无法截取rdtsc指令的使用,也就无法保证它们的返回值一样,也可能引起另一种false positive。 感觉这个东东想法不错,但是没什么实用性,工程量也很大。 阅读全文 →

PPoPP 08 - FastForward

FastForward for Efficient Pipeline Parallelism http://systems.cs.colorado.edu/~moseleyt/publications/giacomoni-2008-ppopp-ff.pdf 这篇paper介绍了一种针对多核访问优化的队列, 主要的特点: 1. Lock-free 2. Single-producer/single-consumer 3. Cache-optimized 经典的Lamport的lock-free的队列实现可以用下面的伪代码来表述(同样只适用于单一生产者/单一消费者的情形): enqueue_nonblock(data) { if (NEXT(head) == tail) { return EWOULDBLOCK; } buffer[head] = data; head = NEXT(head); return 0; } dequeue_nonblock(data) { (head == tail) { return EWOULDBLOCK; } data = buffer[tail]; tail = NEXT(tail); return 0; } 这种实现尽管做到了lock-free,但是存在几个问题,首先是它只适用于sequential consistency内存模型,在relaxed consistency的内存模型里可能会出现类似于Double-Checked Lock(http://techblog.zellux.czm.cn/?p=30)的问题,当然这个问题可以通过插fence指令来解决;第二个问题是这篇paper着重解决的,就是enqueue和dequeue这两个操作都用到了tail和head这两个全局变量,导致多核在读取/修改这两个变量时的为了保证cache coherency会频繁的进行cache的更新,从而导致cache line threading,降低了效率。 接下来看FastForward的实现: enqueue_nonblock(data) { if (NULL != buffer[head]) { return EWOULDBLOCK; } buffer[head] = data; head = NEXT(head); return 0; } dequeue_nonblock(data) { data = buffer[tail]; if (NULL == data) { return EWOULDBLOCK; } buffer[tail] = NULL; tail = NEXT(tail); return 0; } 这个版本的队列实现粗看和Lamport的那个区别很小,而实际上这里解决了一个重要的问题:解除了head和tail的共享问题。dequeue操作只需要关心tail,enqueue操作只关心head,这样两个变量就变成CPU本地的资源了,不需要做任何同步。当然这个实现同样局限于sequential consistency,不过加fence保证顺序的overhead不大。最后测试中这个版本的单次操作比Lamport的快3. 阅读全文 →

CGO 09 一篇关于 DCL 检测的论文

Double-Checked Lock是一个常见的由于程序员把内存模型默认为sequential momery consistency导致的问题,具体见我去年写的一篇博文http://techblog.iamzellux.com/2008/07/singleton-pattern-and-double-checked-lock/ 虽然Java 5解决了这个问题,但是C++等语言中这个问题依然存在,依然有很多因为程序员假设sequential consistency而编译器做了错误的指令调度后导致的bug,见http://www.newsmth.net/bbscon.php?bid=335&id=250203 CGO 09的这篇paper Detecting and Eliminating Potential Violations of Sequential Consistency for Concurrent C/C++ Programs针对这个问题进行了深入研究,通过加fence指令的方法解决了因编译器的指令调度造成的违背程序员原义的问题,可以在http://ppi.fudan.edu.cn/yuelu_duan下载到。没有认真读过,俺在这里就不误人子弟了 O.O 阅读全文 →