12/08/2018, 14:53

Tại sao cần mã hóa mật khẩu ? Và các kiểu mã hóa cơ bản

Lời mở Gần đây trên mấy blog hay trang báo chúng ta có thể dễ đọc được tin vụ Lotte lộ tài khoản và mật khẩu người dùng và thấy bảo rất nguy hiểm vậy nguy hiểm ở mức nào và liệu người dùng đổi mật khẩu ở lotte thì còn có an toàn không?. Theo mình thì nguy hiểm vl (very lắm) luôn bởi lẽ thứ nhất ...

Lời mở

Gần đây trên mấy blog hay trang báo chúng ta có thể dễ đọc được tin vụ Lotte lộ tài khoản và mật khẩu người dùng và thấy bảo rất nguy hiểm vậy nguy hiểm ở mức nào và liệu người dùng đổi mật khẩu ở lotte thì còn có an toàn không?. Theo mình thì nguy hiểm vl (very lắm) luôn bởi lẽ thứ nhất là người dùng đã bị lộ thông tin cá nhân và có thể bị dùng thông tin đó cho mục đích ko hay nào đó như spam chẳng hạn. Nhưng nguy hiểm nhất vẫn là bị lộ mật khẩu vì thói quen người dùng thường dùng chung mật khẩu cho nhiều trang web do đó nếu lộ ở trang Lotte thì những đối tượng xấu có thể đơn giản chạy con crawler sang các trang khác với email/tài khoản + password trong đống dữ liệu đó và người dùng có thể mất nhiều thứ hơn.

OK nói đến đây thì chắc hẳn ai cũng biết để đảm bảo an toàn chúng ta cần mã hóa mật khẩu. Nếu bạn nào hay code Rails mà để ý khi chúng ta dùng gem Devise để đăng nhập thì trong db sẽ không có trường mật khẩu mà thay vào đó là trường mật khẩu mã hóa (encrypted_password) với nội dung ví dụ "$2a$10$H3pCAbs2zO1lY5ZtOKe6a.cmBZ0f9axdaNakzvyjzyDpDwDtTdicO" và giả sử mật khẩu người dùng là abc123. Thì đây chính là đoạn mã Hash của mật khẩu abc123 đó. Khi người dùng đăng nhập lại thì mật khẩu họ nhập vào sẽ bị mã hóa thành chuỗi kí tự như trên và so sánh với encrypted_password đã lưu trong db để xác thực mật khẩu đúng hoặc sai. Điều này đạt được là dựa vào đặc tính cơ bản của mã hóa hash này đó là tính 1 chiều ( là khả năng không bị dịch ngược đoạn encrypted_password thành password) và tính duy nhất tức là từ 1 đoạn mã text đầu vào thì chỉ cho ra 1 đoạn mã output duy nhất. Ngoài ra còn có rất nhiều các đặc tính khác mà tôi sẽ nói ở sau đây, đồng thời tôi sẽ lý giải tại sao dùng hash mà không phải các thuật toán mã hóa khác

Các Định nghĩa cơ bản của mã hóa cho anh em dev

  1. Hỏi: mã hóa là gì?
  • Đáp: mã hóa là sử dụng các thuật toán để đảm bảo an toàn nội dung cho một đối tượng nào đó 2.Hỏi: Chọn lựa phương pháp mã hóa như nào là hợp lý?
  • Đáp: có thể đoan giản dựa vào 2 yếu tố :
    • lượng thông tin cần mã hóa
    • mục đích việc mã hóa:
      • tính bảo mật - Confidentiality?
      • Tính toàn vẹn - Integrity?
      • tính xác thực - Authenticity?
      • Chống chối từ (đại khái là đảm bảo thông tin gửi đi từ nguồn nào xác thực mà ko thể chối cãi) Non-repudiation? Deniability? (These two are opposites.)

Note: đừng bao giờ tự sáng tạo kiểu mã hóa của riêng mình khi bạn chưa nắm rõ

Như tôi đã nói ở trên các phương pháp mã hõa cần đảm bảo rất nhiều các yếu tố do đó chỉ nên viết phương pháp mã hóa khi bạn là chuyên gia và chứng minh là nó đủ tốt để dùng, còn không thì hãy cứ dùng những cái đã có sẵn vì nó đã đủ tốt và kiểm tra kĩ lưỡng để sử dụng rồi.

Sơ đồ chung của các pp mã hóa

