Giao thức trao chuyển Khóa đối xứng Needham - Schroeder.

Trong bài viết này, mình sẽ viết về 1 giao thức hỗ trợ trao chuyển Khóa đối xứng của Hệ thống mật mã đối xứng (Symmetric Key Cryptosystem) mà mình đã được Sư Phụ dạy trên lớp đại học năm 4 trong môn Cơ sở An toàn thông tin: giao thức Needham - Schroeder. Có thể nói rằng lúc học cái này, mình cũng như mấy thằng lớp mình có hiểu cái khỉ gió j đâu, có chăng là chỉ hiểu được 1 phần để làm bài thi cuối kỳ thôi. Mãi về sau lúc ngồi đọc lại quyển sách của Sư Phụ thì mình mới hiểu hết toàn bộ bản chất của giao thức.

Giao thức Needham - Schroeder dạng thô sơ.

Đây là giao thức phác thảo, chỉ bao gồm 3 bước, thể hiện đầy đủ quá trình trao chuyển khóa phiên. Cũng là ý tưởng ban đầu gợi mở về giao thức Needham - Schroeder đầy đủ.
  • Alice ↦ Cathy : {Yêu cầu tạo khóa phiên để liên lạc với Bob}
  • Cathy ↦ Alice: {kS}kAC || {kS}kBC
  • Alice ↦ Bob: {kS}kBC
Trong giao thức thô sơ trên, khóa phiên sẽ được sinh ngẫu nhiên bởi trung gian Cathy là người mà cả Alice và Bob đều biết; sau đó sẽ được chuyển dần về cả 2 phía là Alice và Bob. Do đó, khi Alice nhận được {kS}kAC ở bước 2, Alice có thể giải mã để lấy ra klà khóa phiên hiện tại. Sau đó, thông tin còn lại là {kS}kBC sẽ được chuyển cho Bob. Bob cũng biết Cathy nên đương nhiên Bob cũng sẽ giải mã để lấy ra kđược. Vậy là cả Alice và Bob đều đã có khóa phiên kS

Hoặc cũng có thể hình dung trực quan hơn như Sư Phụ mình dạy; đó là tại bước 2, Cathy sẽ chuyển cho Alice 2 cái hộp bị khóa; 1 hộp dành cho Alice, hộp còn lại dành cho Bob. Alice sẽ mở hộp của mình ra để lấy khóa phiên kS; hộp còn lại thì Alice sẽ chuyển cho Bob mở.

Vậy, có vấn đề j xảy ra ở đây ko? Đương nhiên là có rồi! Có thể liệt kê ra dăm ba vấn đề thô sơ thế này:
  • Ở bước thứ 2, Alice lấy j để chắc chắn rằng 2 cái hộp kia là do Cathy chuyển đến? Nhỡ đâu là do 1 thằng AntiCathy thì sao? Tiếp tay cho giặc sao?
  • Ở bước thứ 3, Bob cũng sẽ gặp tình trạng tương tự như vậy. Nhỡ đâu ko phải do Alice chuyển, mà là AntiAlice thì sao?
  • Có 1 thanh niên Cường nào đó xuất hiện chen ngang vào cuộc tình Alice và Bob, thằng Cường đó trở thành "Man in the middle" loại 1. Ngay trong bước 1 của giao thức thô sơ, khi mà Alice gửi tới Cathy yêu cầu kết nối với Bob, thì thằng Cường đó lại bắt lấy các packet do Alice gửi cho Cathy, rồi tự thằng Cường đó mạo danh Alice, gửi cho Cathy và yêu cầu rằng Alice muốn kết nối với Cường (chứ ko phải với Bob). Thế là Bob bị đá ra khỏi cuộc chơi.
  • Nên nhớ rằng bất cứ packet nào trong mạng Internet cũng đều có thể bị tóm bởi hacker! Vậy nếu thằng Cường đó bắt được cả 2 hộp, dù ko có khóa mở ra nhưng vẫn có thể "Replay attack" bằng cách thực hiện bước 3 của giao thức thô sơ! Fine, Bob vẫn phải xử lý packet được phát lại đó thôi. Vậy là thằng Cường đó đã trở thành "Man in the middle" loại 2 thành công. Nó sẽ bắt qua bắt lại các packet chứa bản mã. Càng nhiều bản mã, nếu thuật toán mã hóa ko tốt, thì càng có nhiều khả năng giải mã!
  • Rộng hơn 1 tí, nếu thằng Cường đó ko thèm giải mã, mà nó vô cùng mất dạy, nó thực hiện DoS/DDoS bằng cách kết hợp Replay attack như ở ý trên, vậy thì Bob sớm muộn cũng rơi vào trạng thái Denial of Service rồi còn j!
  • Vân vân và mây mây ...
