我正在设计一个电子商务网站,其中一部分是订单摘要页面。此订单摘要页面将包含订购产品的人的地址和姓名。

我的计划是加密订单 ID,并将其传递给结帐成功页面,如下所示:

这意味着客户可以“刷新”成功页面并仍然获得订单确认。

加密 ID 的长度意味着任何人都很难猜到,但是 URL 会存储在日志等中,虽然 URL 本身没有 PII,但如果任何人都能够看到记录在某些日志中的其他人的 URL,他们就可以单击该 URL 并查看 PII。

解决此问题的最佳做法是什么?这从根本上来说是一种糟糕的设计吗?如果是这样,那么替代方案是什么?也许将数据保存在会话中?

8

  • 1
    欢迎。请澄清您希望使用什么算法来加密订单 ID?另外,订单 ID 是否已经是 64 字节,或者可能的订单号范围是否小得多?


    – 

  • 实际上,加密算法是 AES-128 – 我已经编辑了问题以反映这一点。


    – 

  • 1
    @Bergi 我猜 OP 指的是 POST 数据重定向到订单页面的情况,其中页面刷新会弹出“您确定要重新提交表单吗”警报。我猜,他试图通过将其设为 GET 页面来避免这种情况。


    – 

  • 1
    @U.Windl:哪个外部链接?该mysite.comURL 只是示例,不是真正的 URL。


    – 

  • 1
    @Bergi “为什么不使用[…]常规会话身份验证…” – 这假设您有一个经过身份验证的会话,这需要某种方式进行身份验证/登录。许多网上商店允许您在没有账户的情况下订购,所以我认为这是一个合理的问题。


    – 


最佳答案
4

我的计划是加密订单 ID,并将其传递给结帐成功页面,如下所示:

看起来你想要的是完整性,而不是机密性。加密并不一定能保证完整性。某些东西被加密并不一定意味着它不能被操纵。

正确的加密原语是对订单标识符进行签名。计算哈希值HMAC(secret, orderId)并创建一个 URL,例如:

或者,您可以使用 AEAD(带有附加数据的认证加密)方案。

加密 ID 的长度意味着任何人都很难猜到,但是 URL 会存储在日志等中,虽然 URL 本身没有 PII,但如果任何人都能够看到记录在某些日志中的其他人的 URL,他们就可以单击该 URL 并查看 PII。

看来你对相关风险的看法是正确的。将敏感信息存储在 URL 中(或 URL 后面)通常不是一个好主意,因为这些信息会泄露到浏览器缓存和日志等中。

解决此问题的最佳做法是什么?这从根本上来说是一种糟糕的设计吗?如果是这样,那么替代方案是什么?也许将数据保存在会话中?

如果您只是想在订购后显示确认,您可以将订单标识符保存为会话。

如果您想在电子邮件中发送订单确认链接,您能做的很少。一件事是减少订单确认页面的有效时间。也许您只能为上周下的订单提供订单确认页面。这样,就不可能列举所有订单。

使用加密订单 ID(或订单 ID 的 HMAC)的问题在于整个方案都依赖于密钥的保密性。如果您有一个安全的密钥存储(理想情况下是硬件安全模块),那么这种风险可能是可以接受的,否则您应该避免它。

此外,更换密钥或撤销对单个订单的访问权限也是您的方案存在的问题。密钥不应永远使用,而应在一段时间后更新。如果您这样做,那么您要么必须使所有仍依赖于旧密钥的 URL 失效(这对您的客户来说并不好),要么必须并行使用多个密钥(这会使应用程序更加复杂)。当您发现某个订单 ID 已泄露时,也会出现同样的问题 – 如果您更改密钥,这也会影响其他订单(可能是所有订单)。

一个更好的方法是为每个订单生成一个安全的随机令牌,将其包含在 URL 中,并将令牌的哈希值存储在数据库中。URL 将如下所示:

https://www.mysite.com/success?order_id=465&token=d5dfa49c24d79bd7ad714999d9c0e08b

令牌不应以纯文本形式存储。相反,应使用 SHA-256 之类的算法对其进行哈希处理,并将结果存储在数据库中。收到令牌后,您还会对其进行哈希处理,然后尝试在数据库中查找哈希值。

与加密或顺序 HMAC 相比,这有几个主要优点:

  • 服务器无需保护“主秘密”。如果数据库中的令牌哈希值泄露,这不是问题,因为只要您对令牌使用安全的随机数生成器,它们就不会受到暴力攻击。
  • 您只需更改令牌即可轻松撤销对单个订单的访问权限。这不会影响任何其他订单。
  • 无需实现密钥轮换。

4

  • 3
    使用随机令牌而不是加密标识符


    – 

  • 使用 UUID 作为随机标识符基本上可以免费解决很多问题。


    – 

  • “相反,使用 SHA-256 之类的算法对其进行哈希处理,然后将结果存储在数据库中。” – 我同意使用唯一的安全随机令牌,而不是从订单 ID 中派生出它,但在数据库中对其进行哈希处理有什么意义呢?


    – 

  • @marcelm:哈希算法的意义在于,即使服务器被攻破,令牌也是安全的。如果不进行哈希算法,攻击者将立即获得所有明文令牌。


    – 

我个人会采取额外的预防措施:部分审查所显示文档上的姓名和地址(因此空手道代码变成 k*** c***,11 Wall Street 变成 11 W******),然后允许用户输入购买者的电子邮件地址或电话号码以显示这些详细信息。我认为在没有至少部分确认的情况下公开此类数据不是一个好主意。正如您所说,这些 URL 最终会出现在日志、浏览器历史记录和其他地方。

1

  • 在我看来,这似乎是正确的答案。我假设您想到的用例是用户希望在稍后的某个时间返回订单确认页面,而无需登录,也许是为了查看跟踪信息或类似信息?在这种情况下,显示相关信息(可能不是 PII),并隐藏(或更好地排除)PII。如果他们想检查他们输入的地址,则要求他们表明自己的身份。


    – 

这是一个身份验证/授权问题。问题是,“URL 中包含很长且无法猜测的部分,是否足以识别用户?”您提出了几种可能不具备这种能力的情况,但值得注意的是,这在电子商务中有时是一种常用模式。

通常,这个问题可以通过会话来解决,即为用户的浏览器提供某种会话令牌,该令牌可以随请求一起发送到确认页面。然后,服务器验证令牌是否未过期,以及是否与订单 ID 匹配。如果令牌过期,您希望用户能够在一段时间后返回,您可以为用户提供另一种方式来证明其身份,例如单击新电子邮件或短信中的链接。一种对基础设施要求较低的验证方式可能是让用户验证电话号码或送货地址等详细信息。

没有办法用加密技术取代订单 ID 上的身份验证,因为最终它只是一个地球上任何人都可能拥有的 URL。