Ta có thể thấy phần mã hóa gồm các mảng chính sau

  • Keyless Cryptography (0 keys)
    • Hash Functions
  • Secret-Key Cryptography (1 key)
    • Secret-Key Message Authentication
    • Secret-Key Encryption
    • Authenticated Secret-Key Encryption
  • Public-Key Cryptography (2 keys)
    • Shared Secret Key Agreement
    • Digital Signatures

Keyless Cryptography / mã hóa không dùng key

Đơn giản nhất trong mã hóa đó là dùng Hàm Hash với chỉ 1 input đầu vào và sẽ luôn trả ra 1 đoạn ký tự đầu ra với chiều dài cố định

hash("sha256", "");
// e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

hash("sha256", "The quick brown fox jumps over the lazy dog");
// d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592

và khi bạn thay đổi nội dung input dù là rất nhỏ thì kết quả ouput cũng sẽ thay đổi khác hoàn toàn

hash("sha256", "The quick brown fox jumps over the lazy cog");
// e4c4d8f3bf76b692de791a173e05321150f7a345b46484fe427f6acc7ecc81be

Các mã hóa thường dùng như sha256, MD5, BLAKE2 ... Ưu điểm của phương pháp này đó là tốc độ nhanh, mã hóa theo 1 chiều và không thể giải mã ngược lại. Tuy nhiên ở mã hóa MD5 tính bảo mật lại khá yếu do size oupt sinh ra bé nên người ta có thể tính toán ra 1 đoạn mã tương tự có thể sinh ra ouput giống với input gốc (các bạn tự liên hệ risk khi dùng MD5 mã hóa password lưu trong db và để lộ db).

Tác dụng của phương pháp này chủ yếu là dùng để xác thực tính toàn vẹn của file / mesage (khi bạn down load các file lớn trên mạng về máy thì thường có thêm 1 đoạn mã MD5 cái này là để bạn check lại mã MD5 sinh ra với file bạn down về và với dữ liệu gốc, nếu đoạn mã MD5 là giống nhau tức là file bạn down về giống với file gốc còn nếu sai thì tức là trong lúc tải file về bạn đã bị mất mát dữ liệu)

Secret Key Cryptography / Mã hóa bằng khóa bí mật

Đây là kiểu mã hóa mà input vào ngoài dữ liệu còn có thêm 1 đoạn mã key bí mật mà không bị public ra bên ngoài

Keyed Hash Functions

Đây là kiểu mã hóa dùng hàm hash nhưng có thêm 1 giá trị key nhằm tạo ra 1 message_authentication 1 trong phương pháp hay dùng đó là HMAC

hash_hmac("sha256", "The quick brown fox jumps over the lazy dog", "secret key");
// 4a513ac60b4f0253d95c2687fa104691c77c9ed77e884453c6a822b7b010d36f

hash_hmac("sha256", "The quick brown fox jumps over the lazy cog", "secret key");
// ed6b9bc9d64e4c923b2cc19c15fff329f343f30884935c10e617e0fe067adef1

hash_hmac("sha256", "The quick brown fox jumps over the lazy dog", "secret kez");
// 291579f3123c3126df04a57f78768b6290df93f979b86af25fecd98a9811da5a

hash_hmac("sha256", "The quick brown fox jumps over the lazy cog", "secret kez");
// 298bb0244ebc987810de3892384bb4663742a540db2b3a875f66b09d068d1f64

Phương pháp này thì được đánh giá an toàn hơn hash thường vì có key bí mật và chỉ ai có key thì mới có thể tính toán được đoạn mã xác thực sau khi mã hóa ngược lại đoạn nội dung và so sánh với mã xác thực đi kèm nhằm đảm bảo tính toàn vẹn của dữ liệu nhận được.

Secret Key Encryption - mã hóa key bí mật

Đơn giản mà nói thì đây là kiểu mã hóa dùng một key bí mật mà đảm bảo dùng key này ta có thể mã hóa dữ liệu (plain text) thành 1 đoạn mật mã (ciphertext) và đồng thời có thể khôi phục được duy nhất toàn bộ dữ liệu từ đoạn mã hóa kia. Tuy nhiên kiểu đơn giản (như kiểu ECB mode) như này thì sẽ không an toàn cho 1 số trường hợp ví dụ khi bạn mã hóa 1 đoạn (16bytes) các ký tự giống nhau thì đoạn mã hóa trả ra cũng sẽ bị lặp lại.

Do đó mã hõa dùng key bí mật hiện đại ngày nay ngoài 2 trường trên người ta đã thêm 1 trường mới là vecto khởi tạo IV (Initialization Vector) hoặc nonce (1 số ngẫu nhiên dùng 1 lần). Trong mã hóa này thì trường key sẽ cần bảo mật 2 trường IV, nonce thì sẽ lưu trong đoạn mã gửi đi.