Lưu ý rằng dù giao thức thô sơ trên tuy rất thô sơ, nhưng nó cũng có 1 lưu ý quan trọng mà các giao thức nâng cấp về sau cần phải tuân theo, đó là ko cho Bob và Cathy liên lạc trực tiếp với nhau! Vì sao vậy? Đương nhiên là để ngăn chặn "Man in the middle" loại 1 rồi! Loại 1 mới đúng bản chất "Man in the middle", còn loại 2 ở đây là do mình tự đặt tên vậy thôi, chứ bản chất nó chỉ là DoS/DDoS kết hợp Replay. Do vậy, giao thức Needham - Schroeder dạng đầy đủ được ra đời để ngăn chặn Replay attack.

Giao thức Needham - Schroeder dạng đầy đủ.

Từ những vấn đề nghiệm trọng xuất hiện ở giao thức dạng thô sơ, người ta đã cải tiến giao thức Needham - Schroeder lên 1 cảnh giới cao hơn, gọi là dạng đầy đủ (vì nó có 5 bước) như sau:
  • Alice ↦ Cathy : Alice || Bob || r1
  • Cathy ↦ Alice: {Alice || Bob || r1 || k|| {Alice || kS}kBC}kAC
  • Alice ↦ Bob: {Alice || kS}kBC
  • Bob ↦ Alice: {r2}kS
  • Alice ↦ Bob: {r2 - 1}kS
Ở bước 2 của giao thức đầy đủ, Cathy sẽ tạo ra 1 hộp to và 1 hộp nhỏ. Alice sẽ nhận được hộp to và có thể mở khóa hộp to này. Sau khi mở khóa xong thì sẽ nhận được hộp nhỏ {Alice || kS}kBC và gửi hộp nhỏ này cho Bob ở bước 3. Bob đương nhiên sẽ có chìa để mở hộp nhỏ này.

Các giá trị r1 và rxuất hiện trong giao thức đầy đủ trên thực chất là các giá trị ngẫu nhiên được sử dụng theo cơ chế Thách thức - Đáp ứng (Challenge - Response protocol). Mục đích là để các bên có thể xác thực được lẫn nhau. Ví dụ như với giá trị r2 sẽ cho phép Bob có thể thách thức Alice rằng "tao có khóa phiên kS đây, tao đã mã hóa số r2 bằng kS". Do đó, nếu có 1 thằng Cường nào đó mạo danh Alice, chỉ đơn thuần nghe trộm và Replay attack thì sẽ ko thể vượt qua challenge này được; vì các giá trị này được sinh ngẫu nhiên và ko bao giờ lặp lại.

Nói vậy nghe cho xôm thôi, chứ thực chất việc sinh ngẫu nhiên ở đây ko hề ngẫu nhiên như các bạn nghĩ đâu! Mình còn nhớ Sư Phụ mình đã nói rằng "các giá trị ngẫu nhiên chỉ xuất hiện thực sự trong các hiện tượng vật lý, và được đi kèm với các đại lượng ngẫu nhiên như sóng ngẫu nhiên, xung ngẫu nhiên, ...! Còn trong máy tính, một giá trị ngẫu nhiên được tạo ra thì ko bao giờ là ngẫu nhiên; nó chỉ là giả ngẫu nhiên mà thôi. Function tạo ra các giá trị ngẫu nhiên cũng đơn thuần được viết ra bởi các lập trình viên dựa trên các thuật toán tạo số ngẫu nhiên."

Well, vậy giao thức đầy đủ trên có thể bị tấn công như nào vậy? Câu trả lời đương nhiên vẫn là Replay attack rồi? What the hell? Sao bên trên bảo là dạng đầy đủ ngăn chặn đc Replay attack cơ mà, sao giờ lại thành ra vẫn bị Replay là sao? Câu trả lời nằm ở đây.

klà 1 khóa phiên, và chỉ có hiệu lực trong phiên làm việc hiện tại; khi đã kết thúc phiên làm việc, thì ksẽ mất hiệu lực và vô giá trị cho phiên làm việc tiếp theo. Nhưng sẽ có trường hợp có người lại hiểu rằng "ko còn hiệu lực nữa thì vất đi thoải mái mà quên hủy đi"; thành ra 1 Eve mất dạy nào đó, đã tóm được toàn bộ phiên trò chuyện lúc trước, rồi sau lại tóm đc kS, nó sẽ mạo danh Alice, thực hiện Replay attack ở bước thứ 3 của giao thức đầy đủ. Khi đã có krồi, Eve này chắc chắn sẽ đáp ứng được thách thức mà Bob đặt ra ở bước 4 của giao thức!
  • Eve ↦ Bob: {Alice || kS}kBC
  • Bob ↦ Eve: {r2}kS
  • Eve ↦ Bob: {r2 - 1}kS
