我正在考虑编写一个网页,为客户提供反馈表。
我希望客户能够使用任何特定订单的唯一 URL 访问此表单;一个简单的示例将采用http://www.example.com/feedback/012345的格式。
旁注:我已经熟悉 URL 重写。以给定语言或在给定服务器上创建/重定向 URL 不在此问题的范围内
客户必须进行身份验证(或就此而言,甚至拥有一个帐户)才能访问反馈表是不可接受的。但是,出于对统计正确性的考虑,我对上面 example.com/feedback/[order_id] 的明显解决方案并不满意。这允许任何人更改 URL 中的 ID 并访问另一个订单的反馈。
另一方面,理想情况下,我希望这些 URL 能够从收据等打印输出中输入,因此在许多“重置密码”链接上提供长哈希不是一个有效的选项。
基于此,我有以下标准:
- 每个订单都应该有一个唯一的 URL
- 这个 URL 应该是相对人类可输入的,现在把它理解为“短”
- 应该不可能更改 URL 中的字符并访问其他订单(在合理的概率范围内)
我的思路是应该在 URL 中放两条数据。客户记录上有很多人类可读的数据可以帮助解决这个问题,例如客户 ID、订单的联系电话号码、姓氏……虽然这消除了更改一两位数字的能力,但我看不到它显着提高给定 URL 对无聊的攻击者的“可猜测性”。
以 /feedback/[surname]/[id] 为例,您可以通过简单的字典攻击页面来接收一组有效的 URL:
for x in range(00000,99999):
for name in ["jones","smith", ....]:
url = "http://www.example.com/feedback/"+name+"/"+x
if exists(url):
print(url)
考虑到 tinyurl 之类的服务,我考虑的下一件事是对 ID 号进行哈希处理并以 /feedback/[hash]/[id] 的形式提供 URL
我已经做了一些研究并了解到 URL 缩短服务实际上可能使用自动增量 ID 记录而不是实际的数学哈希。这个方法可能没用
如果使用实际的散列函数,重要的是散列显然不是从 ID 号派生的。提供像 /feedback/trpxq/53192 这样的 URL 是没有用的,因为在看到其中的一个或两个之后,您可以轻松地提取之前的记录:/feedback/trpxp/53191
我当时在想,如果哈希包含盐可能会有所帮助,这样即使知道使用了什么哈希函数,也不可能对任何旧的有效订单 ID 进行哈希处理并显示有效的 URL。
所以,最后,这是实际的问题:
什么函数最适合用于创建基于 7-10 位整数 ID 和任意盐的哈希的简短、非显而易见、相对唯一的字母数字表示?
这本身不是 URL 缩短问题,所以如果哈希部分与 ID 部分的长度相同,我会很满意:减少到 10 个字母数字字符是可以接受的。
此外,不一定每次访问 URL 时都需要计算哈希值。可以在创建订单记录时计算它,或者在第一次访问该订单 ID 的页面时计算它。这意味着哈希函数不一定要很快。
尽管有可能为查找目的创建一个哈希表,但这个问题没有与哈希表相同的限制:查找是基于一个已经唯一的值完成的,因此只要足够,冲突解决不是绝对必要的对于给定的散列,很难找到具有相同散列的另一条记录。
我们现在已经完全脱离了确保反馈表需要做些什么的实际领域——这些数据实际上并没有那么重要——但请幽默,这是一个有趣的问题,我想知道是否有一个很好的解决方案可以最大限度地提高安全性和可读性。