Authenticated Secret-Key Encryption - Mã hóa key xác thực

Đây là phương pháp kết hợp 2 cách trên. Đó là luôn mã hóa bằng key kết hợp với việc dung 1 key khác để xác thực nội dung đoạn mã hõa thông qua tính toán ra giá trị MAC dựa vào giá trị đoạn mã hóa truyền vào

Việc mã hóa này đảm bảo tính an toàn đó là đoạn mã chỉ có thể được giải mã đúng khi dùng đúng key và tính toàn vẹn, xác thực của nội dung đoạn mã nhận được

Public Key Cryptography / Mã hóa bằng public key

Để mô tả 1 các đơn giản các bạn có thể xem ở hình sau

như các bạn thấy ở đây nó khác so với dùng 1 key bí mật ở phần trên, ở đây ta dùng tới 4 key Đầu tiên là 2 key bí mật của từng người mà ko được chia sẻ cho bất cứ ai (lưu ý ko được chia sẻ cho bất cứ ai) và 2 key public tương ứng với 2 key bí mật, 2 key public này được thông báo tới bất cứ ai

Với điều kiện dựa vào private key ta có thể tính toán ra được public key tuy nhiên chiều ngược lại là ko được ta không thể dựa vào public key để tính ra giá trị của private key, điều này đảm bảo tính bảo mật của private key là chỉ duy nhất người tạo ra key biết. Phương thức hoạt động của kiểu mã hóa này đó là 2 người sẽ trao đổi public key cho nhau.

Sau đó khi A muốn gửi dữ liệu sang bên B thì A sẽ gửi dữ liệu bị mã hóa bới public key của B (key đã được chia sẻ ở bước trước) sang B, sau đó B sẽ dùng private key của mình để giải mã dữ liệu. Tính bảo mật dữ liệu ở đây được đảm bào là nhờ dữ liệu sau khi được mã hóa bằng public key của B thì chỉ có dùng private key của B mới giải mã được, mà khóa private B được giữ bởi duy nhất B nên không ai có thẻ giải mã được đoạn mã hóa bằng publib key B.

Khi B gửi dữ liệu sang A thì cũng dùng các tương ứng là mã hóa dữ liệu bằng public key của A.

Ngoài ra phương pháp này còn có chữ kí số dựa vào 1 phần nội dung dữ liệu được mã hóa bằng private key, người nhận dữ liệu sẽ dùng public key của người gửi đã chia sẻ trước đó để kiểm tra lại chữ kí và so sánh với dữ liệu nhận được.

OK đây là nhưng kiến thức cơ bản, giờ chúng ta quay lại 1 chút về câu hỏi mở đầu, là việc mã hóa mật khẩu chúng ta sẽ tìm hiểu sâu hơn thông qua việc đặt vấn đề ngược cho phương pháp mã hóa mật khẩu mà hiện chúng ta đang sửa dụng Hỏi: Mã hóa mật khẩu sử dụng hàm hash (thường dùng bcrypt), vậy tại sao lại dùng hàm hash để mã hóa mà không phải dùng cách khác như dùng mã hóa bằng secret key, publickey ... Đáp: chúng ta chỉ sử dụng hàm hash cho mật khẩu mà không phải các phương pháp khác vì lý do cơ bản nhất đó là tính không thể dịch ngược điều đó đảm bảo thông tin mật khẩu chính xác bạn lưu trên máy chủ là khổng thể bị tra lại trên dữ liệu, cho dù là admin quản lý hoặc các hacker chiếm được quyền điều khiển hệ thống hay khi xảy ra sự cố như lộ db ra ngoài (như vụ Lotte ở phần mở đầu) thì các đối tượng xấu vẫn không thể nào biết được mật khẩu thực sự bạn sử dụng, từ đó hạn chế được các tổn thất chỉ ở 1 vùng dữ liệu bị chiếm dụng mà thôi.

Tuy nhiên hash password khác Hash cơ bản vì nó cần đảm bảo thêm nhiều điều kiện để đảm bảo tính an toàn

Lời kết

Đây chỉ là những kiến thức cơ bản của mã hóa, hi vọng là các bạn đã có thêm những kiến thức mới về bảo vệ an toàn thông tin

Tham khảo : https://paragonie.com/blog/2015/08/you-wouldnt-base64-a-password-cryptography-decoded

0