網(wǎng)絡(luò)安全攻防:Web安全之URL結(jié)構(gòu)
本文針對URL(Uniform Resource Locator)簡單介紹URL的結(jié)構(gòu)和URL的編碼與解碼等問題。為什么需要對 URL 進(jìn)行編碼,對其編碼的好處體現(xiàn)在哪里?首先,URL是統(tǒng)一資源標(biāo)識,通常所說的URL只是URI的一部分。典型的URL的格式如圖1所示。
圖1 URL格式
而下面所提到的URL編碼,實際也應(yīng)該指的是URI編碼。
需要進(jìn)行編碼的部分通常來說是不方便傳輸或會造成歧義的。原因還有很多,對于URL來說,需要編碼是因為 URL 中的某些字符會造成歧義。例如,在傳輸?shù)倪^程中,通常會使用鍵值對的方式,username=12345;這種方式對于人而言很好理解,這是一個賦值的過程,而接收URL的服務(wù)器卻不知道“=”這個字符是字符串?dāng)?shù)據(jù)的一部分還是賦值的需要,所以這里的字符在傳輸過程中是需要進(jìn)行編碼的。
又例如,URL的編碼格式采用的是ASCII碼,而不是Unicode,這也就是說URL中不能包含任何非ASCII字符,如中文。否則,如果客戶端瀏覽器和服務(wù)端瀏覽器支持的字符集不同,中文可能會造成問題。
所以,URL編碼的原則是使用安全字符去表示那些不安全的字符,如百分號編碼。
1. 百分號編碼
在介紹百分號編碼前,還要了解URL需要對哪些字符進(jìn)行編碼。
RFC3986文檔規(guī)定,URL中只允許包含英文字母(a~z、A~Z)、數(shù)字(0~9)、“-”“_”“.”“~” 4個特殊字符以及所有保留字符。
所謂的保留字符就是劃分URL的,分隔不同組件的字符。
RFC3986中指定了以下字符為保留字符,如圖2所示。
圖2 RFC3986保留字符
百分號編碼的編碼方式非常簡單,使用百分號(%)加上兩個字符(0123456789ABCDEF),表示為一個字節(jié)的十六進(jìn)制的形式。URL編碼默認(rèn)使用的字符集是ASCII碼。例如,井號(#)對應(yīng)的十六進(jìn)制是0x23,所以它的URL編碼就為%23。對于非ASCII字符,需要使用ASCII字符集的超集進(jìn)行編碼得到相應(yīng)的字節(jié),然后對每個字節(jié)執(zhí)行百分號編碼。
2. URL解析
在傳輸前,瀏覽器會對 URL 進(jìn)行編碼。接收 URL 的服務(wù)器主要負(fù)責(zé)對接收到的 URL進(jìn)行解析。URL的使用過程當(dāng)中,由于互聯(lián)網(wǎng)上的每個網(wǎng)頁大多會引用與它同服務(wù)器甚至是同級目錄下的文件,就會使用到相對URL的概念。在介紹URL編碼時,展示的是絕對URL,這就相當(dāng)于電腦中的相對路徑與絕對路徑的區(qū)別。所以在解析的時候,服務(wù)器需要區(qū)分相對URL與絕對URL。
按照規(guī)范里的說法,要區(qū)分兩者非常簡單。如果 URL 字符串不是一個有效的協(xié)議名,后面跟的不是冒號(:)或雙斜杠(//),那么它就是一個需要被引用的相對 URL。其實在實際應(yīng)用中,對于相對 URL 的解析是有規(guī)范的,因為不同瀏覽器的具體實現(xiàn)千差萬別,有效協(xié)議名稱的字符集也各有不同,還有各種替代雙斜杠(//)分隔符的方法,因此,接下來會對相對URL的解析進(jìn)行一個歸類。
(1)有協(xié)議名稱,但沒有授權(quán)信息(http:abc.txt)。這是一個比較有名的漏洞,它的產(chǎn)生是由RFC3986規(guī)范疏忽所致。在規(guī)范中將這些地址描述為無效的絕對地址,但在提供的解析算法中又將這種地址的解析搞錯了。所以這種形式的URL,在執(zhí)行過程中會被理解為相對地址來進(jìn)行處理。例如,在某些情況下,http:abc.txt會被理解為相對地址,而https:example.com會被解釋為絕對地址。
(2)沒有協(xié)議名,但有授權(quán)信息(//example.com)。這種寫法在規(guī)范中給出了較為完整的處理。面對這種URL,瀏覽器會自動補(bǔ)全該URL。
(3)沒有協(xié)議名,沒有授權(quán)信息,但有路徑(../robots.txt)。這是一種比較常見的用法,協(xié)議和授權(quán)信息都從引用URL里復(fù)制過來,然后將這個相對地址進(jìn)行補(bǔ)全。
(4)沒有協(xié)議名,沒有授權(quán)信息,沒有路徑,但有查詢的字符串(?username=abc)。在這種情況下,協(xié)議、授權(quán)信息、路徑全都會原封不動地從原引用 URL 復(fù)制過來。查詢字符串和字段ID則來自于相對URL。
(5)只有片段 ID(#bunnies)。這種方式也是如此,其他部分全部原封不動地從原引用URL復(fù)制,只替換字段ID的部分。