Một giải pháp có thể (tôi không chịu trách nhiệm về bất kỳ sự phá hủy):
Khi mã hóa dữ liệu nhạy cảm, không sử dụng mật khẩu của người sử dụng như chìa khóa. Thay vào đó, lấy được khóa từ mật khẩu của người dùng (tốt nhất là sử dụng thuật toán chuẩn như PBKDF2). Chỉ trong trường hợp người dùng quên mật khẩu của họ, bạn có thể giữ một bản sao của khóa dẫn xuất này (được mã hóa bằng một khóa khác có nguồn gốc từ câu trả lời của người dùng) của người dùng. Nếu người dùng quên mật khẩu của họ, họ có thể trả lời câu hỏi bảo mật của họ. Chỉ có câu trả lời đúng sẽ giải mã mật khẩu ban đầu khóa (không phải mật khẩu ban đầu). Điều này cho bạn cơ hội để mã hóa lại thông tin nhạy cảm.
Tôi sẽ chứng minh bằng mã giả (Python-esque), nhưng trước tiên hãy xem bảng có thể cho người dùng. Đừng để bị cuốn vào các cột chỉ được nêu ra, họ sẽ trở nên rõ ràng sớm ...
CREATE TABLE USERS
(
user_name VARCHAR,
-- ... lots of other, useful columns ...
password_key_iterations NUMBER,
password_key_salt BINARY,
password_key_iv BINARY,
encrypted_password_key BINARY,
question VARCHAR,
answer_key_iterations NUMBER,
answer_key_salt BINARY
)
Khi nói đến thời gian để đăng ký một người sử dụng, họ phải cung cấp một câu hỏi và trả lời:
def register_user(user_name, password, question, answer):
user = User()
# The question is simply stored for later use
user.question = question
# The password secret key is derived from the user's password
user.password_key_iterations = generate_random_number(from=1000, to=2000)
user.password_key_salt = generate_random_salt()
password_key = derive_key(password, iterations=user.password_key_iterations, salt=user.password_key_salt)
# The answer secret key is derived from the answer to the user's security question
user.answer_key_iterations = generate_random_number(from=1000, to=2000)
user.answer_key_salt = generate_random_salt()
answer_key = derive_key(answer, iterations=user.answer_key_iterations, salt=user.answer_key_salt)
# The password secret key is encrypted using the key derived from the answer
user.password_key_iv = generate_random_iv()
user.encrypted_password_key = encrypt(password_key, key=answer_key, iv=user.password_key_iv)
database.insert_user(user)
Nếu người dùng quên mật khẩu của họ, hệ thống sẽ vẫn phải yêu cầu người dùng trả lời câu hỏi bảo mật của họ. Không thể khôi phục mật khẩu của chúng tôi, nhưng khóa có nguồn gốc từ mật khẩu có thể được. Điều này cho phép hệ thống để tái mã hóa các thông tin nhạy cảm bằng cách sử dụng mật khẩu mới:
def reset_password(user_name, answer, new_password):
user = database.rerieve_user(user_name)
answer_key = derive_key(answer, iterations=user.answer_key_iterations, salt=user.answer_key_salt)
# The answer key decrypts the old password key
old_password_key = decrypt(user.encrypted_password_key, key=answer_key, iv=user.password_key_iv)
# TODO: Decrypt sensitive data using the old password key
new_password_key = derive_key(new_password, iterations=user.password_key_iterations, salt=user.password_key_salt)
# TODO: Re-encrypt sensitive data using the new password key
user.encrypted_password_key = encrypt(new_password_key, key=user.answer_key, iv=user.password_key_iv)
database.update_user(user)
Tất nhiên, có một số nguyên tắc mã hóa nói chung không rõ ràng nêu bật tại đây (chế độ mật mã, vv ...) mà là những trách nhiệm của người thực hiện để tự làm quen với.
Hy vọng điều này sẽ giúp ích một chút! :)
Cập nhật kê biếu không của bình luận Eadwacer của
Như Eadwacer nhận xét:
tôi sẽ tránh phát sinh các khóa trực tiếp từ mật khẩu (entropy hạn chế và thay đổi mật khẩu sẽ yêu cầu tái mã hóa tất cả các dữ liệu). Thay vào đó, hãy tạo một khóa ngẫu nhiên cho mỗi người dùng và sử dụng mật khẩu để mã hóa khóa. Bạn cũng sẽ mã hóa khóa bằng cách sử dụng khóa bắt nguồn từ các câu hỏi bảo mật.
Đây là một phiên bản sửa đổi của giải pháp tôi đưa lời khuyên tuyệt vời của mình vào xem xét:
CREATE TABLE USERS
(
user_name VARCHAR,
-- ... lots of other, useful columns ...
password_key_iterations NUMBER,
password_key_salt BINARY,
password_encrypted_data_key BINARY,
password_encrypted_data_key_iv BINARY,
question VARCHAR,
answer_key_iterations NUMBER,
answer_key_salt BINARY,
answer_encrypted_data_key BINARY,
answer_encrypted_data_key_iv BINARY,
)
Sau đó, bạn sẽ đăng ký người dùng như sau:
def register_user(user_name, password, question, answer):
user = User()
# The question is simply stored for later use
user.question = question
# The randomly-generated data key will ultimately encrypt our sensitive data
data_key = generate_random_key()
# The password key is derived from the password
user.password_key_iterations = generate_random_number(from=1000, to=2000)
user.password_key_salt = generate_random_salt()
password_key = derive_key(password, iterations=user.password_key_iterations, salt=user.password_key_salt)
# The answer key is derived from the answer
user.answer_key_iterations = generate_random_number(from=1000, to=2000)
user.answer_key_salt = generate_random_salt()
answer_key = derive_key(answer, iterations=user.answer_key_iterations, salt=user.answer_key_salt)
# The data key is encrypted using the password key
user.password_encrypted_data_key_iv = generate_random_iv()
user.password_encrypted_data_key = encrypt(data_key, key=password_key, iv=user.password_encrypted_data_key_iv)
# The data key is encrypted using the answer key
user.answer_encrypted_data_key_iv = generate_random_iv()
user.answer_encrypted_data_key = encrypt(data_key, key=answer_key, iv=user.answer_encrypted_data_key_iv)
database.insert_user(user)
Bây giờ, đặt lại mật khẩu của người dùng trông giống như sau:
def reset_password(user_name, answer, new_password):
user = database.rerieve_user(user_name)
answer_key = derive_key(answer, iterations=user.answer_key_iterations, salt=user.answer_key_salt)
# The answer key decrypts the data key
data_key = decrypt(user.answer_encrypted_data_key, key=answer_key, iv=user.answer_encrypted_data_key_iv)
# Instead of re-encrypting all the sensitive data, we simply re-encrypt the password key
new_password_key = derive_key(new_password, iterations=user.password_key_iterations, salt=user.password_key_salt)
user.password_encrypted_data_key = encrypt(data_key, key=new_password_key, iv=user.password_encrypted_data_key_iv)
database.update_user(user)
Hy vọng đầu tôi vẫn hoạt động rõ ràng đêm nay ...
+1: Câu hỏi hay. Thật là một tình huống khủng khiếp ... –