搞Web開發離不開安全這個話題,確保網站或者網頁應用的安全性,是每一個開發人員都應該瞭解的事。本篇主要簡單介紹在Web領域幾種常見的攻擊手段及Java Web中的預防方式。javascript
項目地址: https://github.com/morethink/web-securityhtml
XSS攻擊:跨站腳本攻擊(Cross-Site Scripting),爲了避免和層疊樣式表(Cascading Style Sheets, CSS)的縮寫混淆,故將跨站腳本攻擊縮寫爲XSS。XSS是一種常見的web安全漏洞,它容許攻擊者將惡意代碼植入到提供給其它用戶使用的頁面中。不一樣於大多數攻擊(通常只涉及攻擊者和受害者),XSS涉及到三方,即攻擊者、客戶端與Web應用。XSS的攻擊目標是爲了盜取存儲在客戶端的cookie或者其餘網站用於識別客戶端身份的敏感信息。一旦獲取到合法用戶的信息後,攻擊者甚至能夠假冒合法用戶與網站進行交互。前端
XSS一般能夠分爲兩大類:java
惡意用戶的Html輸入Web程序->進入數據庫->Web程序->用戶瀏覽器
。好比說我寫了一個網站,而後攻擊者在上面發佈了一個文章,內容是這樣的 <script>alert(document.cookie)</script>
,若是我沒有對他的內容進行處理,直接存儲到數據庫,那麼下一次當其餘用戶訪問他的這篇文章的時候,服務器從數據庫讀取後而後響應給客戶端,瀏覽器執行了這段腳本,就會將cookie展示出來,這就是典型的存儲型XSS。jquery
如圖:
git
答案很簡單,堅定不要相信用戶的任何輸入,並過濾掉輸入中的全部特殊字符。這樣就能消滅絕大部分的XSS攻擊。github
目前防護XSS主要有以下幾種方式:web
script
標籤)。w.Header().Set("Content-Type","text/javascript")
攻擊者成功的向服務器提交惡意的SQL查詢代碼,程序在接收後錯誤的將攻擊者的輸入做爲查詢語句的一部分執行,致使原始的查詢邏輯被改變,額外的執行了攻擊者精心構造的惡意代碼。ajax
舉例:' OR '1'='1
算法
這是最多見的 SQL注入攻擊,當咱們輸如用戶名 admin ,而後密碼輸如' OR '1'=1='1
的時候,咱們在查詢用戶名和密碼是否正確的時候,原本要執行的是SELECT * FROM user WHERE username='' and password=''
,通過參數拼接後,會執行 SQL語句 SELECT * FROM user WHERE username='' and password='' OR '1'='1'
,這個時候1=1是成立,天然就跳過驗證了。
以下圖所示:
可是若是再嚴重一點,密碼輸如的是';DROP TABLE user;--
,那麼 SQL命令爲SELECT * FROM user WHERE username='admin' and password='';drop table user;--'
這個時候咱們就直接把這個表給刪除了。
'"\尖括號&*
;等)進行轉義處理,或編碼轉換。在上圖展現中,使用了Java JDBC中的PreparedStatement
預編譯預防SQL注入,能夠看到將全部輸入都做爲了字符串,避免執行惡意SQL。
DDOS:分佈式拒絕服務攻擊(Distributed Denial of Service),簡單說就是發送大量請求是使服務器癱瘓。DDos攻擊是在DOS攻擊基礎上的,能夠通俗理解,dos是單挑,而ddos是羣毆,由於現代技術的發展,dos攻擊的殺傷力下降,因此出現了DDOS,攻擊者藉助公共網絡,將大數量的計算機設備聯合起來,向一個或多個目標進行攻擊。
在技術角度上,DDoS攻擊能夠針對網絡通信協議的各層,手段大體有:TCP類的SYN Flood、ACK Flood,UDP類的Fraggle、Trinoo,DNS Query Flood,ICMP Flood,Slowloris類等等。通常會根據攻擊目標的狀況,針對性的把技術手法混合,以達到最低的成本最難防護的目的,而且能夠進行合理的節奏控制,以及隱藏保護攻擊資源。
下面介紹一下TCP協議中的SYN攻擊。
在三次握手過程當中,服務器發送 SYN-ACK
以後,收到客戶端的 ACK
以前的 TCP 鏈接稱爲半鏈接(half-open connect)。此時服務器處於 SYN_RCVD
狀態。當收到 ACK 後,服務器才能轉入 ESTABLISHED
狀態.
SYN
攻擊指的是,攻擊客戶端在短期內僞造大量不存在的IP地址,向服務器不斷地發送SYN
包,服務器回覆確認包,並等待客戶的確認。因爲源地址是不存在的,服務器須要不斷的重發直至超時,這些僞造的SYN
包將長時間佔用未鏈接隊列,正常的SYN
請求被丟棄,致使目標系統運行緩慢,嚴重者會引發網絡堵塞甚至系統癱瘓。
阿里巴巴的安全團隊在實戰中發現,DDoS 防護產品的核心是檢測技術和清洗技術。檢測技術就是檢測網站是否正在遭受 DDoS 攻擊,而清洗技術就是清洗掉異常流量。而檢測技術的核心在於對業務深入的理解,才能快速精確判斷出是否真的發生了 DDoS 攻擊。清洗技術對檢測來說,不一樣的業務場景下要求的粒度不同。
CSRF(Cross-site request forgery),中文名稱:跨站請求僞造,也被稱爲:one click attack/session riding,縮寫爲:CSRF/XSRF。
你這能夠這麼理解CSRF攻擊:攻擊者盜用了你的身份,以你的名義發送惡意請求。CSRF可以作的事情包括:以你名義發送郵件,發消息,盜取你的帳號,甚至於購買商品,虛擬貨幣轉帳......形成的問題包括:我的隱私泄露以及財產安全。
下圖簡單闡述了CSRF攻擊的思
從上圖能夠看出,要完成一次CSRF攻擊,受害者必須依次完成兩個步驟:
看到這裏,你也許會說:「若是我不知足以上兩個條件中的一個,我就不會受到CSRF的攻擊」。是的,確實如此,但你不能保證如下狀況不會發生:
下面講一講java解決CSRF攻擊的方式。
用戶名和密碼都是admin。
http://localhost:8081/login.html
:
http://localhost:8081/deletePost.html
:
http://localhost:8082/deletePost.html
:
明顯看到B網站是8082端口,A網站是8081端口,可是B網站的刪除2號帖子功能依然實現。
簡單來講,CSRF 就是網站 A 對用戶創建信任關係後,在網站 B 上利用這種信任關係,跨站點向網站 A 發起一些僞造的用戶操做請求,以達到攻擊的目的。
而之因此能夠完成攻擊是由於B向A發起攻擊的時候會把A網站的cookie帶給A網站,也就是說cookie已經不安全了。
Synchronizer Tokens: 在表單裏隱藏一個隨機變化的 csrf_token csrf_token 提交到後臺進行驗證,若是驗證經過則能夠繼續執行操做。這種狀況有效的主要緣由是網站 B 拿不到網站 A 表單裏的 csrf_token
這種方式的使用條件是PHP和JSP等。由於cookie已經不安全了,所以把csrf_token值存儲在session中,而後每次表單提交時都從session取出來放到form表單的隱藏域中,這樣B網站不能夠獲得這個存儲到session中的值。
下面是JSP的:
<input type="hidden" name="random_form" value=<%=random%>></input>
可是我如今的狀況是html,不是JSP,並不能動態的從session中取出csrf_token值。只能採用加密的方式了。
這多是最簡單的解決方案了,由於攻擊者不能得到第三方的Cookie(理論上),因此表單中的數據也就構造失敗了。
我採用的hash加密方法是JS實現Java的HashCode方法,獲得hash值,這個比較簡單。也能夠採用其餘的hash算法。
前端向後臺傳遞hash以後的csrf_token值和cookie中的csrf_token值,後臺拿到cookie中的csrf_token值後獲得hashCode值而後與前端傳過來的值進行比較,同樣則經過。
http://localhost:8081/deletePost.html
咱們經過UserFilter.java給攻擊者返回的是403錯誤,表示服務器理解用戶客戶端的請求但拒絕處理。
http://localhost:8082/deletePost.html
:
攻擊者不能刪除4號帖子。
前端代碼:
deletePost.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>deletePost</title> <script type="text/javascript" src="js/jquery.min.js"></script> <script type="text/javascript"> function deletePost() { var url = '/post/' + document.getElementById("postId").value; var csrf_token = document.cookie.replace(/(?:(?:^|.*;\s*)csrf_token\s*\=\s*([^;]*).*$)|^.*$/, "$1"); console.log('csrf_token=' + csrf_token); $.ajax({ type: "post",//請求方式 url: url, //發送請求地址 timeout: 30000,//超時時間:30秒 data: { "_method": "delete", "csrf_token": hash(csrf_token) // 對csrf_token進行hash加密 }, dataType: "json",//設置返回數據的格式 success: function (result) { if (result.message == "success") { $("#result").text("刪除成功"); } else { $("#result").text("刪除失敗"); } }, error: function () { //請求出錯的處理 $("#result").text("請求出錯"); } }); } // javascript的String到int(32位)的hash算法 function hash(str) { var hash = 0; if (str.length == 0) return hash; for (i = 0; i < str.length; i++) { char = str.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash = hash & hash; // Convert to 32bit integer } return hash; } </script> </head> <body> <h3>刪除帖子</h3> 帖子編號 : <input type="text" id="postId"/> <button onclick="deletePost();">deletePost</button> <br/> <br/> <br/> <div> <p id="result"></p> </div> </body> </html>
後臺代碼:
UserInterceptor.java
package cn.morethink.interceptor; import cn.morethink.util.JsonUtil; import cn.morethink.util.Result; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.PrintWriter; /** * @author 李文浩 * @date 2018/1/4 */ public class UserInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String method = request.getMethod(); System.out.println(method); if (method.equalsIgnoreCase("POST") || method.equalsIgnoreCase("DELETE") || method.equalsIgnoreCase("PUT")) { String csrf_token = request.getParameter("csrf_token"); Cookie[] cookies = request.getCookies(); if (cookies != null && cookies.length > 0 && csrf_token != null) { for (Cookie cookie : cookies) { if (cookie.getName().equals("csrf_token")) { if (Integer.valueOf(csrf_token) == cookie.getValue().hashCode()) { return true; } } } } } Result result = new Result("403", "你還想攻擊我??????????", ""); PrintWriter out = response.getWriter(); out.write(JsonUtil.toJson(result)); out.close(); return false; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }
注意:
上面一共提到了4種攻擊方式,分別是XSS攻擊(關鍵是腳本,利用惡意腳本發起攻擊),SQL注入(關鍵是經過用SQL語句僞造參數發出攻擊),DDOS攻擊(關鍵是發出大量請求,最後令服務器崩潰),CSRF攻擊(關鍵是藉助本地cookie進行認證,僞造發送請求)。
參考文檔: