rails 加密
最近,我一直在对我维护的gem进行测试重构,我需要测试它是否在正确的时间设置了正确的cookie。 但是,宝石中使用的cookie是已签名的cookie,这对我造成了轻微的打ic。 我以前从未测试过签名Cookie中的值,而且还不清楚该怎么做。
所以我想我会分享我发现的内容,以防万一。
Rails上的Cookie
在Rails应用程序中,可以使用三种Cookie:
简单会话cookie,签名cookie和加密cookie。 您可以
通过使用控制器中的cookies
对象来设置其中任何一个,如下所示:
class CookiesController < ApplicationController
def index
cookies[ "simple" ] = "Hello, I am easy to read."
cookies.signed[ "protected" ] = "Hello, I can be read, but I can't be tampered with."
cookies.encrypted[ "private" ] = "Hello, I can't be read or tampered with."
end
end
简单的饼干
简单的cookie由纯文本组成。 如果您在浏览器中检查了上面称为“简单”的cookie,您将看到文本“您好,我很容易阅读”。
简单的cookie可以存储真正无关紧要的数据。 最终用户可以阅读和更改它,并且您的应用程序不会受到影响。
签名的cookie
签名的cookie不会以纯文本形式发送到浏览器。 取而代之的是,它们由有效载荷和签名组成,并由两个破折号--
分隔。 在破折号之前,有效载荷是基数为64的编码数据 。 要读取数据,您可以基于64位对其进行解码。 此数据不是秘密数据,但是由于Cookie的第二部分是签名,因此不能被篡改。
通过获取应用程序的secret_key_base
和cookie中的数据的HMAC SHA1
摘要来创建签名。 如果您尝试读取Cookie时更改了cookie的内容,则签名将不再与内容匹配,并且Rails将返回nil
。 在ActiveSupport::MessageVerifier
这全部由ActiveSupport::MessageVerifier
处理。 从上面可以看到,您不必担心,可以将cookies.signed
对象当作哈希来对待。
签名的cookie对于用户可以读取的数据很有用,但是当您再次将其返回给服务器时,需要信任的是相同的。
加密的cookie
加密的cookie会更进一步,并加密cookie中的数据,然后对其进行签名。 这由ActiveSupport::MessageEncryptor
处理,这意味着如果没有secret_key_base
您将无法读取或写入此Cookie。 值得庆幸的是,您无需担心加密问题,使用cookies.encrypted
对象,您可以将加密的cookie设置为常规哈希来设置。
加密的cookie对于要与用户存储但不希望它们或任何人读取的私有数据很有用。
测试cookie
假设我们现在要测试上面看到的控制器。 我们想
确保我们所有的Cookie均已正确设置。 测试可能看起来
像这样的东西:
class CookiesControllerTest < ActionDispatch::IntegrationTest
test "should set cookies when getting the index" do
get root_url
assert_response :success
assert_equal "Hello, I am easy to read." , cookies[ "simple" ]
assert_equal "Hello, I can be read, but I can't be tampered with." , cookies[ "protected" ]
assert_equal "Hello, I can't be read or tampered with." , cookies[ "private" ]
end
end
或使用RSpec Rails:
RSpec.describe CookiesController,type: :request do
it "should set cookies when getting the index" do
get root_url
expect(response).to have_http_status( :success )
expect(cookies[ "simple" ]).to eq( "Hello, I am easy to read." )
expect(cookies[ "protected" ]).to eq( "Hello, I can be read, but I can't be tampered with." )
expect(cookies[ "private" ]).to eq( "Hello, I can't be read or tampered with." )
end
end
但这将在测试签名的cookie时失败,并且也不会通过加密的cookie。 如果这些cookie已签名或加密,则不能直接从罐子中调用这些cookie。
您可能会认为应该针对Cookie的signed
和encrypted
版本进行测试,如下所示:
assert_equal"Hello, I can be read, but I can't be tampered with." , cookies.signed[ "protected" ]
assert_equal "Hello, I can't be read or tampered with." , cookies.encrypted[ "private" ]
那也不行。 至少如果您使用的是当前推荐的测试控制器的方法(在Minitest中使用ActionDispatch::IntegrationTest
或在RSpec中type: :request
ActionDispatch::IntegrationTest
type: :request
,则它不起作用。
如果您使用的是旧样式ActionController::TestCase
或type: :controller
ActionController::TestCase
type: :controller
测试,则cookies.signed
和cookies.encrypted
将起作用。 如果您的应用程序具有较早的样式测试,请继续阅读以防万一您决定重构它们以使其与当前的Rails方式保持一致。
通过上述测试, cookies
对象实际上是Rack::Test::CookieJar
的实例,该实例不了解您的Rails应用程序机密。
那么我们如何测试这些cookie?
这就是我接触到的宝石的所在。 我需要测试签名cookie的结果,但是我有一个Rack::Test::CookieJar
对象。 好消息是,我们可以重新使用Rails应用程序自己的ActionDispatch::Cookies::CookieJar
来解码已签名的Cookie和解密已加密的Cookie。
为此,您ActionDispatch::Cookies::CookieJar
使用测试中的request
对象和cookie数据的哈希来实例化ActionDispatch::Cookies::CookieJar
的实例。 然后,您可以在该Cookie罐上调用signed
或encrypted
。
所以现在测试看起来像:
class CookiesControllerTest < ActionDispatch::IntegrationTest
test "should set cookies when getting the index" do
get root_url
assert_response :success
assert_equal "Hello, I am easy to read." , cookies[ "simple" ]
jar = ActionDispatch::Cookies::CookieJar.build(request, cookies.to_hash)
assert_equal "Hello, I can be read, but I can't be tampered with." , jar.signed[ "protected" ]
assert_equal "Hello, I can't be read or tampered with." , jar.encrypted[ "private" ]
end
end
或规格看起来像:
RSpec.describe CookiesController,type: :request do
it "gets cookies from the response" do
get root_url
expect(response).to have_http_status( :success )
expect(cookies[ "simple" ]).to eq( "Hello, I am easy to read." )
jar = ActionDispatch::Cookies::CookieJar.build(request, cookies.to_hash)
expect(jar.signed[ "protected" ]).to eq( "Hello, I can be read, but I can't be tampered with." )
expect(jar.encrypted[ "private" ]).to eq( "Hello, I can't be read or tampered with." )
end
end
红色,绿色,零食
在这篇文章中,我们已经看到了如何在Rails中测试签名或加密的cookie。 希望您的测试套件运行为绿色,并且现在覆盖您的cookie。
我将回到我正在研究的重构中。 现在,这些Cookie已被删除,还有很多测试可以覆盖。
翻译自: https://hackernoon.com/testing-signed-and-encrypted-cookies-in-rails-application-358z369v
rails 加密