计算网页中某个元素的位置

由于项目的需要,测试中需要对网页元素进行截图,以确保它看上去没有问题。之前我写过一篇文章介绍过一种方法,先使用 WebDriver 进行全屏截图,然后根据目标元素(DOM Element)所在的位置,再对截下来的图片进行剪裁,保留我们需要的位置即可。

那段代码一直都工作得很好,直到我知道了一个东西:iframe。iframe(普通的 frame 也是一样的,不过 frame 现在不太常见,这里只用 iframe 举例)中的内容被视为一个独立的网页,连 Window 对象也是和它的父级网页分开的。而 WebDriver 中的 WebElement.getLocation()方法只能返回这个 WebElement 和它所在的 Window 的位置关系,它的实现没什么问题,但全屏截图不仅包含了 iframe 的内容,可能也包含了它的父级页面的内容,剪裁的时候需要知道目标元素在截图中的位置。那么问题来了,挖掘机技术哪家强?如何计算一个元素相对于截图的位置?

这个问题还要分类讨论,原因是:Chrome 和 Firefox 中截图的行为是不一样的。Chrome 的截图是当前可见(viewport)的网页内容,比方说,当网页的实际大小超过 Chrome 窗口大小时,根据滚动条的位置不同,窗口中显示的内容不同,Chrome 的截图就是显示出来的内容。于是我们要计算目标元素相对于当前可见内容的位置。而 Firefox 用了一个方法,可以截到整个网页的内容,无视当前窗口大小。于是对于 Firefox 我们要计算元素的绝对位置(Absolute Position)。

获得一个元素的位置,需要用到一个方法:Element.getBoundingClientRect()。这个方法返回这个元素相对于它所处的 Windows 在当前可见内容的位置,用 top、left、right、bottom 四个值来表示。我们只关心其中的 top 和 left,至于剪裁的尺寸,我们可以通过元素本身的长和宽来得到,不需要计算。要计算目标元素对于顶级 Window的位置,我们只需要依次加上它的父级 Window的 top 和 left 即可。代码如下:

以上代码适用于 Chrome ,而在 Firefox 中,我们还需要计算元素的绝对位置。这里需要用到 Window.pageXOffset。pageXOffset,或者 scrollX,表示当前 Window 的横向滚动条滚动的位置,把这个值和上述的 left 相加,即可得到目标元素的横向绝对位置。当然,iframe 也可以特殊处理的:

由于 IE8 不支持 pageXOffset 和 scrollX,于是在 IE8 中需要一些特殊处理,即代码中标注“IE8”的部分。把这两段 Javascript 代码,替换之前文中的 WebElement.getLocation(),即可实现在 iframe 中对特定元素截图。

ShellShock,炫酷特性引发的严重漏洞

ShellShock 是昨天刚刚被公开的一个 Linux 的漏洞,如果你手头有 Linux 机器(比如工作站、博客主机、笔记本等),并且正在使用 Bash,请尽快升级。如果你手头没有 Linux 机器,也不想了解 ShellShock 的深入细节,那就不用继续往下阅读了。

这个漏洞来自Bash,Bash 是 Linux 中常用的一个脚本运行环境。在 Bash 中有这样一个鲜为人知的“特性”,它可以定义一个函数,然后开启一个新的 Bash 环境来运行这个函数。比如下面这一行代码,它就定义了函数 foo,然后打开一个新的 Bash 来运行 foo,继而输出“hello”。

这是一个很有趣,可能也很有用的特性。当然,“有用”的前提是,你知道你在运行什么样的代码。如果你不知道,那就成了一个“远程代码执行”(Remote Code Execution,简称RCE)的漏洞。RCE 通常都是非常非常严重的漏洞,不及时修补,就毫无安全性可言。这不,网页服务器就在这次事件是充当了“不知道”的那个角色。

网页服务器,如 Apache,会接收来自客户端的 HTTP 请求,这些请求的内容是不受控制的。也就是说,用户只要写一段代码,就可以发送任何的内容给服务器(Apache),而 Apache,以及其连带的各种服务器端语言,如 PHP、Java等,有责任安全地处理这些内容。

根据上面的两点,只要黑客写了一段自动运行的 Bash 脚本,把它放在 HTTP 请求中发给服务器,服务器又恰好(以任何一种方式)使用了 Bash 来处理这个 HTTP 请求,只要 Bash 看到了那段有害的代码,就会造成 RCE。上述的代码只是打印一行文字,如果黑客把它写成“开放远程登录权限”或者“发送管理员帐号给我”,那后果就不堪设想了。

有评论说 ShellShock 比起前段时间的心脏出血漏洞有过之而无不及,原因是显而易见的。

不过还好,官方补丁已出,只要升级过 Bash,或者根本不用 Bash(部分 Linux 发行版使用了其它替代软件),就可以暂时不受黑客攻击。但是官方补丁还没有把这个漏洞补完,它只是尝试避免 RCE 攻击,但并没有阻止用户定义新的函数,比如下面这段代码:

如果用户提交的 HTTP 请求中,包含这样一个 Cookie,那么一个名为 HTTP_Cookie 的函数会被定义出来。虽然它不会自动运行,也看上去不像会被其它代码调用的样子,但依然还是蛮让人胆战心惊的。网站管理员估计又要睡不好觉了。

由于 ShellShock 还没有被完整修复,打了补丁的朋友们也要保持一颗警惕的心,随时留意事件的进展,及时更新后续的补丁。

与时俱进的垃圾评论

和垃圾邮件一样,博客中的垃圾评论也是一种 SEO 的方式。它的主要特点是包含一些网页链接或者关键词,以达到做广告的效果。Wordpress 有一个很好用的官方插件叫做 Akismet,它把所有的评论都发送到 WordPress 的官方服务器,来鉴别每条评论是不是垃圾评论。这样做的好处是一旦某一种模式的评论,如果包含某个特定网址,被认为是垃圾评论,那么它将在所有的 WordPress 站点中被阻止,总体上提升了垃圾评论的识别率。

我一直都在使用 Akismet 来阻止垃圾评论,不过在上周发生了一点小小的意外。

意外的根源来自我的一个邮件通知评论作者的插件,那是我一个月前刚刚启用的新功能。它的作用是在有人回复了某条评论时,自动给他所回复的人发送一封邮件,以便提升“回头率”。之前一直都工作得很好,我也没有仔细维护它,直到上周,一些读者开始抱怨收到了垃圾评论的通知邮件。

一开始我认为是 Akismet 的问题,因为确实有一些垃圾评论没有被过滤掉,然后我就手动把那些评论标记成垃圾评论。但在这之后,又收到了很多类似的通知邮件。这让我很纳闷,因为垃圾评论已经被 Akismet 给过滤掉了,不应该再触发通知功能。

后来仔细研究之后才发现,原来从一开始,垃圾评论就会触发通知功能,但始终没有人收到这些通知。原因是,那些垃圾评论没有回复给其它评论者,他们都是直接回复博文的评论。由于没有回复人,邮件就不会发出去。但是不知为何,垃圾评论的功能升级了,它开始回复已有的评论。由于我的插件中没有做好检测,尽管这些垃圾评论被 Akismet 过滤掉了,但依然会有通知邮件。

现在邮件通知功能已经改进了,不会再对垃圾评论发送邮件了。如果还有问题,请及时留言。