談Web前端安全編碼

jopen 9年前發布 | 13K 次閱讀 前端 安全相關

 

最近開發中涉及到有關輸出正確的HTML標簽這樣的問題,正好對字符編碼這塊兒多看看,之前對這個方面認識的不深,思考的確實不夠,如果下次再碰見類似的問題,若再次不少時間去調研的花,就得不償失了。

就像正則表達式一樣,似乎你知道它,但是每一次開發都需要現取查、現取測試,估計你會像我一樣,每一次都會花些意想不到的時間。

總之,重在學習。

有一篇文章,這個博友已經總結的非常到位了,引入于此,看到的同學,希望可以多看看他做的總結:

在web的開發的開發過程中,前端總是在處理后端打的各種變量,變量可以包含著中的各種各樣的字符,如果不對這些字符進行”特殊“處理的 話,輕者導致頁面不正常的顯示,潛入了其他的東西,亦即頁面掛了,或者彈出不應該彈出的東西,這些都是我們不期望看到的,重者可能導致密碼泄露,網站的訪 問量突然猛增,服務器掛掉。

在前端的開發中,涉及到以下幾種語境:

1)直接顯示在頁面上, eg:<div>{%username%}</div>,<input type="text" value="{%username%}"/>

2)在script 標簽中,eg :<script>var test = '{%username%}';var test="{%username%}"</script>

3)在頁面事件中,eg:<div onclick="alert('{%username%}')">334455</div>

4)在innerHTML 的語境中,eg:<div id="test"></div> <script>var test="{%username%}";document.getElementById('test').innerHTML =test; </script>

5)在頁面鏈接的url中:eg:<a href="{%username%}"></a>

6)提交url參數處理

7)js 獲取url參數值的時候

下面來一個一個的分析上面提到了7種語境中的轉義情況:

1)直接顯示在頁面上(簡稱頁面html環境中):

為了保證用戶的本意,完完全全的展示在頁面上,這類主要是防止標簽的自閉合,屬性中的單引號,雙引號已經存在的情況下不正確顯示,所以必須轉義4個字符:<,>,",'  to為轉義的意思(下同)

(1)<  to &lt;

(2) > to &gt;

(3)" to &quot;

(4)' to &#39;

2)在script的標簽中(簡稱js環境中):

在javascript 中 ” 和' 都是表示字符串,沒有任何區別,所以如果變量中出現了這2個字符,就會影響后面不正確顯示,所以必須轉義這2個字符 ,同理,如果變量中包含\ 會將后面的'或者“給轉義掉,

變成真正的’和”,也沒有閉合,導致語法錯誤,所以這個字符也需要轉義,另外在我們的注釋中存在/*  */ 這種形式,如果在變量中出現了 */這種字符,就會將注釋掉的部分代碼給暴漏出來,所以也要轉義/字符,

綜上所述,在script標簽中要轉義的字符為:

(1)'   to \'

(2)"  to \"

(3)\  to \\

(4)/  to \/

3)在頁面事件中:

這類語境涉及到了頁面html和Js 環境,要執行什么轉義呢?到底是先html 在js,還是先js 再html 轉義呢?我們來看一個例子:

eg:<div onclick="alert('{%username%}')"></div>

當username = " 的時候,如果是先html ,然后再js 轉義的時候,那么就是<div onlick="alert('&qout;')"></div>   我們拿到頁面上去執行,發現語法報錯

如果是先js,先后在html轉義的時候,那么就是<div onlick="alert('\&qout;')"></div>   我們拿到頁面上去執行,成功!!

所以結論是 先進行JS 轉義,然后再進行html 轉義,為什么是這樣呢?因為這里它是要執行一個js函數的,如果都當做html來解析了,這里的js函數就不會執行,也就沒有js 環境的意思了。

綜上所述,在這累語境中需要轉義的字符為:

(1)'   to \&#38;

(2)"  to \&quot;

(3)\  to \\

(4)/  to \/

(5)< to &lt;

(6)< to &gt;

4) 在innerHTML環境中:

這類語境首先是js環境中,其次是在html環境中,顯然,先進行js轉義,然后再進行html轉義,需要轉義的字符同上述3)

5)在頁面鏈接的url 環境中:

這類比較復雜,url中本身涉及到很多的特殊字符,此外也會涉及到html 和js 環境中的賦值的情況, 特別注意,url 編碼和html的編碼是不一樣的,見后文附錄url編碼表和html編碼表

在html 和js環境中,需要轉義的字符為:  ”  ,' ,<,>,\ ,/

在其他環境中,需要轉義的字符為:+,空格,?,=,&,#, %

這類字符的轉義如下:

(1)"  to %22;

(2)' to %22;

(3) <  to  %3C

(4) >  to %3E

(5) \  to %5C

(6) / to %2F

(7) +  to %2b

(8)空格 to  %20

(9)?  to  %3F

(10)=  to  %3D

(11)&  to %26

(12)#  to 23

(13) %  to %25

為什么要轉義這些字符呢?稍微web開發的經驗同學就知道,原因很簡單,如果存在這些字符的話,不進行轉義,那么我們就會得不到我們應該得到的東西

引申一點:在我們拼接url的時候,比如將表單中的數據提取出來,用ajax的方式提交的時候,也需要對上述字符進行轉義,不然得到的也不是想到的東西

