Triển Khai Kiểm Tra Lịch Sử Mật Khẩu Trong Devise Cho Hệ Thống Xác Thực An Toàn

Cơ Sở Triển Khai Tính Năng Lịch Sử Mật Khẩu

Devise là giải pháp xác thực tiêu chuẩn trong hệ sinh thái Ruby on Rails, nhưng thiếu tính năng kiểm tra lịch sử mật khẩu theo mặc định. Việc bổ sung chức năng này giúp ngăn người dùng tái sử dụng mật khẩu cũ, giảm thiểu rủi ro bảo mật khi mật khẩu bị rò rỉ hoặc tấn công brute-force.

Thiết Kế Cơ Sở Dữ Liệu

Tạo bảng lưu trữ lịch sử mật khẩu với cấu trúc tối ưu:

# db/migrate/add_password_audit_trail.rb
class AddPasswordAuditTrail < ActiveRecord::Migration[7.0]
  def change
    create_table :password_audits do |t|
      t.belongs_to :account, null: false, index: true
      t.string :hashed_value, null: false
      t.timestamp :archived_at, null: false
      t.index [:account_id, :archived_at], name: "idx_audit_by_account"
    end
  end
end

Định nghĩa model tương ứng:

# app/models/password_audit.rb
class PasswordAudit < ApplicationRecord
  belongs_to :account
  self.table_name = "password_audits"
end

Cơ Chế Theo Dõi Mật Khẩu

Thực hiện ghi nhận và kiểm tra mật khẩu trong model người dùng:

# app/models/account.rb
class Account < ApplicationRecord
  devise :database_authenticatable, :registerable, 
         :recoverable, :rememberable

  has_many :password_audits, dependent: :destroy
  PASSWORD_HISTORY_LIMIT = 5

  before_save :record_previous_password, if: :will_save_change_to_encrypted_password?
  validate :ensure_password_freshness, if: :password_changed?

  private

  def record_previous_password
    password_audits.create(
      hashed_value: encrypted_password_was,
      archived_at: Time.current
    )
    trim_audit_records
  end

  def trim_audit_records
    ordered = password_audits.order(archived_at: :desc)
    ordered.offset(PASSWORD_HISTORY_LIMIT).destroy_all
  end

  def ensure_password_freshness
    return if password.blank?
    
    new_hash = Devise::Encryptor.digest(Account, password)
    if password_audits.exists?(hashed_value: new_hash)
      errors.add(:password, "Mật khẩu đã được sử dụng gần đây. Vui lòng chọn mật khẩu mới.")
    end
  end
end

Tối Ưu Hóa Hiệu Năng

Thiết lập chỉ mục và giới hạn lịch sử để tránh vấn đề hiệu năng:

# config/initializers/devise_security.rb
Devise.setup do |config|
  config.password_history_depth = 5
end

Trong model, sử dụng cấu hình này để kiểm soát số lượng bản ghi:

def trim_audit_records
  max_records = Devise.password_history_depth || 5
  password_audits.order(archived_at: :desc).offset(max_records).destroy_all
end

Kiểm Thử Tính Năng

Đảm bảo tính năng hoạt động chính xác qua các test case:

# test/models/account_test.rb
require "test_helper"

class AccountTest < ActiveSupport::TestCase
  test "should reject recent passwords" do
    user = Account.create!(email: "test@example.com", password: "OldPass123!")
    
    user.update!(password: "NewPass456!")
    assert user.valid?
    
    user.password = "OldPass123!"
    assert_not user.valid?
    assert_includes user.errors[:password], "Mật khẩu đã được sử dụng gần đây"
  end
end

Xử Lý Ngoại Lệ

Đảm bảo tương thích với chức năng reset mật khẩu:

def reset_password_token=(token)
  super
  @password_reset_triggered = true
end

def update_password(new_password, new_password_confirmation)
  result = super
  record_previous_password if result && @password_reset_triggered
  result
end

Thẻ: Devise Rails security Password policy authentication Ruby on Rails

Đăng vào ngày 4 tháng 6 lúc 03:20