如何从操作中保护此表单帖子

时间:2014-03-08 00:47:49

标签: ruby-on-rails ruby security

我有一个非常独特的情况。我正在构建一个应用程序,用户将QR码上传到我的站点,解码后,它已经存储在数据库中的匹配ID(就像我在用户上传之前已经有qr代码的记录一样)

当他们上传它时,我解码它,这是一个base64字符串,如此6BbW0pxO0YENxn38HMUbcQ ==

就像我说的那样,该代码对应一些信息,在他们上传QR图像后,我将它们重定向到另一页,其中显示了qr代码,存储在DB中的相应信息,并且还提示它们使用提交按钮。按下时,我注意到他们已经确认,我还做了其他一些事情。

详细说明

作为用户,我访问www.url.com/code/upload并上传图片。然后,我将重定向到/ code / new,页面显示存储在DB中的数据,来自对应的图像解码。

如何使/ code / new上的提交按钮可靠?以下是我能想到的解决方案及其漏洞

  • 使用存储在数据库中的对应数据传播/代码/ new,将@username和@movie称为表单,使用提交按钮并将数据发送到服务器

    • 这很危险,因为我认为没有人阻止某人编辑DOM并将@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个并发帖子请求来传递信息而不会丢失它,并且可以验证第一个和第二个帖子请求都是由同一个用户完成的。

如果有人耐心阅读,我很感激!如果有任何建议我会非常感激,或者如果您认为我的解决方案是充分的,请告诉我。谢谢!

1 个答案:

答案 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中的代码知道如何操作(因为它可以访问正确的秘密,而不是因为它的编写方式有任何特殊的事实)。因此,您可以相信这些值尚未修改。