最近項目涉及到安全方面,本身特地瞭解了一下,記錄在此,共同窗習。javascript
常見的web安全有如下幾個方面html
所謂同源策略,指的是瀏覽器對不一樣源的腳本或者文本的訪問方式進行的限制。好比源a的js不能讀取或設置引入的源b的元素屬性。java
所謂"同源"指的是"三個相同"web
舉例來講,http://www.example.com/dir/page.html 這個網址,協議是 http:// ,域名是 www.example.com ,端口是 80(默認端口能夠省略)。它的同源狀況以下ajax
http://www.example.com/dir2/other.html:同源 http://example.com/dir/other.html:不一樣源(域名不一樣) http://v2.www.example.com/dir/other.html:不一樣源(域名不一樣) http://www.example.com:81/dir/other.html:不一樣源(端口不一樣)
同源政策的目的,是爲了保證用戶信息的安全,防止惡意的網站竊取數據。正則表達式
設想這樣一種狀況:A網站是一家銀行,用戶登陸之後,又去瀏覽其餘網站。若是其餘網站能夠讀取A網站的 Cookie,Cookie 包含的信息(好比存款總額)就會泄漏。而Cookie 每每用來保存用戶的登陸狀態,若是用戶沒有退出登陸,其餘網站就能夠冒充用戶,隨心所欲。spring
因而可知,"同源政策"是必需的,不然 Cookie 能夠共享,互聯網就毫無安全可言了。sql
隨着互聯網的發展,"同源政策"愈來愈嚴格。目前,若是非同源,共有三種行爲受到限制數據庫
咱們能夠在本地模擬非同源的ajax請求。express
先寫一個簡單的web應用做爲服務方,提供一個登錄服務接口,部署運行在tomcat上,此tomcat端口爲8080。
再寫一個小工程,只有一個簡單的登錄頁面。部署在另外一個tomcat上,此tomcat端口設定爲8081。
如此一來,兩個工程就不是同源了,由於端口不一樣。咱們在登錄頁面發送ajax請求,出現錯誤:
XMLHttpRequest cannot load http://192.168.2.82:8080/Demo/user/login. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8081' is therefore not allowed access. The response had HTTP status code 403.
要解決這個問題,能夠在服務器方設定
response.setHeader("Access-Control-Allow-Origin", "*");
服務方就能夠容許其餘域名訪問。
要設定容許某個域名或某幾個域名以下
response.setHeader("Access-Control-Allow-Origin", "http://localhost:8081"); response.setHeader("Access-Control-Allow-Origin", "http://localhost:8081,http://localhost:8082");
在spring mvc中,有一個註解@CrossOrigin,在須要提供跨域訪問的方法上添加便可
@CrossOrigin(origins = {"http://localhost:8081", "http://192.168.2.99:8080"})
這樣就能夠成功跨域登錄了。
實際應用中,也可讓ajax訪問同源服務接口,再由此服務去訪問其餘服務。
跨站腳本攻擊(Cross Site Scripting),爲了避免和層疊樣式表(Cascading Style Sheets,CSS)縮寫混淆,因此在安全領域叫作XSS。
XSS攻擊,是指黑客經過"HTML注入"篡改了網頁,插入了惡意的腳本,在用戶瀏覽網頁時,代碼執行,從而實現用戶瀏覽器。對受害用戶可能採起Cookie資料竊取、會話劫持、釣魚欺騙等各類攻擊。
XSS有以下幾種類型
反射型XSS
反射型XSS只是簡單地把用戶輸入的數據"反射"給瀏覽器。也就是說,黑客須要誘使用戶點擊一個惡意連接,才能攻擊成功。反射型XSS也叫非持久型XSS。
好比
<div>${message}</div>
正常狀況用戶提交信息
http://xxx.com/test.html?param=hello
那麼瀏覽器正常輸出"hello"信息
可是若是用戶輸入了一段HTML代碼
http://xxx.com/test.html?param=<script>alert("xss")</script>
那麼頁面彈框,顯示"XSS"
存儲型XSS
存儲型XSS會把用戶輸入的數據"存儲"在服務器。這種XSS具備很強的穩定性。
比較常見的場景是,黑客寫了一遍包含有惡意JavaScript的博客文章,文章發表後,全部訪問該博客文章的用戶,都會在他們的瀏覽器中執行這段惡意的JavaScript代碼。黑客把惡意腳本保存到服務器端,因此這種XSS攻擊就叫作"存儲型XSS"。
DOM Based XSS
經過修改頁面的DOM節點造成的XSS稱之爲DOM Based XSS。實際上,這種類型的XSS並不是按照"數據是否保存在服務器端"來劃分,DOM Based XSS從效果上來講也是反射型XSS。
假設xss.html頁面代碼以下
<!DOCTYPE HTML> <html> <head> <title>原頁面</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <style> button{ position:absolute; top: 315px; left: 462px; z-index: 1; width: 72px; height: 26px; } </style> </head> <body> <button onclick="func()">加關注</button> </body> <script> function func(){ alert("關注成功!"); } </script> </html>
文本框輸入內容並點擊write按鈕後,會在當前頁面插入一個超連接,其地址爲輸入的內容。
假設用戶輸入爲
' onclick=alert(/xss/) //
那麼頁面代碼變爲
<a href'' onclick=alert(/xss/)//'>testLink</a>
首先用第一個單引號閉合掉href的第一個單引號,而後插入一個onclick事件,最後在用//註釋掉第二個單引號。
點擊連接,腳本執行
XSS攻擊成功的根本緣由是將輸入的數據當成了代碼來執行,從而違背了原來的語義。因此要在輸入的時候要嚴格過濾,輸出的時候也要進行檢查。
常見的XSS攻擊,SQL注入,都要求攻擊者構造一些特殊字符,這些特殊字符是正經常使用戶不會用到的,因此輸入檢查頗有必要。
只接受指定長度範圍和指望格式的的內容提交,阻止或者忽略除此外的其餘任何數據。好比:用戶名只能是字母加數字,手機不長於16位,且大陸手機必須以13x,15x開頭,不然非法。過濾一些些常見的敏感字符,例如:
< > ‘ 「 & # \ javascript expression "onclick=" "onfocus"
過濾或移除特殊的Html標籤, 例如:
<script>, <iframe> , < for <, > for >, " for
過濾JavaScript 事件的標籤,例如 "onclick=", "onfocus" 等等。
通常來講,除了富文本的輸出外,在變量輸出到HTML頁面時,可使用編碼(HtmlEncode)或轉義的方式來防護XSS攻擊。
把變量輸出到頁面時要作好相關的編碼轉義工做,如要輸出到 <script>中,能夠進行JS編碼;要輸出到HTML內容或屬性,則進行HTML編碼處理。根據不一樣的語境採用不一樣的編碼處理方式。
將重要的cookie標記爲http only, 這樣的話當瀏覽器向Web服務器發起請求的時就會帶上cookie字段,可是在腳本中卻不能訪問這個cookie,這樣就避免了XSS攻擊利用JavaScript的document.cookie獲取cookie:
CSRF原理比較簡單,如圖
用戶C打開瀏覽器,訪問受信任網站A,輸入用戶名和密碼請求登陸網站A;
在用戶信息經過驗證後,網站A產生Cookie信息並返回給瀏覽器,此時用戶登陸網站A成功,能夠正常發送請求到網站A;
用戶未退出網站A以前,在同一瀏覽器中,打開一個TAB頁訪問網站B;
網站B接收到用戶請求後,返回一些攻擊性代碼,併發出一個請求要求訪問第三方站點A;
瀏覽器在接收到這些攻擊性代碼後,根據網站B的請求,在用戶不知情的狀況下攜帶Cookie信息,向網站A發出請求。網站A並不知道該請求實際上是由B發起的,因此會根據用戶C的Cookie信息以C的權限處理該請求,致使來自網站B的惡意代碼被執行。
假設用戶在A網站能夠刪除本身的文章,其請求地址相似http://xxx.com/del.do?id=101。而且已經登陸。
攻擊者先構造一個本身的網頁csrf.html,其內容爲
<img src="http://xxx.com/del.do?id=102">
攻擊者誘使目標用戶C訪問該頁面,以後再回去查看本身的文章,發現id爲102的文章被刪除了。
原來在剛纔訪問csfr.html時,圖片標籤發送了一次請求,致使該文章被刪除。
由於csrf攻擊是在用戶不知情的狀況下發起請求。驗證碼則強制用戶與應用交互。
可是出於用戶體驗考慮,網站不能給全部操做都加驗證碼。因此驗證碼只能做爲一種輔助手段。
根據HTTP協議,在HTTP頭中有一個字段叫Referer,它記錄了該HTTP請求的來源地址。在一般狀況下,訪問一個安全受限頁面的請求必須來自於同一個網站。
在互聯網中,Referer Check的常見用法是防止圖片盜鏈。同理也能夠檢查請求是否來自合法的源。
某銀行的轉帳是經過用戶訪問 http://bank.test/test?page=10&userID=101&money=10000 頁面完成,用戶必須先登陸bank.test,而後經過點擊頁面上的按鈕來觸發轉帳事件。當用戶提交請求時,該轉帳請求的Referer值就會是轉帳按鈕所在頁面的URL(本例中,一般是以bank.test域名開頭的地址)。而若是攻擊者要對銀行網站實施CSRF攻擊,他只能在本身的網站構造請求,當用戶經過攻擊者的網站發送請求到銀行時,該請求的Referer是指向攻擊者的網站,則銀行網站拒絕該請求。
CSRF攻擊之因此可以成功,是由於攻擊者能夠僞造用戶的請求,該請求中全部的用戶驗證信息都存在於Cookie中,所以攻擊者能夠在不知道這些驗證信息的狀況下直接利用用戶本身的Cookie來經過安全驗證。
由此可知,抵禦CSRF攻擊的關鍵在於:在請求中放入攻擊者所不能僞造的信息,而且該信息不存在於Cookie之中。鑑於此,系統開發者能夠在HTTP請求中以參數的形式加入一個隨機產生的token,並在服務器端創建一個攔截器來驗證這個token,若是請求中沒有token或者token內容不正確,則認爲多是CSRF攻擊而拒絕該請求。
點擊劫持,這個術語是Robert Hansen 和 Jeremiah Grossman這2位安全研究專家給出的;其實在2008年9月,Adobe公司就發表了一份公開演講,關於點擊劫持問題的,由於其Flash產品的缺陷能夠被嚴重的惡意利用。
點擊劫持/UI重定向,是指惡意網站僞造一個看似可信的元素(如PayPal的donate按鈕,或一個Send按鈕-by Gmail等你可能使用的郵箱網站),根據RSnake and Jeremiah的調查證實,用戶點擊這些貌似可信的Sites的任何元素均可能觸發你的話筒或者攝像頭,遠程攻擊者可同時當即對你進行監控。
更經常使用的方法是,攻擊者在他控制的網站用框架包含一個可信Sites,剝除掉上下文或者透明化這個Sites,這樣他就能夠輕易的操控你,而你最後可能就是給他發送轉帳,或者給他任何特權,而這些操做用戶是徹底不知曉的,後臺進行;更甚的,若是這個惡意站點容許使用JS,那麼攻擊者能夠及其輕鬆的把隱藏的元素精確地放置在鼠標指針下,這樣的話無論用戶點哪兒,攻擊者都贏了;更更有甚的,攻擊者能夠在JS被禁用的狀況下進行欺騙,只須要騙取用戶點擊一個連接或者按鈕。
注意:點擊劫持在任何瀏覽器上都存在,由於點擊劫持不是瀏覽器漏洞或者Bug形成的,不能一晚上就打上補丁;相反,點擊劫持是利用最基本的標準Web特色,在任何位置都能實現,而這種自然缺陷是沒法在短期內改善的。
點擊劫持是一種視覺上的欺騙手段。大概有兩種方式,一是攻擊者使用一個透明的,不可見的iframe,覆蓋在一個網頁上,而後誘使用戶在該頁面上進行操做,此時用戶將在不知情的狀況下點擊透明的iframe頁面,能夠誘使用戶剛好點擊在iframe頁面的一些功能性按鈕上;二是攻擊者使用一張圖片覆蓋在網頁,遮擋網頁原有位置的含義。
先寫一個src.html,模擬源網頁。
<!DOCTYPE HTML> <html> <head> <title>原頁面</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <style> button{ position:absolute; top: 315px; left: 462px; z-index: 1; width: 72px; height: 26px; } </style> </head> <body> <button onclick="func()">加關注</button> </body> <script> function func(){ alert("關注成功!"); } </script> </html>
這個頁面有一個按鈕,點擊後觸發事件。
再寫一個jack.html,劫持頁面。
<!DOCTYPE HTML> <html> <head> <title>點擊劫持</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <style> html,body,iframe{ display: block; height: 100%; width: 100%; margin: 0; padding: 0; border:none; } iframe{ opacity:0; filter:alpha(opacity=0); position:absolute; z-index:2; } button{ position:absolute; top: 335px; left: 462px; z-index: 1; width: 72px; height: 26px; } </style> </head> <body> 那些不能說的祕密 <button>查看詳情</button> <iframe src="src.html"></iframe> </body> </html>
這個頁面用一個按鈕覆蓋了原網頁的按鈕,用戶點擊後,實際就點擊到了原網頁的按鈕。
將透明度調一下查看按鈕佈局
先在以前的src.html中加入一個logo圖片
在jack.html中一樣添加一個圖片
調解透明度能夠看到背後實際狀況
假如LOGO圖片對應的連接是某個網站,那麼用戶點擊該圖片,就會被連接到假的網站上。
圖片也能夠假裝得像正常的連接,按鈕;或者圖片中構造文字,覆蓋在關鍵位置,可能會改變原有的意思。這種狀況下,不須要用戶點擊,也能達到欺騙的目的,好比覆蓋了頁面的聯繫電話。
一般能夠寫一段JavaScript代碼,以禁止iframe的嵌套。
if(top.location != location){ top.location = self.location; }
在src中加入該代碼,再訪問jack.html,發現瀏覽器自動跳轉到了src.html。
因爲是用JavaScript寫的,這樣的控制能力不是特別強,有許多方法能夠繞過它。一個更好的方案是使用一個HTTP頭——X-Frame-Options。
X-Frame-Options能夠說是爲了解決ClickJacking而生的。
它有三個可選值
因爲<img>標籤在不少系統中是對用戶開放的,所以在現實中有很是多的站點存在被圖片覆蓋攻擊的可能。在防護時,須要檢查用戶提交的html代碼中,<img>標籤的style屬性是否可能致使浮出。
經過把SQL命令插入到Web表單遞交或輸入域名或頁面請求的查詢字符串,最終達到欺騙服務器執行惡意的SQL命令。
具體來講,它是利用現有應用程序,將(惡意)的SQL命令注入到後臺數據庫引擎執行的能力,它能夠經過在Web表單中輸入(惡意)SQL語句獲得一個存在安全漏洞的網站上的數據庫,而不是按照設計者意圖去執行SQL語句。
好比咱們開發了一個登錄模塊,查詢語句是
select * from user where name = ${name} and password = ${password};
正常狀況下,咱們拿到用戶輸入的用戶名和密碼拼接出來的語句是
select * from user where name = "admin" and password = "123456";
若是用戶輸入用戶名爲 "xxx" or 1 #,密碼隨便。那麼拼接的語句就變成了
select * from user where username = "xxx" or 1 # and password = "123456";
"#"會使後面的and password = "123456"變成註釋,這個語句會查詢出全部用戶,因此驗證經過,成功登錄了系統。
通常來講,從如下幾點防範sql注入。
校驗用戶的輸入
拿到用戶數據後,能夠經過正則表達式,限制長度,對引號和"-","#"進行轉換或過濾等。
使用預處理語句
不要使用動態拼裝SQL,而是使用參數化的SQL或者直接使用存儲過程進行數據查詢存取。
好比以前的例子,在mybatis中,若是使用#{}代替${},編寫的sql以下
select * from user where name = #{name} and password = #{password};
這句話會在程序運行時會先編輯成帶參數的sql語句
select * from user where name = ? and password = ?;
當用戶輸入 "xxx" or 1 # 時,實際語句
select * from user where name = "'xxx' or 1 #" and password = "123456";
這樣是查不到用戶的,因此登錄失敗。
固然有些地方必須使用$,好比order by name desc,這裏的name desc都是傳參進來的,直接按照參數字符串自己的含義。
select * from gooods order by ${param};
這種狀況下,咱們必須嚴格控制傳進來的參數。後臺最好寫方法確保參數正常。好比
//檢驗排序字段 private String orderColumn(String orderColumn){ //定義或獲取可用排序字段集 //斷定外部傳進來的參數字段是否存在於字段集中 //若是存在,返回正確結果字段,不存在可拋出錯誤。 } //檢驗排序順序 private String orderStringtoOrder(String orderString){ String order = "asc"; if(!orderString.isEmpty() && orderString.equals("desc")){ order = "desc"; } return order; }
嚴格控制排序參數的正確性。
最小權限策略
不要使用管理員權限的數據庫鏈接,爲每一個應用使用單獨的權限有限的數據庫鏈接,保證其正常使用便可。
這麼作的好處是,即便當前用戶被攻破了,入侵者只能獲取極小一部分權限,防止危害擴大。
加密信息
不要把密碼等機密信息明文存放,加密或者hash掉密碼和敏感的信息。
異常提醒
有些應用直接返回了異常信息給用戶頁面,這是很不安全的,經過這些異常信息,使用者能夠知道程序棧,數據庫類型甚至版本號等信息,這將有利於其進一步攻擊。
應用的異常信息應該給出儘量少的提示,最好使用自定義的錯誤信息對原始錯誤信息進行包裝,把異常信息存放在獨立的表中。
參考書籍: 白帽子講Web安全 參考連接: http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html http://blog.csdn.net/baidu_24024601/article/details/51957270 http://www.cnblogs.com/lovesong/p/5248483.html http://blog.csdn.net/stilling2006/article/details/8526458 http://blog.csdn.net/baochao95/article/details/52025180