ToolHub
View All Posts

URL Encoding Giải Thích Chi Tiết: Percent Encoding Là Gì

Mỗi lần bạn nhấp vào liên kết, gửi biểu mẫu hoặc nhập URL, trình duyệt của bạn đang xử lý URL encoding ở hậu trường. Những chuỗi bí ẩn gồm dấu phần trăm và chữ số hex mà bạn nhìn thấy trong URL không phải là ngẫu nhiên; chúng là một cơ chế được thiết kế cẩn thận giúp internet hoạt động đáng tin cậy. Hiểu URL encoding rất quan trọng đối với lập trình viên web, nhà thiết kế API và bất kỳ ai làm việc với công nghệ web. Hướng dẫn này giải thích URL encoding là gì, tại sao nó tồn tại, cách nó hoạt động và những ảnh hưởng bảo mật bạn cần biết.

URL Encoding Là Gì?

URL encoding, tên chính thức là percent encoding, là một cơ chế được định nghĩa trong RFC 3986 chuyển đổi ký tự thành định dạng có thể truyền an toàn trong Uniform Resource Identifier (URI). Đặc tả URL chỉ cho phép một tập con ký tự ASCII xuất hiện trực tiếp trong URL. Bất kỳ ký tự nào không nằm trong tập hợp được phép này phải được mã hóa thành dấu phần trăm (%) theo sau là hai chữ số hex, biểu diễn giá trị byte của ký tự đó.

< trở thành %3C, vì mã ASCII của < là 60, hex là 3C.

Tại Sao Cần URL Encoding

URL có cú pháp cụ thể sử dụng một số ký tự làm dấu phân cách. Dấu hỏi ? phân tách đường dẫn với chuỗi truy vấn. Ký hiệu & phân tách các tham số truy vấn. Dấu bằng = phân tách tên và giá trị tham số. Dấu gạch chéo / phân tách các phân đoạn đường dẫn. Nếu các ký tự này xuất hiện trong dữ liệu được truyền, chúng sẽ bị hiểu nhầm là cấu trúc URL thay vì nội dung.

Hãy xem xét điều gì xảy ra khi người dùng tìm kiếm "rock & roll" trên một trang web. Không mã hóa, URL sẽ là /search?q=rock & roll. Trình duyệt sẽ hiểu & là dấu phân cách tham số truy vấn, chia truy vấn thành hai tham số: q=rock và tham số thứ hai tên là roll (không có giá trị). URL encoding khắc phục điều này: /search?q=rock%20%26%20roll.

Cách Percent Encoding Hoạt Động

Quy trình mã hóa tuân theo thuật toán đơn giản được định nghĩa bởi đặc tả URI:

  1. Xác định ký tự không dành riêng: ký tự A-Z, a-z, 0-9, -, ., _ và ~ là không dành riêng. Chúng không bao giờ cần mã hóa và có thể xuất hiện trực tiếp trong URL.
  2. Xác định ký tự dành riêng: ký tự :, /, ?, #, [, ], @, !, $, &, ', (, ), *, +, ,, ; và = được dành riêng cho cú pháp URL. Chúng phải được mã hóa khi được sử dụng làm dữ liệu thay vì dấu phân cách.
  3. Mã hóa tất cả ký tự khác: bất kỳ ký tự nào không nằm trong tập hợp không dành riêng hoặc dành riêng phải được percent encoding. Điều này bao gồm dấu cách, ký tự điều khiển, ký tự không phải ASCII và bất kỳ ký tự nào ngoài phạm vi ASCII.

Quy Trình Mã Hóa Ký Tự Không Phải ASCII

Ký tự không phải ASCII (như chữ có dấu, ký tự CJK và emoji) yêu cầu bước bổ sung. Đầu tiên, ký tự được chuyển đổi thành chuỗi byte UTF-8 của nó. Sau đó mỗi byte được mã hóa percent encoding riêng lẻ. Điều này có nghĩa là một ký tự đơn có thể tạo ra nhiều bộ ba percent encoding.

Ví dụ, ký hiệu euro (€) có chuỗi byte UTF-8 là E2 82 AC. Sau khi URL encoding, nó trở thành %E2%82%AC. Ký tự tiếng Việt có dấu "ế" có chuỗi UTF-8 là E1 BA BF, tạo ra %E1%BA%BF. Emoji 😀 (mặt cười) có chuỗi byte UTF-8 4 byte, được mã hóa thành %F0%9F%98%80.

Các Ký Tự Được Mã Hóa Phổ Biến

Bảng dưới đây hiển thị các ký tự URL encoding phổ biến nhất:

Ký TựMã HóaMã ASCIILý Do
Dấu Cách%2032 (0x20)Không được phép trong URL
!%2133 (0x21)Dành riêng (sub-delimiter)
#%2335 (0x23)Dành riêng (dấu phân cách fragment)
$%2436 (0x24)Dành riêng (sub-delimiter)
&%2638 (0x26)Dành riêng (dấu phân cách truy vấn)
'%2739 (0x27)Dành riêng (sub-delimiter)
(%2840 (0x28)Dành riêng (sub-delimiter)
)%2941 (0x29)Dành riêng (sub-delimiter)
+%2B43 (0x2B)Dành riêng (dấu cách trong truy vấn)
,%2C44 (0x2C)Dành riêng (sub-delimiter)
/%2F47 (0x2F)Dành riêng (dấu phân cách đường dẫn)
:%3A58 (0x3A)Dành riêng (dấu phân cách giao thức)
;%3B59 (0x3B)Dành riêng (dấu phân cách tham số)
=%3D61 (0x3D)Dành riêng (dấu phân cách giá trị)
?%3F63 (0x3F)Dành riêng (dấu phân cách truy vấn)
@%4064 (0x40)Dành riêng (dấu phân cách ủy quyền)
[%5B91 (0x5B)Dành riêng (IPv6 literal)
]%5D93 (0x5D)Dành riêng (IPv6 literal)