6)提交url 參數的處理:

1) Form  表單提交方式:不需要做任何處理,表單會依照頁面的編碼進行編碼

2) ajax 的提交:因為ajax的提交的時候,是拼接成url的方式提交給后端的,所以必須要考慮對  +,空格,?,=,&,#, % 的轉義,通常使用 encodeURIComponent進行轉義

關于escape,encodeURI,encodeURIComponent  這三個函數的需要的轉義字符,見后面的附件列表

7) js 獲取url參數的值的時候

(1) 得到url中的參數值的時候,首先必須要進行unescape的轉碼才能使用,因為url中的一些特殊字符都經過了編碼

(2) 將url的值設置到一些參數上時,比如隱藏表單上的value值的時候(作提交refer),需要進行escape 編碼

附錄:

1)html 編碼: http://wenku.baidu.com/view/0dbaa1dc7f1922791688e8a2.html

2)url 編碼: http://baike.baidu.com/view/204662.htm

3)escape,encodeURI,encodeURIComponent 的區別: http://www.alixixi.com/web/a/2008081147930.shtml

上述引文來自: web前端安全編碼(模版篇)

我概要一下,分為兩類,模板(或稱為顯示)相關,另一類是URL相關;

一、模板(顯示)相關:

我們要把不確定性的后端文本變量(當然來自絕大部分來自用戶的輸入),為了讓之正確的顯示在頁面中(也就是HTML中),或者正確的執行js代碼,我們要對特殊字符進行轉義:

HTML環境:

< 轉義 &lt;
> 轉義 &gt;
" 轉義 "
' 轉義 '

JS環境:

' 轉義 \'
" 轉義 \"
\ 轉義 \\
/ 轉義 \/

對應的工具函數如:

// 轉義為HTML環境
// 主要用于innerHTML這種場景
var toSwitchForHtml = function(text){
    if (typeof text !== 'string') {
  throw new Error('The text must be a string !');
    }
    return text
      .replace(/</g,'<')
      .replace(/>/g,'>')
      .replace(/"/g, """)
      .replace(/'/g, "'");
};
// 轉義為JS環境
// 主要用于執行js代碼,如new Function(someStringFunctionFromServer);等
var toSwitchForJs = function(text) {
    if (typeof text !== 'string') {
  throw new Error('The text must be a string !');
    }
    return text
      .replace(/\\/g,'\\')
      .replace(/\//g,'\/')
      .replace(/"/g, """)
      .replace(/'/g, "'");
};

二、URL相關:

主要涉及3個可以對字符串編碼的函數,分別是:escape,encodeURI,encodeURIComponent,相應3個解碼函數:unescape,decodeURI,decodeURIComponent 。

相應的函數介紹,主要查看js api文檔即可。

這里做了個統計表格

方法 編碼范圍 作用 備注
escape 不編碼:
ASCII字母和數字、*+-./@_
其余全部編碼為十六進制轉義序列
在所有的計算機上讀取該字符串。要注意,它是將需要轉義的字符轉義成UTF-16(因為JavaScript只支持16位UTF-16編碼)碼點。 關于這個轉義之后的unicode編碼方案,可參考: Unicode與JavaScript詳解
encodeURI 不編碼:
ASCII字母和數字、!’()*._~
URL特定標示符:;/?:@&=+$,#
其余全部編碼,根據URL編碼規則進行編碼
對整個URL進行編碼,而URL的特定標識符不會被轉碼。 url編碼的含義:
url編碼就是一個字符ascii碼的十六進制。不過稍微有些變動,需要在前面加上“%”。比如“\”,它的ascii碼是92,92的十六進制是5c, 所以“\”的url編碼就是%5c。那么漢字的url編碼呢?很簡單,看例子:“胡”的ascii碼是-17670,十六進制是BAFA,url編碼是“ %BA%FA”。更多請參看: URL編碼
encodeURIComponent 不編碼:
ASCII字母和數字、!’()*._~
編碼:
URL特定標示符:;/?:@&=+$,#
其余全部編碼,根據URL編碼規則進行編碼
將文本字符串編碼為一個統一資源標識符 (URI) 的一個有效組件。 請注意 encodeURIComponent() 函數 與 encodeURI() 函數的區別之處,前者假定它的參數是 URI 的一部分(比如協議、主機名、路徑或查詢字符串)。因此 encodeURIComponent() 函數將轉義用于分隔 URI 各個部分的標點符號。

根據上面的表格,我們再來分析使用場景:

1. 當js使用數據時可以使用escape,比如獲取或者設置URL中的參數值的時候(當然,約定該URL中傳遞的參數是經過unicode編碼的)

2. 進行 url跳轉 時可以整體使用encodeURI。如——

document.write(encodeURI("http://abc.com/do?name=文章&name=king"));

3. 傳遞參數 時需要使用encodeURIComponent,這樣組合的url才不會被#等特殊字符截斷。如——

<script >document.write('<a );</script>

弄清escape、encodeURI、encodeURIComponent的內容,量并不小,需要耐心去理解、去實踐。

參考:

1. web前端安全編碼(模版篇)

2. escape()、encodeURI()、encodeURIComponent()區別詳解

3. URL編碼

4. HTML轉義字符

5. Unicode與JavaScript詳解

6. escape,encodeURI,encodeURIComponent方法使用

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!