hashcash 是一个基于可广泛应用的 SHA-1 算法的巧妙系统,它使得请求者要进行大量可参数化的工作,而求值程序仍可以“廉价”地进行检验。换句话说,发送者为了向您的收件箱中放入一些内容,不得不去做一些切实的工作。您当然可以使用 hashcash 来防止垃圾邮件,不过它还有其他方面的应用,其中包括为 Wiki 防止垃圾邮件以及加速分布式并行应用程序的运转。在本文中,您将接触到 David 自己的基于 Python 的 hashcash 实现。
hashcash.org Web 站点(请参阅参考资料)指出,hashcash 系统的主要功能是作为一个垃圾邮件过滤协议:
Hashcash 是一个拒绝服务(denial-of-service)计数器度量工具。当前它的主要作用是帮助 hashcash 用户避免因为使用了基于内容和基于黑名单的(blacklist-based)反垃圾邮件系统而丢失邮件。
可是,我认为,这项技术有着广泛的适用性,并不是只适用于电子邮件。本文还将介绍这项技术在邮件过滤方面的应用,并将提供它在其他一些方面的应用。文中将介绍我自己用 Python 完成的 hashcash 实现(它似乎是第一个当前 发布的 Python 版本),hashcash.org 站点上现在已经包含该实现。David McNab 创建了一个 Python 实现,该实现使用的协议与 hashcash 不是特别相似;其他一些开发人员也创建了部分实现 hashcash 的不完全的 Pytyhon 版本。
不过,在开始这些话题之前,让我们来回顾一下什么是 hashcash。
hashcash 基础知识
hashcash 的灵感来自于这样一个想法,即一些数学结果难于发现而易于校验。一个众所周知的例子是因数分解一个大的数字(尤其是因数较少的数字)。将一些数字相乘来获得它们的积的代价是低廉的(毕竟,CPU 周期就是金钱),但首先找到那些因数,而这项操作的代价却要高得多。
RSA 公钥密码系统就是基于这种因数分解特性的。如果应答者能够回答因数分解质询(Challenge),则说明他已经做了相当多的工作(或者偷偷地从生成那个组合的人那里得到了因数)。
对交互式质询来说,因数分解足以胜任。比如,我有一个在线资源,希望您能象征性地为其付出代价。我可以向您发送一个消息,说“只要您能因数分解这个数,我将让您得到这个资源”。没有诚意的人将无法得到我的资源,只有那些能够证明自己有足够的兴趣、付出一些 CPU 周期来回答这个质询的人才能得到这个资源。
非交互式质询
不过,有一些资源无法很方便地进行交互式协商。
我的电子邮件收件箱是我非常重视的一个资源。但不期而至的消息占用了我的一些磁盘空间和带宽,最糟糕的是,它们吸引了我的注意力。我并不介意陌生人给我写信,但是,我希望他们能以稍微认真的态度,亲自通过对我有价值的邮件与我取得联系。至少,我不希望他们是垃圾邮件制造者,那些人向我和上百万的其他人发送包含同样消息的邮件,期望我们中的某些人能购买某种产品或陷入一个骗局。
为了实现非交互式的“支付(payment)”,hashcash 让我向所有想给我发送电子邮件的人都分发一个标准质询。在您的消息头中,必须包括一个合法的 hashcash 戳记(hashcash stamp);具体地说,该标志中包含我的收件人地址。
hashcash 提出质询的方式是,当通过安全散列算法(Secure Hash Algorithm)进行散列时,要求“minters”生成一个字符串(戳记,stamps),在它们的散列中有很多前导零。所找到的前导零的数目就是特定戳记的比特值。给定 SHA-1 的一致性与加密强度,找出给定比特值的 hashcash 戳记的惟一已知途径是平均 2^b 次运行 SHA-1。
然而,要确认一个戳记,只需要进行一次 SHA-1 计算即可。对于电子邮件中的应用来说,当前推荐使用的是 20-比特值:为了找到一个合法的戳记,发送者需要进行大约一百万次尝试,在最新的 CPU 和经过编译的应用程序上,这将需要不到一秒的时间。在相对旧一些的机器上它也只需要几秒钟的时间。
虽然我们已经开始讨论 bashcash 基础知识,但在继续讨论之前,让我们先领略一下 SHA 算法的强大功能。
SHA 有多么强大?
在一次被证明是密码界中具有重大意义的事件中,披露出一个对 SHA-0 的碰撞(collision)(请参阅参考资料中指向 Pascal Junod 的电子邮件的链接,它给出了实际碰撞的细节)。所使用的攻击需要大约 2^51 步,远远少于我们所期望的暴力构造碰撞所需要的大约 2^80 步(以及存储空间)(遵循“生日悖论(birthday paradox);关于生日悖论以及如何将它应用于散列函数的更多信息的链接,请参阅参考资料)。
在过于担心这种与 bashcash 相关的攻击之前,要紧记两点:一是这种方法攻击的是 SHA-0,不是 SHA-1(目前还不是)。另一相关的保证是,在当前最快的 CPU 上,2^51 步需要的时间仍会超过 9 CPU 年。即便有类似的方法可以应用于 SHA-1,构造虚假碰撞的代价也不可能低于构造更大数量的 20-位戳记(或者甚至是 40-位 hashcash 戳记)。
回到我们先前的讨论。
