Tìm hiểu một vài khái niệm liên quan đến "mã hóa"

Cùng ăn mừng sự kiện gỡ bỏ quy định bắt buộc phải viết report trên Viblo, cùng hướng tới một tương lai xa xăm khi người người làm theo năng lực, hưởng theo nhu cầu và hàng tháng không còn phải lựa chọn giữa 2 ngày lương hay report, chúng ta cùng làm một bài viết nhỏ trên Viblo =)). Xét theo quy mô cũng như tính chất + nội dung bài viết, có lẽ nên xếp bài viết này vào trong series P.E.N.I.S của tác giả ( Programmer's Extremely Neglected but Interesting Subjects ). Thích thì có thể các bạn có thể xem thêm các bài viết khác cùng series :

Có lẽ vào một ngày đẹp trời nào đó, mình sẽ phải ngồi gom hết đám này lại thành một cái series cho nó tử tế. Hoặc có lẽ phải chỉnh sửa, cập nhật lại mấy bài viết cũ, đa số sau một thời gian nhìn lại đều phải thốt lên "wtf, ngày xưa mình viết cái beep gì thế này". Nhưng nói chung là chuyện ngày mai chớ để hôm nay, cái gì chưa muốn làm luôn thì cứ để sau đi. Ngày hôm nay, chúng ta hãy cùng nhau đi vào tìm hiểu 4 khái niệm mà nhắc đến mã hóa, đôi khi chúng ta thường rất hay nhầm lẫn : Encoding - Encryption - Hashing - Obfuscation, Chúng là gì, dùng làm gì, khi nào dùng ? Dám cá rằng 99% người đọc bài viết này sẽ cảm thấy ít nhất 3/4 khái niệm trên rất quen thuộc, hẳn bạn đã gặp chúng không ít lần. Và cũng dám cá luôn rằng 99% trong số các bạn chưa chắc đã trả lời được ba câu hỏi trên, để có thể phân biệt được một cách rõ ràng giữa các khái niệm ( Ai biết rồi mời ra khỏi bài viết giùm, để giữ gìn tính đúng đắn cho con số thống kê được nêu ra ). Đa số có lẽ đều nhớ mang máng, mấy khái niệm này có liên quan tới mã hóa bảo mật các kiểu, chứ cụ thể thì có lẽ hơi khó nhớ. Nếu bạn cảm thấy như thế thật, thì xin chúc mừng, chúng ta là đồng đội rồi đó =)).

Enconding

Về mặt định nghĩa mà nói, ta có thể đưa ra khái niệm sau về chuyện thế nào gọi là encoding

> Encoding là quá trình biến đổi dữ liệu sang một hệ biểu thị khác để sử dụng trong môi trường thiết bị hay hệ thống khác. Nội dung của phương pháp được sử dụng trong quá trình biến đổi này là công khai để tất cả đều có thể sử dụng. Dữ liệu sau khi đã qua encode có thể được đảo ngược lại quá trình, hoặc tiếp tục được sử dụng để encode sang hệ biểu thị khác.

Đọc nghe hơi rối rắm phải không. Một vài ví dụ về encoding mà ta thường xuyên sử dụng :

  • Đầu tiên là base64 encoding. Đây là một trong số những kiểu encode dùng để chuyển dữ liệu từ dạng mã nhị phân sang dạng text. Tưởng tượng như ta đang có nhu cầu gửi email một bức ảnh chẳng hạn. Vì email không thể truyền data dạng binary đi được rồi, nên ta cần phải encode base64 để chuyển nó sang dạng text
  • Hay một kịch bản khác thường hay gặp hơn, đó là url encoding . Như ta đã biết, url chỉ có thể chứa những kí tự trong bảng mã ASCII. Tuy nhiên, trong thực tế, các đường dẫn url của ta thường xuyên cần phải chứa những kí tự đặc biệt nằm ngoài bảng mã này, thế nên, ta cần sử dụng encoding để chuyển nó về định dạng chấp nhận được. Cụ thể, các thuật toán url encode, thường sẽ thay thế các kí tự đặc biệt bằng một chuỗi bắt đầu với % gắn với 2 giá trị số hex

Tóm lại , ta có thể rút ra một vài điểm cần lưu ý về encoding :

  • Encode liên quan đến kịch bản trao đổi dữ liệu giữa các hệ thống hay môi trường khác nhau
  • Mục đích của encode là để đảm bảo khả năng sử dụng (usability) của dữ liệu
  • Từ điểm đầu tiên, ta có thể biết được encoding không liên quan đến sự bảo mật của dữ liệu
  • Từ nhu cầu trao đổi dữ liệu, nên các phép encode đều có thể đảo ngượcthuật toán encode đều được công khai
  • Đầu vào của encode không nhất thiết phải là text

Encryption

