如何不在你的网站上添加验证码

68 阅读7分钟

有一次,我不得不通过互联网进行一些官僚程序,由于网页很糟糕,我不得不求助于自动化,所以我不得不找到一种方法来绕过验证码,在这样做的时候,我发现了一些事情,我将在这篇文章中与你分享。

下面的建议可能看起来很明显,但如果我没有在 "企业 "应用中遇到这些错误,我就不会写这篇文章。所以我想这些建议最终可能对某人有帮助。

尽管如此,请继续阅读,因为你可能会发现这篇文章很有趣,因为它讨论了计算机视觉、逆向工程、在Java中处理大文件以及其他主题。

不要使用类似reCAPTCHA v1的验证码

从下面的图片可以看出,我打算绕过的验证码是非常普通和简单的。

要绕过的验证码样本

因此,我首先想到的是使用计算机视觉。然而,事实证明,绕过验证码要容易得多,我们将在下一节讨论这个问题。现在,让我告诉你计算机视觉如何帮助我们。

我首先想到的是这个。假设字母的厚度为3,而噪音(随机的椭圆)的厚度为1,因此,如果你删除所有厚度为1的数字,你就会删除噪音。

我想没有一个OpenCV运算符能完全做到这一点。然而,我们可以用另一种方式来考虑它。从图像中每个几何图形的厚度中减去1,这样就会留下厚度为2的字母和厚度为0的噪声。因此,从本质上讲,我们有效地消除了噪音。

这种操作在OpenCV中确实存在,它被称为侵蚀。用它来消除噪声是非常简单的。

medium.com/media/de16e…

(Opening是一个首先使用侵蚀然后再扩张的操作。我们可以只使用侵蚀操作,但这将导致字母的厚度为2。扩张运算符又会使它们的厚度为3)

当以样本验证码为输入运行该脚本时,我们得到以下输出。

原始和预处理的验证码比较

正如你所看到的,图像现在更清晰了,我们可以使用OCR,如魔方,来提取字符。

很好!我们刚刚找到一种方法,通过使用计算机视觉😝来绕过这个简单的验证码。我们可以从中吸取以下教训。

不要使用类似reCAPTCHA v1的验证码。谷歌关闭该版本是有原因的。

现在我们将看到实际上没有必要使用计算机视觉。

在后端验证验证码的响应

为了绕过验证码,我需要知道它的来源。因此,我在DevTools中打开了网络标签,发现了来自服务器的以下响应。

Captcha属性包含base64编码的验证码图像,a属性包含一个十六进制字符串,其目的目前还不清楚。

同时,我发现了一个不常见的行为:验证码的输入是被动的,如果验证码是错误的,它会立即向你显示一条信息。我以为在任何输入变化后都会发出验证验证码的请求,但当我再次查看DevTools中的Network标签时,我发现没有发出新的请求。

这让我觉得验证码在我这边被验证了,而a属性与此有关。因此,我查看了源代码(在DevTools的调试器选项卡中)并搜索了a属性。这就是我所发现的。

正如你所看到的,在第5行,从用户那里获得了验证码响应的SHA1哈希值,在第6行,它与响应中的a属性进行比较。因此,a属性实际上是正确验证码响应的SHA1哈希值。

因为SHA1是一个单向的哈希值,而且要恢复它以得到正确的验证码响应是非常困难的,所以我们除了进行暴力攻击外没有什么可以做。这在本质上是非常简单的,我们只需要尝试所有可能的组合。

为了获得所有可能的组合,我们需要知道验证码由5个小写字母数字的英文字符组成(共36个字符),并且允许重复(我在看到多个验证码后发现了这些限制)。因此,总的可能性是60,466,176(36⁵)。

这似乎是一个很大的可能性,你可能认为几乎不可能逐一尝试。但实际上,这样做很简单,而且不需要太多的时间,正如你即将看到的那样。

蛮力攻击

下面的代码生成了所有可能的验证码值并进行了暴力攻击。由于所使用的库,代码相当简单。不过,我还是添加了一些Javadoc以方便阅读。

medium.com/media/cff76…

方法 generate(Writer) 和 read(Reader)。Iterator的添加只是为了方便。在我的例子中,从一个大小为~2.7GB的文件中读取所有60,466,176个哈希值和验证码,比即时生成它们更方便。

当然,通过流读取一个2.7GB的文件比读取整个文件并将其保存在一个列表中要有效得多(这样做可能会抛出OutOfMemoryError)。

注意一些重要的事情:虽然这是一个暴力攻击,但即使应用程序有某种速率限制,它也是无用的(分别检查CaptchaCracker和ExamplePage的第60和52行)。如果验证是在后端完成的,那就不是这样了。

因此,这里的教训是,不要在前台验证验证码,而要在后台验证,如果你这样做,要 增加速率限制以防止暴力攻击。或者干脆使用第三方,如谷歌的reCAPTCHA。

总结

我认为我在这里给出的建议是显而易见的,没有什么特别之处,但正如前面所说,如果我没有在 "企业 "应用中遇到这些故障,我就不会写这篇文章。

最后,我想补充这个奇怪而讽刺的事实:负责这个应用的企业只雇用有权利的专业人士。

说到这里,我已经没有什么了,只能感谢你阅读这篇文章,像往常一样,如果你认为有什么不对的地方或者可以改进的地方,请让我知道。我喜欢你的反馈。

附录A:用Selenium拦截验证码请求响应

该网页的工作情况如下。

  1. 用户被要求在一个表格中输入一些数据
  2. 当所有需要的字段都填好后,向后台发出请求,以获得验证码图像和SHA1哈希值(我们在上一节看到的响应)。
  3. 在验证码被成功解决之前,你不能进入下一个页面。

正如你所看到的,验证码图片和哈希值并不是从一开始就加载的,所以我们需要拦截异步请求的响应。为了做到这一点,我使用了以下代码。

medium.com/media/19065…

这段代码几乎是不言自明的,但它可能有助于澄清,在第45行,执行将停止,直到第80行的对象被排队(这在收到服务器的响应后异步发生)。

我知道这与如何不在网站上添加验证码的建议几乎没有关系,但我想把它包括进来,因为它可能会帮助某人,或者只是我未来的自己。