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
我需要以某种方式让我的路线不可猜测。
实际上用户通过读取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