Đây mới thực sự là mã hóa. Encryption là quá trình biến đổi dữ liệu ( giống encode ) mà mục đích của nó nhằm đảm bảo dữ liệu là bí mật , và chỉ người mình muốn mới có thể hiểu được dữ liệu mà mình truyền tải. Để làm được điều này, thường cần sự kết hợp giữa text đầu vào, một chìa khóa bí mật, và thuật toán trộn để tạo thành chuỗi được mã hóa. Và chỉ những ai có được chuỗi đã qua mã hóa, thuật toán dùng để mã hóa, và chuỗi chìa khóa mới có khả năng đảo ngược quá trình để lấy được chuỗi ban đầu. Một vài ví dụ về encrption, bạn có thể xem thêm tại : Blowfish, RSA

Tóm lại, ta có thể rút ra đặc điểm nhận dạng của encrption :

  • Encyption liên quan đến kịch bản truyền tải dữ liệu giữa 2 hay nhiều đối tương
  • Mục đích của encryption là tính bảo mật của dữ liệu
  • Các thuật toán encryption được sử dụng là bí mật, chỉ có người gửi và người nhận được quyền biết
  • Để dữ liệu ban đầu có thể đến được tay người nhận, các quá trình encryption là có thể đảo ngược

Hashing

Hashing cũng tương tự như các khái niệm trên, nhận một giá trị đầu vào, và qua thuật toán biến đổi, cho một giá trị đầu ra. Tương tự như encryption, muốn thực hiện một phép hashing , ta cần 3 yếu tố đầu vào : chuỗi input ta muốn hash, thuật toán dùng để hash, và chuỗi secret key. Thế nhưng , mục đích của phép hash là nhằm đảm bảo tính toàn vẹn của dữ liệu, nghĩa là với input thay đổi, luôn luôn cho ta một output thay đổi. Nhưng khác với encryption, hashing là một quá trình không thể đảo ngược. Kể cả khi bạn có chuỗi output, secret key và thuật toán, bạn cũng không thể lấy lại được chuỗi input. Với đặc điểm này , phép hashing thường được dùng trong các quá trình xác thực, để nhận biết xem, dữ liệu nhận được và dữ liệu truyền đi có bị thay đổi gì hay không. Cụ thể, người gửi và người nhận cùng thống nhất với nhau một secret key. Khi gửi, người gửi hashing dữ liệu gửi tạo thành một signature gửi đi kèm với dữ liệu. Khi nhận, người nhận hashing dữ liệu nhận được, và so sánh với signature người nhận gửi kèm. Nếu không có gì khác biệt, dữ liệu nhận được đảm bảo là toàn vẹn. Nếu bạn làm việc với Java Web Token, hẳn sẽ nhận ra kịch bản này rất quen thuộc. Một vài thuật toán hashing thông dụng như SHA-3 , MD5

Qua đây, ta có thể rút ra một vài đặc điểm của hashing:

  • Hashing liên quan đến vấn đều xác thực dữ liệu
  • Mục đích của hashing là Tính toàn vẹn của dữ liệu
  • Các thuật toán hashing được sử dụng là công khai, mọi người đều có thể biết được
  • Hashing là một quá trình không thể đảo ngược , người nhận không thể qua chuỗi output để tìm ra được chuỗi input.

Obfuscation

Kết quả cuối cùng của Obfuscation, khái niệm cuối cùng mà mình muốn nói đến hôm nay, sẽ kiểu như hình trên. Khác với các khái niệm trước, mục tiêu mà chúng nhắm đến thường không phân biệt là người hay chương trình ( có đọc được dữ liệu này không, có xem trộm được dữ liệu này không, có đảm bảo được dữ liệu này là hàng xịn không ), Obfuscation chỉ có ý nghĩa với con người. Đây là một quá trình làm cho dữ liệu trở nên khó hiểu , khó đọc hơn, từ đó khiến chúng khó bị sao chép hay tấn công hơn. Kịch bản hay gặp nhất là khi ta cần bảo source code bị người dùng tiếp cận của mìn,như các file js chẳng hạn. Ví dụ bạn bật thử F12 lên, vào trong source của ngay trang viblo, sẽ thấy một file js rất lằng nhằng khó hiểu, đó chính là đã qua quá trình obfuscation rồi đó. Máy đọc vẫn hiểu, người đọc thì không . Tuy nhiên cần lưu ý rằng, quá trình này chỉ là một cản trở nhỏ, không phải là một biện pháp bảo đảm an toàn, bởi lẽ, rất dễ để đảo ngược quá trình này.

Tóm lại, đặc điểm nhận dạng của thằng này là :

  • Obfuscation nhằm đến mục tiêu ngăn ngừa (cản trở thì đúng hơn) con người hiểu được dữ liệu
  • Mục đích của nó là nhắm đến tính đọc hiểu ( readability ) của dữ liệu
  • Các phép toán thực hiện Obfuscating là công khai
  • Qúa trình này có thể đảo ngược một cách rất dễ dàng.
  • Đặc điểm riêng nhất của nó, đó là Obfuscation chỉ có ý nghĩa với con người. Chương trình có thể hiểu dữ liệu đã qua hoặc chưa qua obfuscation một cách không mấy khác biệt.