Web前端实训——电脑上的所有数据都可以通过JS读取如果你比较在意,那么我们今天的主角Spectre很容易构造,危害很大。使用Spectre,你可以:通过几行JavaScript读取电脑/手机上的所有数据,浏览浏览器中的网页,可以读取你所有的密码,并知道其他程序在做什么。这甚至不需要你写的程序有漏洞,因为这是计算机硬件层面的漏洞。要理解Spectre,我们需要以下三个方面的知识:理解什么是旁道攻击,理解内存是如何工作的,理解计算机预测执行,其实是一些很基础的计算机知识,你可能在学校里学过。那么Spectre就巧妙的利用了以上三个原理,下面我们一一了解一下。你完全不用担心,我会用最简单的方式给你解释。前端培训先把这些知识拆开,最后拼起来,其实很好理解。内存的工作原理首先,我们的电脑是由很多部分组成的:存储:内存、硬盘等CPU输入输出设备:键盘、鼠标等我们的电脑运行时,程序是从存储设备中加载的进入CPU,CPU负责处理需要多次从内存中读取数据的繁重计算。然后将结果输出到我们的显示器等输出设备,这大概就是一个简单的计算机工作原理。接下来,让我们关注CPU和内存。内存中存放着很多你正在运行的程序,包括系统、用户数据等,同时也存放着CPU运行的中间结果。要存储如此多的信息,就需要一种标准化的存储方式。我们可以把内存想象成一堆排列的小内存块,每个内存块存储一位信息。另外,内存有很多层。CPU读取一个数据在里面是很慢的,所以我们在CPU和内存中建了好几级缓存。当我们拿到一个缓存的数据时,速度会更快。.那么当访问一个没有被缓存的数据时,该数据会在缓存内存中创建一个副本,下次访问时会非常快。这就是内存的一般工作原理。当然,这个过程简化了很多。我们这里只需要了解一下。侧信道攻击那么什么是侧信道呢?我们可以简单这样理解:如果你的程序在正常的通信通道之外还有另外一个特征,这些特征反映了你不想产生的信息,如果这个信息被别人获取了,你就会泄密。这种边缘特征产生的信息通道称为旁路。比如你的记忆在进行计算的时候,会产生一个电波,反映出记忆中的内容,有人用特定的方法收集这个电波,就形成了旁路。基于侧信道的攻击称为侧信道攻击。常见的绕过包括:延迟、异常、能耗、电磁、噪声、可见光、错误信息、频率等。反正你的操作总是有边缘特征的,一不小心,这个边缘特征就会成为泄漏的机会。下面举一个基于延迟的侧信道攻击的例子:假设我们想让计算机验证密码,比如我们的密码是ConardLi。接下来我们从攻击者的角度来猜一下,密码是多少,我们从一个字母来猜:密码是A,1ms后电脑告诉我:不是!密码是B,1ms后电脑告诉我:不行!密码是C,1.1ms后电脑告诉我:不行!你有没有发现任何问题?我们猜对了第一个字母,但电脑却用了0.1ms的时间告诉我们密码错误?因为这次计算机发现第一个数字匹配后,需要验证第二个数字是否匹配,所以会花费更多的时间。是不是很巧妙!同理,我们可以继续验证Ca,Cb,……Co,最终猜出我们的密码。这时候我们的猜测时间和密码的长度是线性关系,我们可以在O(n)的时间复杂度内猜出密码。如果直接爆破的话,至少需要计算52的8次方!那是旁路攻击,该死的魅惑!CPU的预测执行上面我们提到,CPU在运行的时候,会频繁的从内存中调用信息。但是读内存很慢,CPU为此闲置了很长时间,只是在等待内存中的数据。这显然不是一个很好的解决方案。那么,人们想知道,CPU是不是可以推测出需要执行的命令呢?假设我们有如下代码,根据内存中的某个数据判断并执行不同的语句:if(Menory===0){//执行第一步计算//执行第二步计算//执行第三步计算}这里有两种可能,Menory为0或者不为0。这时候CPU会预测什么时候等待内存数据。假设读内存返回0,CPU不用等内存返回就可以跑路:跳过if判断,直接执行里面的计算命令。那么如果内存真的返回了0,说明CPU已经成功提前运行,CPU可以继续执行后面的命令。但是如果内存不返回0,CPU就会回滚上一次执行的结果。所以CPU执行需要非常小心,不要直接覆盖寄存器的值,这样才能真正改变程序的状态,一旦发现预测失败,立即回滚改变。攻击原理。我们已经掌握了该漏洞利用的所有因素。现在让我们来看看发生了什么。比方说下面是我们的缓存,读取它很慢。系统内核将其屏蔽,分配给不同的程序,如果考虑云计算,可能会分配给不同的虚拟机。不同程序可能分配的内存块是相邻的,红色的内存块存放的是我们受害者的数据,比如受害者的密码:操作系统会尽量保证一个程序不能访问属于其他程序的内存块,Memoryblocks对于不同的程序是隔离的。所以其他程序无法直接读取“受害者”(红色区域)的数据:如果我们试图直接访问红色区域,肯定是读取不到的,但缓存中可能已经有一些数据了。接下来,我们可以尝试使用缓存来为它做点什么。我们在紫色的内存块中放了一个数组A。这块内存属于我们的程序,可以合法访问,但是很小,只有两位。但是我们并不满足于读取数组A中的两个元素,我们尝试跳出A的范围(下标越界),访问A数组的第X个位置。但是X可能远远超出A数组的长度。通常情况下,CPU会阻塞这个操作,抛出一个错误:“非法操作”,然后强制结束这个操作,但是我们可以试着再观察一下这个过程,看看它是怎么做到的。我们在允许访问的内存范围内新建一个区域,可以称之为工具箱。我们特别要求CPU不要将这段数据复制到缓存中,而只保留在内存中,内存是一块连续的内存区域。假设我们执行的指令长这样,首先有一个if判断语句:if(name==='code'){//...}一般来说CPU执行会先忽略这个判断,因为需要等待内存返回name的值是否等于code,因为有预测执行等技术,if语句里面的东西会提前执行。if(name==='code'){accessTools[A[x]]}我们尝试读取Tools的第(A的第X个元素)元素。假设我们读到的victimmemory中有3:这是我们不应该读的,但是我们可以通过推测执行来做如下:CPU执行完不应该执行的命令后,CPU认为需要看A的值[X]。此时CPU不检查A[X]的下标是否越界,因为CPU认为内核会一直验证下标是否越界,如果越界,程序将被强制终止。所以预测执行直接查询A[X]的值,然后发现A[X]=3,即:Tools[A[x]]=Tools[3],这是Tools中存储的第四个值在我们的实际记忆中。有一个元素a,重点来了:CPU访问到a后,将a(也就是Tools[3])放入缓存!最后一步是遍历Tool中的每个元素。我们发现访问前几个元素有点慢,直到访问第三个元素突然变得非常快!因为第三个元素a在缓存中存储了一份!当推测执行发现错误时,它会回滚寄存器更改,但不会回滚缓存!信息因此泄露,因为访问第三个元素比其他元素花费的时间更少!这也称为基于时间的旁路。所以,我们知道“受害者”在内存中的这个位置有一个3。后面我们可以把Tools区域做大,www.atguigu.com你可以猜到其他更多的数据!当然,这是在实际攻击中需要考虑的。对网络的影响已经分析清楚。事实上,使用JavaScript实现这种攻击非常容易。几乎所有JavaScript中的边界检查都可以被绕过。通过,从而实现任意内存边界读取。我们可以看下面这段代码:if(index
