我有超级丑陋的代码,如下所示:
class User < ActiveRecord::Base
self.table_name = 'users'
def get_password
@test_password = User.find_by_sql "SELECT CAST(AES_DECRYPT(Pass, 'kkk') AS CHAR(50)) Pass From prod.sys_users Where Owner = '"+@owner+"' AND User = '"+@user+"'"
@test_password[0].Pass
end
end
此代码有效,但它让我感到恶心,因为它不是根据Ruby编码样式编写的。所以我决定修复这段代码,到目前为止我所拥有的代码:
class User < ActiveRecord::Base
self.table_name = 'users'
def get_pass
User.where(Owner: @owner, User: @user).pluck(:Pass).first
end
end
所以,我收到加密密码,我该怎么解密呢?
我累了OpenSSL
,但此处的密钥'kkk'
太短了。
我该如何解决这个问题?
答案 0 :(得分:1)
在这种情况下,您可能最好完全转换字段值。这可以在迁移中完成,一旦完成,您就不必担心MySQL如何存储数据。这也是实现数据库独立性的一步。
因此,迁移基本上会做三件事:
迁移可能如下所示:
class ConvertMySqlEncryptedData < ActiveRecord::Migration
# Local proxy class to prevent interaction issues with the real User class
class User < ActiveRecord::Base
end
def up
# Check to see if the flag has already been created (indicates that migration may have failed midway through)
unless column_exists?(:users, :encrypted_field_converted)
# Add the flag field to the table
change_table :users do |t|
t.boolean :encrypted_field_converted, null: false, default: false
end
end
# Add an index to make the update step go much more quickly
add_index :users, :encrypted_field_converted, unique: false
# Make sure that ActiveRecord can see the new column
User.reset_column_information
# Setup for AES 256 bit cipher-block chaining symetric encryption
alg = "AES-256-CBC"
digest = Digest::SHA256.new
digest.update("symetric key")
key = digest.digest
iv = OpenSSL::Cipher::Cipher.new(alg).random_iv
key64 = Base64.encode(key)
# Don't update timestamps
ActiveRecord::Base.record_timestamps = false
begin
# Cycle through the users that haven't yet been updated
User.where(encrypted_field_converted: false).pluck("CAST(AES_DECRYPT(Pass, 'kkk') AS CHAR(50)) Pass").each do |user|
# Re-encode the password with OpenSSL AES, based on the setup above
new_pass = aes.update(user.pass).final
# Update the password on the row, and set the flag to indicate that conversion has occurred
user.update_attributes(pass: new_pass, encrypted_field_converted: true)
end
ensure
# Reset timestamp recording
ActiveRecord::Base.record_timestamps = true
end
end
def down
# To undo or not undo, that is the question...
end
end
这不是我的首要问题,因此加密可能存在问题。在结构方面,它应该是良好的形状,并考虑到许多事情:
updated_at
列,以防止覆盖可能有用的先前值(这不是重大更改,因此updated_at
不需要更新)pass
字段,以便最大限度地减少转移开销现在,您可以根据应用程序的需要查询pass
并加密/解密。您可以在应用程序级别记录和支持该字段,而不是依赖于数据库实现。
我花了几年时间咨询和进行数据库转换,从一个数据库产品到另一个数据库产品,或作为重要版本升级的一部分。当需要升级时,它还允许开发使用更轻量级的数据库(例如SQLite)或测试其他产品的可行性。避免使用MySQL加密等特定于数据库的功能,从长远来看,可以为您(或您的雇主)节省大量资金和麻烦。数据库独立是你的朋友;拥抱它并使用ActiveRecord为您提供的内容。