Tôi có nên thoát khỏi dấu gạch chéo /
Trong viết lạiđiều kiện
?
Bằng cách "thoát dấu gạch chéo", ý của bạn thực sự là "tôi có nên khớp dấu gạch chéo được mã hóa URL hay không?". Điều này hoàn toàn phụ thuộc vào yêu cầu HTTP được gửi đến máy chủ của bạn.
Nhưng tôi kiểm tra https://serverfault.com/a/968916/280923 và nó nói "Dấu gạch chéo (/
) không cần phải thoát". Vì vậy, tôi bối rối.
Câu hỏi/câu trả lời được liên kết không liên quan đến vấn đề hiện tại. Câu hỏi đó là xử lý các dấu gạch chéo ngược thoát trong các chỉ thị/regex của Apache, không phải các URL được mã hóa URL (hoặc %-encoded) mà bạn đang xử lý ở đây. Đây là hai loại phương pháp "thoát" rất khác nhau cho các mục đích khác nhau.
Những gì bạn đang xử lý là các URL được mã hóa %. Cách URL xuất hiện trong yêu cầu HTTP. Các phần khác nhau của URL (đặc biệt là "đường dẫn" và "chuỗi truy vấn") có các yêu cầu mã hóa khác nhau. Cho dù một nhân vật cụ thể nhu cầu được %-encoded phụ thuộc vào việc liệu nó có ý nghĩa đặc biệt trong ngữ cảnh đó hay không.
Như được định nghĩa trong RFC3986, dấu gạch chéo (/
) không nhất thiết phải được mã hóa % trong phần chuỗi truy vấn của URL. Tuy nhiên, các chức năng mã hóa URL (chẳng hạn như trong PHP và JavaScript) thường sẽ %-mã hóa ký tự này. (Tôi nghĩ điều này phần lớn là do lịch sử vì một số triển khai cũ được báo cáo là không xử lý chính xác dấu gạch chéo không được mã hóa - tham khảo RFC3986.)
Tuy nhiên, bất kể một nhân vật nhu cầu để được mã hóa URL (để phủ nhận ý nghĩa đặc biệt của nó), bất kỳ ký tự nào cũng có thể được %-mã hóa và ký tự này phải được xử lý giống như ký tự chữ (không được mã hóa).
Có hay không bạn cần phải phù hợp /
(đã giải mã) hoặc %2F
(được mã hóa) tùy thuộc vào việc ký tự đó có được %-mã hóa trong yêu cầu hay không.
Vấn đề của bạn là CHUỖI TRUY VẤN
biến máy chủ không được giải mã%, không giống như đường dẫn URL khớp với viết lại quy tắc
mẫu.
Nhưng... bạn có cần kiểm tra cả %-decoded /
và %-mã hóa %2F
? Có lẽ bạn đang liên tục liên kết đến chỉ một hoặc một URL (chuẩn) khác. Vì vậy, bất kỳ yêu cầu nào đối với URL không chính tắc sẽ phải được bên thứ ba nhập thủ công hoặc liên kết với lỗi. Bạn có nhận được yêu cầu cho cả hai? Hậu quả của việc không chuyển hướng URL không chính tắc là gì?
Nếu không, vâng, bạn sẽ cần kiểm tra cả hai (và có khả năng là tất cả các biến thể/trường hợp của). Mặc dù điều này có thể sẽ chỉ là /kiến thức cơ bản/
hoặc %2Fknowledgebase%2F
. Nhưng lưu ý rằng nó có thể %2F
(chữ hoa) hoặc %2f
(chữ thường). Chữ hoa chỉ là một quy ước. Phải kiểm tra mã hóa hỗn hợp, chẳng hạn như %2Fcơ sở tri thức/
nên rất hiếm. Nhưng đưa đến một thái cực thì điều này cũng giống như %2f%6b%6e%6f%77%6c%65%64%67%65%62%61%73%65%2f
. Việc bạn có cần xử lý tất cả các biến thể này hay không tùy thuộc vào khả năng nhận được yêu cầu như vậy và mức độ nghiêm trọng của quy tắc không khớp.
Vì vậy, để phù hợp với cả hai /kiến thức cơ bản/
và %2Fknowledgebase%2F
(không phân biệt chữ hoa chữ thường) bạn có thể sử dụng một cái gì đó như:
RewriteCond %{QUERY_STRING} ^rp=(/|%2[Ff])cơ sở tri thức(/|%2[Ff])
Bạn có thể tránh lớp ký tự [FF]
và sử dụng NC
cờ để làm cho toàn bộ so sánh không phân biệt chữ hoa chữ thường. Ví dụ:
RewriteCond %{QUERY_STRING} ^rp=(/|%2F)knowledgebase(/|%2F) [NC]
Trên Apache 2.4, bạn có thể sử dụng không thoát()
chức năng trong một biểu thức Apache với viết lạiđiều kiện
chỉ thị để giải mã URL CHUỖI TRUY VẤN
trước khi thực hiện so sánh. Tuy nhiên, điều này không thực sự giúp ích cho bạn vì nó không có dấu gạch chéo %-decode. %2F
hoặc %2f
vẫn theo yêu cầu (nhưng bất kỳ ký tự nào khác được %-decoded). Ví dụ:
RewriteCond expr "unescape(%{QUERY_STRING}) =~ m#^rp=(/|%2[Ff])knowledgebase(/|%2[Ff])#"
Điều này sẽ cho phép bạn phù hợp với rp=%2f%6b%6e%6f%77%6c%65%64%67%65%62%61%73%65%2f
.
Hoặc, nếu bạn không mong đợi bất kỳ ký tự mã hóa URL nào trong chuỗi truy vấn thì bạn có thể chỉ cần chặn mọi yêu cầu gửi bất kỳ! Ví dụ: những điều sau đây sẽ cần phải xuất hiện ở đầu cấu hình của bạn:
# Chặn bất kỳ yêu cầu nào bao gồm ký tự %-được mã hóa trong chuỗi truy vấn
RewriteCond %{QUERY_STRING} %[\da-f]{2} [NC]
Quy tắc viết lại ^ - [R=400]