我有一个非常独特的情况。我正在构建一个应用程序,用户将QR码上传到我的站点,解码后,它已经存储在数据库中的匹配ID(就像我在用户上传之前已经有qr代码的记录一样)
当他们上传它时,我解码它,这是一个base64字符串,如此6BbW0pxO0YENxn38HMUbcQ ==
就像我说的那样,该代码对应一些信息,在他们上传QR图像后,我将它们重定向到另一页,其中显示了qr代码,存储在DB中的相应信息,并且还提示它们使用提交按钮。按下时,我注意到他们已经确认,我还做了其他一些事情。
详细说明
作为用户,我访问www.url.com/code/upload并上传图片。然后,我将重定向到/ code / new,页面显示存储在DB中的数据,来自对应的图像解码。
如何使/ code / new上的提交按钮可靠?以下是我能想到的解决方案及其漏洞
使用存储在数据库中的对应数据传播/代码/ new,将@username和@movie称为表单,使用提交按钮并将数据发送到服务器
在参数中传递唯一的base64标识符,例如/ code / new?id = STRING
基本上,我有一个用户上传qr代码,提交后,我需要验证以确认他们是上传图像的那个。我上传图片后丢失了所有状态和信息。
建议的解决方案:
用户上传图像后,创建一个唯一的字符串并将其存储在会话中以及数据库中的记录(用户已登录,因此其为current_user.session_token),然后当用户单击提交时/ uploads / new,我抓住会话令牌,并验证current_user.session_token == session_token。
此时,我只能验证当前用户是否是上传图像的用户..然后我需要以某种方式获取来自上传的QR码的base64字符串。
另一个建议的解决方案:我暂时将base64字符串作为用户上传文件时的属性。所以我将有current_user.session_token和current_user.base64_string。然后,当用户点击第二个提交按钮时,我会执行类似
的操作#check if the user's token is equal to the sessions, and the string is not nil
if current_user.session_token == session_token && !current_user.base64_string.nil?
data = current_user.base64_string
#hooray! I have the QR code
end
然后删除会话令牌,然后删除current_user的base64_string和session_token
如果恶意用户试图伪造他们的会话令牌,它将无法匹配他们在数据库中的商店,那么当我处理发布请求时,我将不会继续。但是如果合法用户发出第二个帖子请求,会话ID匹配,我就能获取base64字符串。
TL; DR,我需要2个并发帖子请求来传递信息而不会丢失它,并且可以验证第一个和第二个帖子请求都是由同一个用户完成的。
如果有人耐心阅读,我很感激!如果有任何建议我会非常感激,或者如果您认为我的解决方案是充分的,请告诉我。谢谢!
答案 0 :(得分:1)
对第一个请求生成的参数进行签名,并在处理第二个请求时验证签名。
用于此的技术是HMAC。以下是如何使用Ruby中提供的一个版本:
require 'openssl'
secret = 'ABCDEFGHIJKLMNOP'
data = 'user:code'
signature = OpenSSL::HMAC.hexdigest( 'sha256', secret, data )
p signature
输出:
"bd7194c0604902d6594694d25e7f27bdc2d10926638e0ce8bdda3f6debb37f6a"
这是如何使用它将两条HTTP路由链接在一起,以便第二条路由可以信任通过第一条路由发送给它的参数未被篡改:
调用第一个路由时,生成或获取机密。重要的是,此秘密值不会被发送或暴露给最终用户。它可以简单地是应用程序配置(然后应用于所有链接的请求),但是如果你可以存储它与QR代码相关联,那么最强大的保护是在创建签名之前生成一个长的随机字符串,并存储它准备用于确认第二步。像SecureRandom.hex
这样的东西对于短期秘密是很好的,如果你有服务器端存储它的话。
将您想要免篡改的表单上的所有参数合并为一条长消息。最简单的事情是在数组中.join
,你应该使用任何值都不允许的分隔符,并且由于验证你也不接受。此字符串是示例中data
使用的值。
生成调用第二条路径的表单。除了您希望在下一阶段接受的参数之外,还要添加上面生成的signature
值。 不通过输入表单或Cookie等将secret
的值发送给客户端。
当您收到来自第二条路线的请求以完成多阶段请求时,请从用户发送的参数生成签名(在验证它们之后),并与从表单发送给您的签名进行比较。如果相同,则请求有效。如果它不同,那么数据可能已被篡改(假设您没有错误 - 如果任何参数可以包含非ASCII字符,请检查一致的字符编码等事项)
如果您对最终用户保密秘密,他们几乎无法生成正确的签名。只有路由1和路由器2中的代码知道如何操作(因为它可以访问正确的秘密,而不是因为它的编写方式有任何特殊的事实)。因此,您可以相信这些值尚未修改。