Rails 4中的secret_key_base有什么用途?

79
我刚开始学习 Rails 4,不理解在 Rails 4 中在 config/secrets.yml 下使用的 secret_key_base 的用途。你能否解释一下这个概念?
此外,在生产环境中工作时,我需要通过 devise.rbconfig.secret_keysecret_key_base 设置 secret_key。但是,我可以使用 rake secret 命令生成新的密钥。
开发环境和生产环境之间有什么区别?
当我每次生成新的密钥并将其添加到 secret_key_base 中时,如何匹配新生成的 secret_key
它如何保护应用程序与其他服务器的安全性?

5
针对使用 Ruby on Rails 5.2 或更新版本的读者:secret_key_base 仍然被使用,但是现在存储在 config/credentials.yml.enc 中,这个文件已加密。您可以在这里了解关于新凭据系统的更多信息,或运行 rails credentials:help 命令。 - 3limin4t0r
2个回答

69
secret_token.rb文件的内容包括一个长随机字符串,用于验证已签名cookie的完整性(例如用户在您的Web应用程序中登录时使用的会话)。 文档指出:

使用来自secret_token.rb初始化器的现有secret_key_base设置SECRET_KEY_BASE环境变量, 为在生产模式下运行Rails应用程序的任何用户。 或者,您可以将现有的secret_key_basesecret_token.rb初始化器复制到secrets.yml的production部分中, 替换<%= ENV [“SECRET_KEY_BASE”]%>

由于这是重要文件,不能将其放入.gitignore,因此最好将env变量用于存储secret_key_base值:
创建.env.powenv文件并将其存储为:
export SECRET_TOKEN="9489b3eee4eccf317ed77407553e8adc97baca7c74dc7ee33cd93e4c8b69477eea66eaedeb18af0be2679887c7c69c0a28c0fded0a71ea472a8c4laalal19cb"

然后在 config/initializers/secret_token.rb 中:

YourAppName::Application.config.secret_key_base = if Rails.env.development? or Rails.env.test? # generate simple key for test and development environments
  ('a' * 30) # should be at least 30 chars long
else
  ENV['SECRET_TOKEN']
end

这篇文章内容丰富、有些老旧,但对这个主题非常有用。


更新于04.05.15

从Rails 4.2开始,不再使用secret_token.rb文件。按照新约定,有一个config/secrets.yml文件用于存储应用程序的机密信息。

请参阅如何根据创新升级现有应用程序到4.2.x版本。


技术上secrect_key_base的目的是作为应用程序的key_generator方法(检查Rails.application.key_generator)的秘密输入。

应用程序的key_generator以及secret_key_base由Rails框架内的三个核心功能使用:

  • 为可通过cookies.encrypted访问的加密cookie派生密钥。
  • 为可通过cookies.signed访问的HMAC签名cookie派生密钥。
  • 为应用程序的所有命名message_verifier实例派生密钥。

请在@michaeljcoyne的文章中了解更多关于这三个功能的信息。


请注意,如果您使用类似Ansible的工具进行部署,您可以在生产部署期间替换整个secret.yml文件,并且如果您愿意,可以将config/secret.yml添加到gitignore中。 - Kris
实际上,config/secrets.yml 是自 Rails 4.1 版本引入的。 - Fumisky Wells
所有这些意味着当您更改secret_key_base时,您的用户将被注销。至少如此。 - x-yuri

28

secret_key_base用于加密和签名会话

以便在cookie中安全地来回发送会话


Rails 4中,

  1. 如果您的应用程序名为Hello,并且
  2. 您设置了session ['a'] ='b'

您的cookie将类似于此:

_Hello_session=BAh7B0kiD3%3D%3D--dc40a55cd52fe32bb3b84ae0608956dfb5824689

翻译成中文为:

_Hello_session=<encrypted a=b>--<digital signature>

Cookie是由服务器设置并保存在客户端,每次请求页面时浏览器会重新发送已经设置的cookie到服务器。

为了防止恶意人士理解字符串,它被加密
为了防止恶意人士篡改cookie,使用数字签名

在这两种情况下都使用secret_key_base值(用于加密/解密a=b并验证数字签名)。


  1. 据我所知,会话数据保存在服务器上,并且有一个存储在 cookie 中的 session_id。例如,在会话中存储 user_id,只有浏览器可以看到 session_id,而一旦登录,服务器就可以通过 session_id 知道是哪个用户发送了请求。在这里,您说 session['a'] = 'b' 将加密 cookie 中的数据。我不确定您是否混淆了会话和 cookie。
  2. 如果不知道 secret_key_base,浏览器如何解密并获取信息?
- Damon Yuan
3
抱歉,现在我知道Rails使用基于cookie的会话,这意味着会话信息存储在cookies内部。 - Damon Yuan
是的,基于cookie的会话为分布式应用服务器中的会话提供了可移植性和速度。 - hammady

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