【XSS】通過對HTML響應進行編碼來防止跨站點指令碼攻擊
技術標籤:Web
公司將應用程式移動到Web上,以改善客戶互動,降低業務處理成本並加快結果的速度。但是這樣做也會增加漏洞-除非安全性是應用程式開發過程中不可或缺的組成部分。要了解有關在組織中建立安全文化的更多資訊,請下載並閱讀“安全Web應用程式:建立安全文化”。
在跨站點指令碼(XSS)攻擊中,攻擊者將惡意程式碼注入到合法的網頁中,然後該網頁執行惡意的客戶端指令碼。當用戶訪問受感染的網頁時,指令碼將下載到使用者的瀏覽器並從其執行。此方案有很多變體。惡意指令碼可能訪問瀏覽器cookie,會話令牌或瀏覽器保留的其他敏感資訊。但是,所有XSS攻擊都遵循圖1所示的模式。
圖1.典型的XSS攻擊
XSS漏洞
在典型的XSS攻擊中,攻擊者找到了一種在伺服器的網頁中插入字串的方法。假設攻擊者向網頁中注入了以下字串: <script>alert("attacked")</script>
。終端使用者每次訪問此頁面時,其瀏覽器都會下載此指令碼並在呈現頁面時執行該指令碼。在這種情況下,指令碼將執行,並且使用者會看到一個彈出警報,提示“已攻擊”。
XSS的影響
當攻擊者成功利用Web應用程式中的XSS漏洞時,他們可以插入指令碼,使他們能夠訪問終端使用者的帳戶憑據。攻擊者可以執行各種惡意活動,例如:
- 劫持帳戶
- 傳播網路蠕蟲
- 訪問瀏覽器歷史記錄和剪貼簿內容
- 遠端控制瀏覽器
- 掃描和利用Intranet裝置和應用程式
防止XSS攻擊
為了幫助防止XSS攻擊,應用程式需要確保將頁面中的所有變數輸出編碼後再返回給終端使用者。編碼變數輸出將HTML標記替換為稱為實體的替代表示。瀏覽器顯示實體,但不執行它們。例如,<script>
將轉換為<script>
。
表1顯示了一些常見HTML字元的實體名稱。
表1. HTML字元的實體名稱
結果 | 描述 | 實體名稱 | 實體編號 |
---|---|---|---|
不間斷空間 | &nbsp; | &#160; | |
< | 少於 | &lt; | &#60; |
> | 比...更棒 | &gt; | &#62; |
和 | &符 | &amp; | &#38; |
¢ | 分 | &cent; | &#162; |
£ | 磅 | &磅; | &#163; |
¥ | 日元 | &日元; | &#165; |
歐元 | &歐元; | &#8364; | |
§ | 部分 | &教派; | &#167; |
© | 版權 | &複製; | &#169; |
® | 註冊商標 | &reg; | &#174 |
™ | 商標 | &trade; | &#8482; |
當網路瀏覽器遇到實體時,它們將被轉換回HTML並列印,但將不會執行。例如,如果攻擊者注入 <script>alert("you are attacked")</script>
伺服器網頁的可變欄位,則伺服器將使用此策略返回 <script>alert("you are attacked")</script>
。
當網路瀏覽器下載編碼指令碼時,它將把編碼指令碼轉換回 <script>alert("you are attacked")</script>
並顯示為網頁的一部分,但瀏覽器不會執行該指令碼。
將HTML程式碼新增到伺服器端Java應用程式
為確保惡意指令碼程式碼不會作為頁面的一部分輸出,您的應用程式需要對所有可變字串進行編碼,然後才能在頁面上顯示它們。編碼只是將每個字元轉換為其HTML實體名稱,如清單1中的Java程式碼示例所示。
清單1.將字元轉換為HTML實體名稱
在清單1的Java示例中,對於HTML編碼,輸入為
public class EscapeUtils {
public static final HashMap m = new HashMap();
static {
m.put(34, """); // < - less-than
m.put(60, "<"); // < - less-than
m.put(62, ">"); // > - greater-than
//User needs to map all html entities with their corresponding decimal values.
//Please refer to below table for mapping of entities and integer value of a char
}
public static String escapeHtml() {
String str = "<script>alert(\"abc\")</script>";
try {
StringWriter writer = new StringWriter((int)
(str.length() * 1.5));
escape(writer, str);
System.out.println("encoded string is " + writer.toString() );
return writer.toString();
} catch (IOException ioe) {
ioe.printStackTrace();
return null;
}
}
public static void escape(Writer writer, String str) throws IOException {
int len = str.length();
for (int i = 0; i < len; i++) {
char c = str.charAt(i);
int ascii = (int) c;
String entityName = (String) m.get(ascii);
if (entityName == null) {
if (c > 0x7F) {
writer.write("&#");
writer.write(Integer.toString(c, 10));
writer.write(';');
} else {
writer.write(c);
}
} else {
writer.write(entityName);
}
}
}
}
在清單1的Java示例中,對於HTML編碼,輸入為 String “”。使用以下步驟。
1、建立所有HTML實體及其十進位制值的雜湊圖。該示例僅顯示三個條目。您需要在此對映中對映所有HTML實體及其十進位制值。表2顯示了一些常用的實體及其十進位制值。對於所有字元實體的完整參考,請參見HTML實體參考資源。
2、建立一個StringWriter1.5倍於輸入字串長度的緩衝區。
3、將此寫程式和輸入字串都傳遞給該escape 方法,該方法一個接一個地拾取字串的每個字元,並獲取該字元的整數值。
將整數值傳遞給您在步驟1中建立的對映,獲取實體名稱,然後將此值寫在writer上。
4、字串的每個字元都將轉換為其實體名稱。
輸出為
<script>alert("abc")</script>
// 正如上文所言當瀏覽器載入該結果時,會自動轉化為<script>alert(\"abc\")</script>,但是並不會執行該指令碼
跨站點指令碼編寫仍然是攻擊使用者計算機的最常用方法之一。但是,您可以在很大程度上消除攻擊者使用惡意程式碼感染Web應用程式的能力。在編寫應用程式時,請先對頁面中的所有變數輸出進行編碼,然後再將其傳送到終端使用者的瀏覽器。
原文地址:https://www.ibm.com/developerworks/library/se-prevent/index.html