Có kS làm bố, Eve chắc chắn sẽ giải mã để lấy ra được r2 rồi đáp ứng lại thách thức của Bob ở bước 5 vô cùng ez!

Vấn đề này nghe có vẻ củ chuối, nhưng thực chất thì "người sử dụng", họ làm sao có đủ kinh nghiệm mà quan tâm đến việc này như các chuyên gia An toàn thông tin được! Họ có nhiều việc phải làm hơn là nhớ hết cả việc phải hủy khóa phiên. Đôi khi là do họ quên vậy. Nên "người sử dụng" là thành phần vô cùng khó chiều! Vậy chẳng lẽ các chuyên gia An toàn thông tin chỉ ngồi chạy đua vs hacker mà ko có cách nào để ngăn ngừa sự "đãng trí" của người dùng? Đương nhiên là có rồi, và điều đó được thể hiện trong giao thức Needham - Schroeder dạng cải tiến sau đây.

Giao thức Needham - Schroeder dạng cải tiến.

Với vấn đề củ chuối được đề cập ngay bên trên, người ta đã thực hiện cải tiến giao thức Needham - Schroeder lên 1 cảnh giới cao hơn, đó là kết hợp sử dụng thêm nhãn thời gian (timestamp) để hạn chế khả năng phát lại ngay cả trong trường hợp khóa phiên kS cũ bị rơi vào tay Eve. Cụ thể với T là timestamp tại thời điểm khởi tạo phiên kết nối: 
  • Alice ↦ Cathy : Alice || Bob || r1
  • Cathy ↦ Alice: {Alice || Bob || r1 || k|| {Alice || T || kS}kBC}kAC
  • Alice ↦ Bob: {Alice || T || kS}kBC
  • Bob ↦ Alice: {r2}kS
  • Alice ↦ Bob: {r2 - 1}kS
Ta có thể thấy rằng, trong bước 2 của giao thức cải tiến, Cathy đã đặt thêm timestamp vào trong chiếc hộp con. Tại bước 3, Alice sẽ chuyển hộp con đó cho Bob. Bob sẽ mở ra và đối chiếu với đồng hồ hiện tại của mình. Nếu sự chênh lệch thời gian vượt quá ngưỡng cho phép, Bob sẽ hiểu rằng đã có kẻ Replay attack và sẽ reject.

Hồi học về giao thức này trên lớp, Sư Phụ có đố lớp mình 1 câu để cộng điểm cuối kỳ, đó là "ngoài giải pháp sử dụng timestamp để tránh Replay attack ra, các em thử suy nghĩ xem còn giải pháp nào khác có thể áp dụng được không." Và kết quả cũng ko ngoài mọi lần khác, cả lớp mình chẳng thằng nào nghĩ ra hay tìm ra được giải pháp nào khác cả. Bản thân mình khi tiếp xúc và làm việc trực tiếp tại môi trường doanh nghiệp bên ngoài thì thấy họ cũng chỉ biết sử dụng giải pháp timestamp để ngăn chặn Replay attack thôi, chứ chưa thấy có giải pháp nào khác! Vậy mà hôm trước ngồi tâm sự với Sư Phụ, mình bạo gan hỏi Sư Phụ rằng liệu còn giải pháp nào khác ko; thì Sư Phụ trả lời đầy thách thức rằng "đương nhiên là có, nhưng cần phải động não nhiều lên, em thử nghĩ xem!"

Trời ạ, và bây giờ đến khi ngồi viết topic này, mình vẫn còn đang nghĩ xem có giải pháp khỉ gió j khác ko! Chứ chắc ko thể nào lại là giải pháp sử dụng các giá trị tăng dần (seq value) chứ nhỉ! Các giá trị này cứ coi như sẽ có kiểu dữ liệu lớn tầm 8 byte đi, thì tăng mãi tăng mãi rồi cũng gặp sẽ gặp 1 trong 2 hướng. Hướng 1 là tràn bộ đếm như sự cố y2k huyền thoại hồi mình còn thò lò mũi xanh; nhưng chắc giờ ko thằng dev nào ngu đến mức còn để xảy ra lỗi này đâu. Hướng thứ 2 là nối vòng về start value. Vậy thì cũng chẳng có j vượt trội hơn việc dùng timestamp?!? @@

Nhận xét

Bài đăng phổ biến từ blog này

Trên con đường tu đạo luôn cực kỳ theo đuổi!

C++ Con trỏ (Pointer) toàn thư: Phần 4: Con trỏ "đa cấp". Đánh nhau bằng con trỏ.

Vừa ngộ ra sự vi diệu của Padding Oracle Attack thì được tin crush hồi lớp 12 sắp cưới.