问题
由于这个问题,我不得不将我的RoR应用程序升级到Rails 7。在进行此升级时,我使用Lockbox gem加密的db列不再能够读取,因为Rails正在使用本机解密来尝试解密字段。我以issue on GitHub的形式发布了它,但我也想知道是否还有其他人有解决方案可以将数据从一种加密格式迁移到Rails 7.0附带的新的本地加密(目前Rails的稳定版本是6.1.4,Rails 7.0.alpha在GitHub的主分支上)
编码
app/models/journal_entry.rb
class JournalEntry < ApplicationRecord
belongs_to :prayer_journal
encrypts :content
validates :content, presence: true
end
db/schema.rb
create_table "journal_entries", force: :cascade do |t|
t.bigint "prayer_journal_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.text "content_ciphertext"
t.index ["prayer_journal_id"], name: "index_journal_entries_on_prayer_journal_id"
end
第一个日志条目的控制台输出
#<JournalEntry:0x00007f95364745c8
id: 1,
prayer_journal_id: 1,
created_at: Sat, 15 May 2021 00:00:00.000000000 UTC +00:00,
updated_at: Sat, 17 Jul 2021 03:12:34.951395000 UTC +00:00,
content_ciphertext: "l6lfumUqk9RqUHMf0aVUfL2sL+WqkhBmHpyqKqMtxD4=",
content: nil>
3条答案
按热度按时间iswrvxsc1#
在花了几个小时阅读Rails指南和各种关于新的本机加密的博客文章之后,我能够弄清楚如何迁移数据。这是一个多步骤的过程,但我觉得我会把它放在这里,以便将来帮助别人。
首先,我确实想说的是,如果我正确阅读了指南,可能会列出其他加密/解密提供商。我无法弄清楚这一点,所以决定用我所知道的来创建一个解决方案。
我如何想出解决办法
我注意到在我的模式中实际上没有一个“content”列,而是一个“content_ciphertext”列,当在
encrypt :content
中调用lockbox时,它会加密并将其放置在该列中。我可以调用JournalEntry.first.content
来解密content_ciphertext
字段并提供纯文本。这就是为什么在升级到Rails 7和原生加密之后,它一直说列content
是nil
;因为实际上没有这个名字的列。Rails 7在模式中使用精确的命名,而不是将“ciphertext”等附加到列名。有了这些知识,剩下的问题就解决了。
解决步骤
1.升级导轨版本之前:创建迁移以将内容字段添加到包含加密数据的表中。在我的情况下有三张table。我运行了这个代码:
rails g migration AddUnencryptedContentFieldToDatabaseTabels
并将迁移文件更改为如下所示:
完成后,我编写了一个rake任务来遍历并将所有加密字段复制到一个未加密的列中。
这两个都写好了,我现在可以将代码部署到生产环境了。一旦部署完成,我将在生产控制台中运行
rake db:migrate
,然后运行rake switch_encryption_1
来解密并将所有字段复制到新列。然后,我还可以进行测试,以确保数据在继续之前确实被复制和解密。
1.回到开发阶段,我现在可以更新我的
Gemfile
新的Rails主分支,因为我已经解密了字段。因此,我将Gemfile
更改为:gem 'rails', :github => 'rails/rails', :branch => 'main'
然后,您需要通过在控制台中运行
bin/rails db:encryption:init
并将值复制到凭据文件中来创建加密密钥。如果你不知道怎么做,你可以运行下面的代码EDITOR=nano rails credentials:edit
并将值复制到该文件中:然后按照提示保存并退出。对我来说,这是控制+大写字母'O'写出,然后控制+大写字母'X'退出。这将有助于发展。从Rails 6开始,我们就可以为不同的环境设置不同的凭证。因此,您将复制相同的数据,但在控制台中运行
EDITOR=nano rails credentials:edit --environment production
以获得生产凭据。(记住确保这些密钥非常安全,不要将其签入版本控制器)然后,我创建了另一个迁移
rails g migration AddContentFieldToDatabaseTabels
并将迁移文件更改为如下所示:
您可能会注意到,我还添加了删除旧加密列的代码。这是因为它将不再被使用,并且我已经验证了内容现在保存在
unencrypted_content
列中。然后,我编写了另一个rake任务来遍历并将所有数据从
unencrypted_content
列复制到content
列。由于我的模型已经有了前面使用Lockbox gem的代码encrypts :content
,所以我不需要将其添加到模型中来让Rails知道加密这些列。现在部署您的生产凭据也应该已部署用于加密。现在在生产控制台中运行此命令:
rake db:migrate
和rake switch_encryption_2
。在我这么做之后,我验证了加密工作。1.我现在可以在开发中创建另一个迁移来删除未加密的表列。像这样:
rails g migration DeleteUnencryptedContentFieldFromDatabaseTables
db/migrate/*******_delete_unencrypted_content_field_to_database_tabels.rb
将其推到生产环境并运行
rake db:migrate
。此时,所有内容都应该迁移到新的本地Rails 7加密。
希望对未来的程序员有所帮助。编码快乐!
奖金部分
对于我们中的偏执狂,或者处理非常敏感的数据并需要确保未加密的列不再存在。下面是我创建的第三个rake任务,它使用
nil
遍历并覆盖列。您可以在部署迁移以删除列之前运行此命令。但是,实际上,这可能只是矫枉过正:zbdgwd5y2#
在Rails 7迁移之后,您需要更改加密关键字以继续使用Lockbox(稍后再决定是否需要迁移到Rails加密方法)。
Rails 7之前:
encrypt: :login, key: Rails.application.credentials.lockbox_key
Rails 7:
has_encrypted: :login, key: Rails.application.credentials.lockbox_key
因为
encrypt:
被Rails7加密使用。p3rjfoxz3#
要修复此Lockbox gem相关问题,您只需
1.将加密箱gem版本更改为大于
v0.6.4
1.并更改
encrypts
到
lockbox_encrypts
在模型类。就是这样
因为新的Rails 7加密也使用了
encrypts
,Lockbox团队添加了一个新的lockbox_encrypts
方法。你可以找到相关的GitHub讨论here。
但是,如果你想开始使用Rails 7加密(并从你的应用中删除Lockbox gem),这不是你需要做的。