XSS
XSS攻擊的全稱是跨站腳本攻擊(Cross Site Scripting),為了不和層疊樣式表 (Cascading Style Sheets,CSS)的縮寫混淆,故將跨站腳本攻擊縮寫為XSS,是WEB應用程序中最常見到的攻擊手段之一。跨站腳本攻擊指的是攻擊者在網頁中嵌入惡意腳本程序, 當用戶打開該網頁時,腳本程序便開始在客戶端的瀏覽器上執行,以盜取客戶端cookie、 盜取用戶名密碼、下載執行病毒木馬程序等等。
有一種場景,用戶在表單上輸入一段數據后,提交給服務端進行持久化,其他頁面上需要從服務端將數據取出來展示。還是使用之前那個表單nick,用戶輸入昵稱之后,服務端會將nick保存,並在新的頁面展現給用戶,當普通用戶正常輸入hollis,頁面會顯示用戶的 nick為hollis:
<body> hollis </body>
但是,如果用戶輸入的不是一段正常的nick字符串,而是<script>alert("haha")</script>
, 服務端會將這段腳本保存起來,當有用戶查看該頁面時,頁面會出現如下代碼:
<body> <script> alert("haha") </script> </body>
XSS該如何防御
XSS之所以會發生,是因為用戶輸入的數據變成了代碼。因此,我們需要對用戶輸入的數據進行HTML轉義處理,將其中的“尖括號”、“單引號”、“引號” 之類的特殊字符進行轉義編碼。
如今很多開源的開發框架本身默認就提供HTML代碼轉義的功能,如流行的jstl、Struts等等,不需要開發人員再進行過多的開發。使用jstl標簽進行HTML轉義,將變量輸出,代碼 如下:
<c:out value="${nick}" escapeXml="true"></c:out>
只需要將escapeXml設置為true, jstl就會將變量中的HTML代碼進行轉義輸出。
CSRF
CSRF攻擊的全稱是跨站請求偽造(cross site request forgery), 是一種對網站的惡意利用,盡管聽起來跟XSS跨站腳本攻擊有點相似,但事實上CSRF與XSS差別很大,XSS利用的是站點內的信任用戶,而CSRF則是通過偽裝來自受信任用戶的請求來利用受信任的網站。你可以這么理解CSRF攻擊:攻擊者盜用了你的身份,以你的名義向第三方網站發送惡意請求。CRSF能做的事情包括利用你的身份發郵件、發短信、進行交易轉賬等等,甚至盜取你的賬號。
假設某銀行網站A,他以GET請求來發起轉賬操作,轉賬的地址為www.xxx.com/transfer.do?accountNum=10001&money=10000,accountNum參數表示轉賬的目的賬戶,money參數表示轉賬金額。 而某大型論壇B上,一個惡意用戶上傳了一張圖片,而圖片的地址欄中填的並不是圖片的地址,而是前面所說的轉賬地址:
<img src="http://www.xxx.com/transfer.do?accountNum=10001&money=10000">
當你登陸網站A后,沒有及時登出,這個時候你訪問了論壇B,不幸的事情發生了,你會發現你的賬戶里面少了10000塊……
為什么會這樣呢,在你登陸銀行A的時候,你的瀏覽器端會生成銀行A的cookie,而當你訪問論壇B的時候,頁面上的標簽需要瀏覽器發起一個新的HTTP請求,以獲得圖片資源, 當瀏覽器發起請求的時候,請求的卻是銀行A的轉賬地址www.xxx.com/transfer.do?accoun tNum=10001&money=10000,並且會帶上銀行A的cookie信息,結果銀行的服務器收到這個請求后,會認為是你發起的一次轉賬操作,因此你的賬戶里邊便少了10000塊。
CSRF的防御
cookie設置為HttpOnly
CSRF攻擊很大程度上是利用了瀏覽器的cookie,為了防止站內的XSS漏洞盜取cookie,需要在cookie中設置”HttpOnly”屬性,這樣通過程序(如JavascriptS腳本、Applet等)就無法讀取到cookie信息,避免了攻擊者偽造cookie的情況出現。
增加token
CSRF攻擊之所以能夠成功,是因為攻擊者可以偽造用戶的請求,該請求中所有的用戶驗證信息都存在於cookie中,因此攻擊者可以在不知道用戶驗證信息的情況下直接利用用戶的cookie來通過安全驗證。由此可知,抵御CSRF攻擊的關鍵在於:在請求中放入攻擊者所不能偽造的信息,並且該信息不存在於cookie之中。鑒於此,系統開發人員可以在HTTP請求中以參數的形式加入一個隨機產生的token,並在服務端進行token校驗,如果請求中沒有token或者token內容不正確,則認為是CSRF攻擊而拒絕該請求。
通過Referer識別
根據HTTP協議,在HTTP頭中有一個字段叫Referer,它記錄了該HTTP請求的來源地址。在通常情況下,訪問一個安全受限頁面的請求都來自於同一個網站。比如某銀行的轉賬是通過用戶訪問http://www.xxx.com/transfer.do頁面完成,用戶必須先登錄www.xxx.com,然后通過點擊頁面上的提交按鈕來觸發轉賬事件。當用戶提交請求時,該轉賬請求的Referer值就會是提交按鈕所在頁面的URL(本例為www.xxx.com/transfer.do)。如果攻擊者要對銀行網站實施CSRF攻擊,他只能在其他的網站構造請求,當用戶通過其他網站發送請求到銀行時,該請求的Referer的值是其他網站的地址,而不是銀行轉賬頁面的地址。因此,要防御CSRF攻擊,銀行網站只需要對於每一個轉賬請求驗證其Referer值,如果是以www.xxx.com域名開頭的地址,則說明該請求是來自銀行網站自己的請求,是合法的。如果 Referer是其他網站的話,就有可能是CSRF攻擊,則拒絕該請求。
SQL注入攻擊
所謂SQL注入,就是通過把SQL命令偽裝成正常的HTTP請求參數,傳遞到服務端,欺騙服務器最終執行惡意的SQL命令,達到入侵目的。攻擊者可以利用SQL注入漏洞,查詢非授權信息, 修改數據庫服務器的數據,改變表結構,甚至是獲取服務器root權限。總而言之,SQL注入漏洞的危害極大,攻擊者采用的SQL指令,決定攻擊的威力。當前涉及到大批量數據泄露的攻擊事件,大部分都是通過利用SQL注入來實施的。
假設有個網站的登錄頁面,如下所示:
假設用戶輸入nick為zhangsan,密碼為password1,則驗證通過,顯示用戶登錄:
否則,顯示用戶沒有登錄:
SQL注入攻擊原理
Connection conn = getConnection(); String sql = "select * from hhuser where nick = '" + nickname + "'" + " and passwords = '" + password + "'"; Statement st = (Statement) conn.createStatement(); ResultSet rs = st.executeQuery(sql); List<UserInfo> userInfoList = new ArrayList<UserInfo>(); while (rs.next()) { UserInfo userinfo = new UserInfo(); userinfo.setUserid(rs.getLong("userid")); userinfo.setPasswords(rs.getString("passwords")); userinfo.setNick(rs.getString("nick")); userinfo.setAge(rs.getInt("age"));