使用Rails存储加密的cookie

9
我需要在Rails中将一小段数据(少于10个字符)存储在Cookie中,并确保其安全。我不希望任何人能够读取该数据或注入自己的数据(因为这会开放应用程序受到许多攻击)。我认为加密Cookie内容是可行的方式(我是否还应该签名?)。最好的方法是什么?
目前,我正在执行以下操作,看起来很安全,但许多看起来比我更懂安全性的人发现它并不真正安全。
我以以下方式保存秘密:
encryptor = ActiveSupport::MessageEncryptor.new(Example::Application.config.secret_token)
cookies[:secret] = {
  :value => encryptor.encrypt(secret),
  :domain => "example.com",
  :secure => !(Rails.env.test? || Rails.env.development?)
}

然后我像这样阅读它:

encryptor = ActiveSupport::MessageEncryptor.new(Example::Application.config.secret_token)
secret = encryptor.decrypt(cookies[:secret])

这样安全吗?有更好的方法吗?

更新:我知道Rails的会话如何保证安全,既通过对cookie进行签名,也可以选择将会话内容存储在服务器端,我确实使用会话来完成它的功能。但是我的问题是关于存储cookie的,这是一条我不想在会话中保存的信息,但我仍然需要它是安全的。


出于好奇,为什么需要将它存储在 cookie 中而不是服务器端,在服务器端存储会更安全? - Russell
@russell 嗯,你需要在浏览器中存储一些东西,对吧?否则你就无法再次识别它。无论是实际数据还是表格记录的ID,这都是根据个人偏好和数据大小等其他考虑因素而定的。我正在存储的已经是表格中记录的ID了。我可以创建另一个表格,但在这种情况下似乎有些浪费。 - pupeno
我添加了一个答案,因为我认为将默认会话存储更改为使用数据库将为您提供所需的安全性,并且在创建表等方面几乎没有额外开销。 - Russell
@Russell 我不想使用会话。我的会话是按域名分的(blah.example.com),而这个数据是针对整个系统的(.example.com),因此在设置时需要使用域选项。 - pupeno
3个回答

13
  • 设置安全Cookie

    cookies.signed[:secret] = {
     :value => "foo bar",
     :domain => "example.com",
     :secure => !(Rails.env.test? || Rails.env.development?)
    }
    
  • 访问 cookie

  • cookies.signed[:secret] # returns "foo bar"
    

使用ActionController::Base.cookie_verifier_secret进行签名。 您可以在初始化文件中设置cookie_verifier_secret


我不想使用会话。我的会话是基于域(blah.example.com),而这段数据是用于整个系统(.example.com),所以在设置它时需要指定域选项。 - pupeno
更新了答案,请查看。 - Harish Shetty
使用 .signed 设置的 Cookie 也需要使用 .signed 访问。因此,您的第二个代码块应为 cookies.signed[:secret] - Jamon Holmgren

1
正如KandadaBoggu所说,看起来你想要的是一个会话变量,而会话变量默认情况下是加密并存储在cookie中。然而,如果你查看config/initializers/session_store.rb的内容,你会发现以下类似的内容:
 # Be sure to restart your server when you modify this file.
 MyRailsApp::Application.config.session_store :cookie_store, :key => '_my_rails_app_session'

 # Use the database for sessions instead of the cookie-based default,
 # which shouldn't be used to store highly confidential information
 # (create the session table with "rails generate session_migration")
 # MyRailsApp::Application.config.session_store :active_record_store

这让我想到,你应该使用数据库来存储会话,而不是基于 cookie 的默认设置,因为它不适合存储高度机密的信息。预先准备好的迁移使得设置变得非常容易,因此几乎没有额外的开销,一旦完成后,如果您需要在以后添加新的秘密信息,基本上就没有额外的开销了!

我不想使用会话。我的会话是按域名(blah.example.com)分的,而这个数据是针对整个系统的(.example.com),因此在设置时需要使用域选项。 - pupeno

1

我正在重新发布JacobM的答案,他已经删除了它,因为这是正确的答案并指引了我正确的方向。如果他恢复了它,我会删除这个并选择他的作为最佳答案。

首先,如果你使用encrypt_and_verify而不是encrypt,它将为你签署cookie。

然而,当涉及到安全性时,我总是更喜欢依赖于公开审查过的解决方案,而不是自己编写。一个例子就是encrypted-cookies gem


我很好奇为什么你不使用签名的cookies?(在Rails 3.x中默认支持) - Harish Shetty
1
@KandadaBoggu 由encrypt_and_verify或encrypted-cookies gem(1.0版后)处理的cookie是经过签名和加密的。如果这些数据被泄露,情况可能不会太严重,但我宁愿不去考虑它,只保持加密状态,从而对用户不透明,以确保安全性。 - pupeno

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接