Rails 路由:如何创建不可猜测的路由

Rails routing: How to create an unguessable route

我需要以某种方式让我的路线不可猜测。

实际上用户通过读取QR-CODE发出get请求完成了操作周期(订单状态为完成)。

但是 'guess' 路由非常容易,因为 id 在整个订单生命周期中都是相同的。当状态被接受(完成前)时,用户可以在 URL 中看到 id。

所以我想在 url 中添加一种随机标记,这样他们就无法猜测路线...

我的路线是这样的atm:

resources :orders, only: %i(create show index destroy edit update) do
    resources :reviews, only: %i(create new show index)
    resources :payments, only: %i(new create)
    member do
      post 'accept'
    end
    member do
      get 'read_qrcode'
    end
  end

生成此模式到 read_qrcode 路线:

/orders/:id/read_qrcode

所以我想在 read_qrcode 之后添加任何类型的令牌,可能是 MD5 哈希、时间戳或其他任何东西,然后得到一个 url,如下所示:

/orders/:id/read_qrcode/1a79a4d60de6718e8e5b326e338ae533

我怎样才能达到这个结果,或者可能有另一种解决方案?

使令牌成为 ID 和秘密串联的 md5。

所以,让我们说秘密是“-no-guessing!”。

ID为1,则md5(“1-no-guessing!)为9493F2E821BA8B1FC791A048BBCD9A19

如果 ID 为 2,令牌将是 AD17E6D3551BF0C0A2B0D5A029AEFBB2

这些是示例中字符串的合法 MD5 哈希值,您应该能够验证。

但我需要知道能够生成它的秘密。你的应用知道这个秘密,但你的用户不知道。

处理您的订单#read_qrcode 操作时,将令牌作为获取参数传递(无需将其作为路径参数)。然后,让控制器生成 ID 和秘密串联的 md5,将其与作为参数传递的令牌进行比较

我上面描述的本质上是一个HMAC,其中“消息”是订单的ID。有关 HMAC 的更多信息,请参阅 https://en.m.wikipedia.org/wiki/HMAC

一种简单的方法是简单地使用 SecureRandom 库(已经在 Ruby Core 中),并为每个订单生成一个唯一的令牌。 例如,在回调中很容易做到这一点。

SecureRandom.hex(10) #=> "52750b30ffbc7de3b362"

将令牌存储在记录中,并在扫描before_action中的二维码时进行检查。

Rails 6.1 也支持签名 id

order = Order.find(1)

Order.find_signed(order.signed_id)

https://github.com/rails/rails/pull/39313

https://blog.saeloun.com/2020/05/20/rails-6-1-adds-support-for-signed-ids-to-active-record.html