Cách đơn giản để mã hóa thuộc tính của model trong Rails
Bài đăng này đã không được cập nhật trong 5 năm
Giới thiệu
Khi lưu trữ project trên các public repo việc để các dữ liệu ở plain text thì mình thấy không an tâm lắm, nên mình sẽ tìm cách mã hóa chúng. Trong bài viết này, mình xin giới thiệu cách sử dụng module Cipher của thư viện openssl được cung cấp mặc định trong Ruby để mã hóa các dữ liệu khi lưu xuống database.
Cách cài đặt
Ở đây mình sử dụng module Cipher của thư viện OpenSSL cung cấp mặc định của Ruby nên cũng không cần cài đặt gì thêm
Cách sử dụng
Ví dụ mình có một model Staff gồm các thông tin name, email, staff_code.
create_table :staffs do |t|
t.string :email,
t.string :name,
t.staff :code
end
Đây là dữ liệu nhạy cảm nên mình muốn mã hóa chúng trước khi lưu xuống csdl.
Đầu tiên tạo file lib/crypt.rb
như sau:
module Crypt
class << self
ALGO = "aes-128-cbc"
def encrypt value
crypt :encrypt, value
end
def decrypt value
crypt :decrypt, value
end
def encryption_key
ENV["ENCRYPTION_KEY"].to_s
end
def crypt cipher_method, value
cipher = OpenSSL::Cipher.new ALGO
cipher.send cipher_method
cipher.pkcs5_keyivgen encryption_key
result = cipher.update value
result << cipher.final
end
end
end
Ở đây file crypt.rb
là file dùng để mã hóa và giải mã. Cụ thể như sau:
ALGO = "aes-128-cbc"
: Khai báo constain kểu của mã hóa aes (Advanced Encryption Standard), độ dài 128 bit, AES thường hoạt động ở bốn chế độ cơ bản của mã khối n-bit (ECB, CBC, CFB và OFB) đặc tả bởi tiêu chuẩn ISO/IEC 10116:1997 Information technology– Security techniques – Modes of operation for an n-bit cipher (Công nghệ thông tin- kỹ thuật an toàn- chế độ hoạt động của mã hóa nbit).encrypt(value)
là phương thức mã hóa một plain text truyền vào và trả kết quả là một chuỗi đã được mã hóa(Cipher text).decrypt(value)
là phương thức giải mã một chuỗi truyền vào thành plain text.encryption_key
la phương thức lấy key dùng để mã hóa cũng như giải mã. Để lấy được key này chúng ta cần phải khai báo một environtment variable ENCRYPTION_KEYcrypt(cipher_method, value)
đây là phương thức chính dùng để mã hóa cũng như giải mã.
Vậy là chúng ta đã có một module để mã hóa và giải mã.
Công việc tiếp theo là tạo file lib/encrypted_coder.rb
như sau:
class EncryptedCoder
def load value
return if value.blank?
Marshal.load Crypt.decrypt(Base64.decode64(value))
end
def dump value
return if value.blank?
Base64.encode64 Crypt.encrypt(Marshal.dump(value))
end
end
Ở đây có 2 phương thức là load và dump mình ý nghĩa tên phương thức ở phần dưới.
load
dùng để lấy kết quả từ một chuỗi đã được mã hóa.- 'dump' dủng để mã hóa một chuỗi đầu vào.
Để tăng tính bảo mật thì trước khi mã hóa chuỗi đầu vào, chúng ta dùng
Marshal.dump(value)
tức là dùng module Marshal của ruby để đưa 1 object thành luồng byte. VàBase64.encode64 Crypt.encrypt(Marshal.dump(value))
chuyển thành base64 chuỗi đã được mã hóa. Khi muốn giải mã thì chúng ta chỉ cần làm ngược lại theo trình tự đã làm.
Công việc tiếp theo là đến model Staff.
class Staff < ApplicationRecord
serialize :name, EncryptedCoder.new
serialize :email, EncryptedCoder.new
serialize :staff_code, EncryptedCoder.new
end
Trong class Staff chúng ta chỉ cần khai báo serialize cho các thuộc tính cần được mã hóa là name, email và staff_code. Đến đây mình xin giải thích vì sao phải dùng phương thức load và dump trong file encrypted_coder.rb
. Để dùng đượng serialize thì phải có phương thức load và dump để đọc và lưu dữ liệu vào database, nếu không có thì không dùng được.
Kết quả
staff = Staff.new name: "Nguyen Van A", staff_code: "123456", email: "nguyen.van.a@gmail.com"
=> #<Staff id: nil, email: "nguyen.van.a@gmail.com", staff_code: "123456", name: "Nguyen Van A">
staff.save
=> true
Staff.find_by email: "nguyen.van.a@gmail.com"
Staff Load (0.4ms) SELECT `staffs`.* FROM `staffs` WHERE `staffs`.`email` = '5h1uBwsCxoQz4G8zqb06sI69YgVyrAzQv5YMPHZaI546uj24DkW4Bi8Pp0F1\naF6O\n' LIMIT 1
=> #<Staff id: 94, email: "nguyen.van.a@gmail.com", staff_code: "123456", name: "Nguyen Van A" >
Đây là kết quả sau khi lưu vào database
SELECT name, email, staff_code FROM staffs;
Ưu điểm
Cách này đơn giản, dễ hiểu, dễ thực hiện. Có thể search được object
Nhược điểm
Có thể không chính xác với các trường ngày tháng. Cần phải chỉnh sửa lại.
Cám ơn các bạn đã đọc bài viết của mình. Chúc các bạn làm việc thật tốt.
All rights reserved