URL Encoding và HTML Encoding

URL encoding và HTML entity encoding thường bị nhầm lẫn, nhưng chúng phục vụ các mục đích hoàn toàn khác nhau và hoạt động trong các ngữ cảnh khác nhau.

URL Encoding

URL encoding chuyển đổi ký tự thành định dạng %XX để truyền an toàn trong URL. Nó được quy định bởi RFC 3986 và được áp dụng cho các thành phần URL như đường dẫn, chuỗi truy vấn và fragment.

HTML Encoding

HTML encoding chuyển đổi ký tự thành tham chiếu thực thể như &, < và > để hiển thị an toàn trong tài liệu HTML. Nó ngăn trình duyệt hiểu nội dung là đánh dấu HTML. HTML encoding được quy định bởi đặc tả HTML.

Sự Khác Biệt Chính

Khía CạnhURL EncodingHTML Encoding
Ngữ CảnhURL và URITài Liệu HTML
Định Dạng%XX (dấu phần trăm + hex)&tên; hoặc &#NNN;
<%3C<
Ví Dụ của &%26&
Ví Dụ của "%22"
Mục ĐíchTruyền URL an toànNgăn HTML injection
Đặc TảRFC 3986HTML Living Standard

(HTML encoding ký hiệu &). Cả hai đều hợp lệ, nhưng URL encoding ký hiệu & là cách làm đúng hơn vì nó bảo toàn ý nghĩa dự định của dữ liệu.

URL Encoding Trong Các Ngôn Ngữ Lập Trình Khác Nhau

Mỗi ngôn ngữ lập trình chính cung cấp các hàm tích hợp cho URL encoding và decoding. Tuy nhiên, hành vi chính xác khác nhau và hiểu sự khác biệt là rất quan trọng để tránh lỗi.

JavaScript

JavaScript cung cấp ba hàm mã hóa, mỗi hàm có hành vi khác nhau:

// encodeURI - encodes a complete URL
// Preserves: :, /, ?, #, &, =, +, @, ;, ,, !, ~, *, ', (, )
const url = encodeURI("https://example.com/search?q=hello world");
// Result: "https://example.com/search?q=hello%20world"

// encodeURIComponent - encodes a URL component
// Encodes ALL special characters including URL delimiters
const param = encodeURIComponent("price=100&discount=20");
// Result: "price%3D100%26discount%3D20"

// Never use escape() - it is deprecated
// It does not handle Unicode correctly

Sự khác biệt chính là encodeURI giữ nguyên các ký tự cấu trúc URL, trong khi encodeURIComponent mã hóa mọi thứ. Sử dụng encodeURI khi bạn có URL đầy đủ, encodeURIComponent khi mã hóa giá trị tham số riêng lẻ.

Python

from urllib.parse import quote, quote_plus, urlencode

# quote - standard URL encoding (spaces as %20)
encoded = quote("hello world&more")
# Result: "hello%20world%26more"

# quote_plus - spaces become + instead of %20
encoded_plus = quote_plus("hello world")
# Result: "hello+world"

# urlencode - encodes a dictionary as a query string
params = {"q": "hello world", "lang": "en"}
query = urlencode(params)
# Result: "q=hello+world&lang=en"

PHP

// urlencode - spaces become +
$encoded = urlencode("hello world&more");
// Result: "hello+world%26more"

// rawurlencode - RFC 3986 compliant (spaces as %20)
$raw = rawurlencode("hello world&more");
// Result: "hello%20world%26more"

Ký Tự Dấu Cách: %20 và +

Ký tự dấu cách có hai cách mã hóa phổ biến, hiểu khi nào sử dụng mỗi cách là quan trọng:

Sự khác biệt này quan trọng vì giải mã + thành dấu cách chỉ đúng trong ngữ cảnh dữ liệu application/x-www-form-urlencoded. Trong thành phần đường dẫn URL, + là dấu cộng theo nghĩa đen, không phải dấu cách. Hầu hết các framework phía server xử lý đúng cho chuỗi truy vấn, nhưng có thể gây ra lỗi tinh vi khi mã hóa đường dẫn hoặc sử dụng lược đồ URL tùy chỉnh.

Ảnh Hưởng Bảo Mật

URL encoding có những ảnh hưởng bảo mật quan trọng mà mọi lập trình viên web phải hiểu.

Tấn Công Mã Hóa Kép

Mã hóa kép xảy ra khi dữ liệu được URL encoding nhiều lần. Kẻ tấn công có thể gửi %2527, khi giải mã lần đầu trở thành %27, giải mã lần thứ hai trở thành dấu nháy đơn '. Nếu bộ lọc bảo mật chỉ kiểm tra lần giải mã đầu tiên, nó sẽ bỏ sót ký tự độc hại. Điều này có thể vượt qua xác thực đầu vào, bộ lọc Cross-Site Scripting (XSS) và phòng chống SQL injection.