今天呀,我想當一名黑客,去黑別人的網站!我有兩三技能,獨樂不如眾樂樂,今天我也把這個幾個攻擊手段教給你,咱們一起搞事情去。
首先我們來了解一下攻擊手段,也是比較常見的兩種攻擊手段了:
- CSRF
- XSS
CSRF
全稱:Cross-site request forgery,跨站請求偽造。原理是:通過偽裝成受信任用戶的請求來攻擊受信任的網站。
如何偽裝?如何才算攻擊?
生活中其實我們不缺這種例子,比如說我們經常接收到一些來歷不明的垃圾簡訊,簡訊內容裡面有個url連結,有些人手賤點開了連結,然後就發現錢不見了!!
我們從技術角度來復原一下這個過程,首先設定一些基礎:
- 垃圾簡訊里的連結(垃圾網):http://www.lajiwang.com/pianqian
- 存了錢的網站(存錢網):http://www.cunqianwang.com/
然後用戶動作是:點開了垃圾網的連結,但是存錢網裡帳戶的錢不見了。既然是自己帳戶的錢不見了,所以這裡其實有個前提:用戶已經登錄了存錢網!所以準確來說用戶的動作是這樣的:點開了垃圾網的連結,但是之前登錄過的存錢網裡帳戶的錢不見了!
兩個網站毫無關聯,為啥會造成這個讓人意想不到的後果呢?
其實呀,垃圾網的人為了達到攻擊的目的,偷偷在網頁上嵌入了存錢網的連結,所以打開垃圾網時候順便也觸發了存錢網的轉帳的連結,整體邏輯如下:
- 1、用戶登錄成功存錢網,於是瀏覽器中產生了網站cookie
- 2、用戶在沒有退出存錢網的情況下,訪問了垃圾網
- 3、垃圾網要求訪問存錢網的轉帳url,轉帳url帶上存錢網的cookie去訪問伺服器
- 4、存錢網伺服器驗證轉帳url確認是用戶在轉帳,轉帳成功!
說到這裡,你發現漏洞在哪裡沒有?大家都知道cookie代表用戶身份,每次發起請求,請求頭裡都會附上用戶的cookie信息,既然cookie是存在瀏覽器的,我偷不到你的cookie,那麼我就讓你在不知道到的情況下讓你自己去操作。
舉個例子:假如一家銀行轉帳操作的URL地址如下:
http:
//www.cunqianwang.com/zhuanzhang?account=A&for=B&amount=500
那麼,一個垃圾網中可以放置如下代碼
src
=
"http://www.cunqianwang.com/zhuanzhang?account=A&for=B&amount=500"
>
好了,原理和攻擊手段我們都懂了,那麼我們來說說幾種常見的預防手段:
1、檢查referer欄位
HTTP頭中有一個Referer欄位,這個欄位是用來標明請求來源於哪一個網址。當網站A去訪問網站B的資源時候,連結上的請求頭上就會有Referer欄位。注意是在不同域名下才有。
我隨意打開hao123.com的首頁,一些圖片不是放在hao123.com域名下的,所以會在header中帶上Referer欄位表示請求源是hao123.com。
那麼伺服器可以通過判斷Referer欄位來判斷請求的來源。所以在垃圾網站里訪問存錢網,Referer的值就是垃圾網的域名,就能判斷是不是合法的操作啦。
java代碼里獲取Referer欄位值代碼是:
String
referer = request.getHeader(
"Referer"
);
這種方法簡單易行,但也有其局限性。http協議無法保證來訪的瀏覽器的具體實現,可以通過篡改Referer欄位的方式來進行攻擊,所以就要看你用的瀏覽器高級不高級了,如果你用的瀏覽剛好是騙子開發的瀏覽器,嘿嘿~~
2、Token 驗證
既然我們要判定用戶行為的合法性,那麼我就給用戶頒發一個合法token,除了帶上cookie,還得帶上token才行,token在前一個步驟中獲取。
邏輯如下:
- 伺服器發送給客戶端一個token;
- 客戶端提交的表單中帶著這個token。
- 如果這個 token 不合法,那麼伺服器拒絕這個請求。
3、添加圖片驗證碼、簡訊驗證等
重要步驟添加驗證碼認證後才能操作。腦補,略略略略~
學會攻擊
好了,作為一名出色的黑客,必須要知道自己攻擊手段的漏洞在哪,怎麼防禦,絕不做無用功!既然預防手段我知道了,那麼接下來就是我展現真正技術的時候了。
嘿嘿,很多公司在一開始的時候為了節約成本,選擇用開源項目作為基礎,然後再二次開發。雖說開發快,但其實未必安全,一些開源項目如果沒有做csrf的預防,那麼漏洞就一直存在。
經過我多天的研究,終於發現了某個商城用的是開源項目二次開發的,沒有csrf預防。商城的積分可以直接贈送給別人,我立馬搞了個網頁,嵌入網站贈送積分的連結。
於是有了我和我朋友的對白。
- 我:小明呀,你的A商城還有多少積分呀?
- 小明:2000多吧?
- 我:這麼多?我不信!你登錄讓我看看!
- 小明去登錄A網站給我看積分,果然2000多。
- 我:小明呀,我開發了個網站,我發給你看看能不能打開
- 小明打開網站,小明的積分到我帳戶了~
當黑客感覺真好,小明,你是個好人~
XSS
全程:Cross Site Scripting,中文:跨域腳本攻擊。原理:不需要你做任何的登錄認證,通過合法的操作(比如在url中輸入、在評論框中輸入),向你的頁面注入腳本(可能是js、hmtl代碼塊等),類似於SQL注入。
通俗點講就是:惡意攻擊者往Web頁面里插入惡意html代碼,當用戶瀏覽該頁之時,嵌入其中Web裡面的html代碼會被執行,從而達到惡意用戶的特殊目的。
講再細點其實就是:利用輸入內容來閉合對應的html標籤,從而執行輸入內容的腳本。
攻擊形態
xss有兩種形態(網友總結):
- 1、反射型
發出請求時,XSS代碼出現在url中,作為輸入提交到伺服器端,伺服器端解析後響應,XSS代碼隨響應內容一起傳回給瀏覽器,最後瀏覽器解析執行XSS代碼。這個過程像一次反射,所以叫反射型XSS。
- 2、存儲型
存儲型XSS和反射型XSS的差別在於,提交的代碼會存儲在伺服器端(資料庫、內存、文件系統等),下次請求時目標頁面時不用再提交XSS代碼。
攻擊手段
不管是什麼類型,你get到關鍵點沒有?關鍵點以及技術難點其實在於如何往頁面中嵌入惡意的代碼。
下面我們來寫個例子模擬一下:首先我頁面寫了個form表單:
- index.ftl
controller中有個基本跳轉,還有form表單的提交:
- com.example.IndexController#index
@GetMapping
(
""
)
public
String
index(
HttpServletRequest
request) {
request.setAttribute(
"name"
,
"公眾號:java思維導圖"
);
return
"index"
;
}
@PostMapping
(
"/submit"
)
public
String
submit(
HttpServletRequest
request) {
String
name = request.getParameter(
"name"
);
System
.
out
.println(
"name---------->"
+ name);
// 假裝只有名字為「求關注」才能通過
if
(!name.equals(
"求關注"
)) {
request.setAttribute(
"name"
, name);
}
return
"index"
;
}
初始效果如下:
ok,基本邏輯也寫好了,一個簡單的表單提交,提交之後如果數據不對,或格式不對就會返回表單頁面,同時回顯表單數據。
加入我想嵌入腳本如下:
那麼我該怎麼樣才能往這個頁面上嵌入代碼呢?我打開F12,研究一下
要是這個這個腳本能提到input的外面,value能提前結束就好了。嘿嘿,突然想到,既然我改不了原來的,那麼我就創造一個。
於是我改了一下輸入的值成:
">
這">不就跑到前面了嘛,哈哈哈,天才,我趕緊試試。谷歌瀏覽器測試結果如下:
腳本的確跑到外面了,但是alert(1)怎麼不見了呀,我趕緊調試一下:
不是後端在搞事情,那麼真相就只有一個,谷歌瀏覽器在搞事情,谷歌果然強大,還能辨別我的腳本並和諧掉。
我換個Edge瀏覽器再試試:
哇,果然Edge你最帥,我想要的你都給我~ F12看下:
沒毛病,原聲原味的alert(1);
好了上面我們已經弄懂了xss的嵌入腳本的方式,我們輸入是合法的,只是內容有點取巧,這就是xss的攻擊手段。
除了這個input標籤,其實還有很多標籤比較常用,比如title、a、img、script等。
上面這個一般都是反射性的xss攻擊,我們再來看看一個存儲類型的title的例子。
在很多博客中,我們都可以發布文章,我們需要寫文章標題,文章內容等,文章標題一般我們還會放在我們的head的title中,用於標籤展示當前瀏覽文章標題。
加入說,我們的頁面是這樣展示的:
- title.ftl
${title}
這是內容 - ${content}
而controller中傳過來的內容如下:
- IndexController
@GetMapping
(
"/title"
)
public
String
title(
HttpServletRequest
request) {
request.setAttribute(
"title"
,
""
);
request.setAttribute(
"content"
,
"內容是關注公眾號:java思維導圖"
);
return
"title"
;
}
最後我們的得到的頁面展示這樣子:加載時候先執行彈窗:alert("公眾號java思維導圖");然後再加載內容。
因為一般我們文章標題內容都是保存到資料庫的,所以每次渲染都會執行腳本,所以是個存儲型xss攻擊。
解決方法
好了,看了我們的例子項目,我們已經意識到了xss攻擊的可怕性,一單發布文章都可以寫腳本,那麼所有的用戶打開這篇文章都會被執行腳本,影響可就大了。那麼有什麼好的解決方法嗎?
這裡給大家介紹幾個解決方法。我們先來看renren-fast項目是怎麼解決這個問題的:
- renren-fast
#識別攻擊腳本、並刪掉對應可執行腳本的標籤
HTMLFilter
#全局過濾器,包裝request
XssFilter
#包裝request,重寫request的幾個重要方法,比如getParameter等
XssHttpServletRequestWrapper
所以renren-fast項目的設計邏輯是加入一個全局過濾器,然後通過包裝請求的request,重寫request的getParameter、getHeader、getInputStream等方法,在這些方法裡面都進行一遍過濾,從而去掉所有的攻擊腳本。看看重要代碼:
- io.renren.common.xss.XssFilter
public
class
XssFilter
implements
Filter
{
public
void
doFilter(
ServletRequest
request,
ServletResponse
response,
FilterChain
chain)
throws
IOException
,
ServletException
{
XssHttpServletRequestWrapper
xssRequest =
new
XssHttpServletRequestWrapper
(
(
HttpServletRequest
) request);
chain.doFilter(xssRequest, response);
}
...
}
- io.renren.common.xss.XssHttpServletRequestWrapper
public
class
XssHttpServletRequestWrapper
extends
HttpServletRequestWrapper
{
@Override
public
String
getParameter(
String
name) {
String
value =
super
.getParameter(xssEncode(name));
if
(
StringUtils
.isNotBlank(value)) {
value = xssEncode(value);
}
return
value;
}
...
}
可以看到上面的xssEncode就是進行過濾腳本的方法;xssEncode方法代碼如下:
private
String
xssEncode(
String
input) {
return
htmlFilter.filter(input);
}
ok,相信你已經弄明白了。
我們來看看另一個博客項目mblog的解決方法:
- mblog
#通用控制器
BaseController
#自定義編輯器
StringEscapeEditor
mblog項目其實是通過註冊所有controller的自定義編輯器,在提交表單時候對所有欄位都進行一層get和set,在set的過程中對輸入內容進行一番檢查,如果有腳本就進行替換等操作。
詳細代碼如下:
- BaseController
@InitBinder
public
void
initBinder(
ServletRequestDataBinder
binder) {
/**
* 防止XSS攻擊
*/
binder.registerCustomEditor(
String
.
class
,
new
StringEscapeEditor
(
true
,
false
));
...
}
@InitBinder用於表單到方法的數據綁定的,這裡綁定了一個自定義編輯器StringEscapeEditor。
- StringEscapeEditor
可以看到setAsText中就是對腳本進行過濾等操作的。
這兩種方法都學會了嗎?其實邏輯都是對腳本進行過濾替換刪除等操作。
學會攻擊
好了,又到了黑客show time,某個知名博客平台沒防禦xss攻擊,這時候我發布了一篇文章,title中包含了腳本