XSS與CSRF攻擊


一、XSS

Cross Site Script,跨站腳本攻擊。是指攻擊者在網站上注入惡意客戶端代碼,通過惡意腳本對客戶端網頁進行篡改,從而在用戶瀏覽網頁時,對用戶瀏覽器進行控制或者獲取用戶隱私數據的一種攻擊方式。

1.容易發生的場景

(1)數據從一個不可靠的鏈接進入到一個web應用程序。

(2)沒有過濾掉惡意代碼的動態內容被發送給web用戶。

2.XSS攻擊的共同點

將一些隱私數據如cookie、session發送給攻擊者,將受害者重定向到一個由攻擊者控制的網站,在受害者機器上進行惡意操作。

3.XSS攻擊的類型

分為存儲性(持久型)、反射型(非持久型)、基於DOM

(1)反射型

反射型XSS攻擊把用戶輸入的數據"反射"給瀏覽器。該攻擊方式通常誘使用戶 點擊一個惡意鏈接,或者 提交一個表單, 在用戶點擊鏈接或提交表單的同時向用戶訪問的網站注入腳本。

實踐:模擬反射型XSS攻擊

在正常頁面上添加一個惡意鏈接。惡意鏈接的地址指向localhost:3000。

然后攻擊者有一個node服務來處理對localhost:3000的請求:

const Koa = require('koa');
const Router = require('koa-router');
const app = new Koa();
const router = new Router();

router.get('/', async ctx => {
  ctx.body = '<script>alert("XSS攻擊")</script>';
});

app.use(router.routes())
app.listen('3000', ()=> {
  console.log('Listening 3000');
});

當用戶點擊惡意鏈接時,頁面跳轉到攻擊者預先准備的頁面,會發現在攻擊者的頁面執行了 js 腳本。這樣就產生了反射型 XSS 攻擊。攻擊者可以注入任意的惡意腳本進行攻擊,可能注入惡作劇腳本或注入能獲取用戶隱私數據(如cookie)的腳本。

(2)存儲型

存儲型XSS把用戶輸入的帶有惡意腳本的數據存儲在服務器端。當瀏覽器請求數據時,服務器返回腳本並執行。

常見的場景是攻擊者在社區或論壇上寫下一篇包含惡意 JavaScript 代碼的文章或評論,文章或評論發表后,所有訪問該文章或評論的用戶,都會在他們的瀏覽器中執行這段惡意的 JavaScript 代碼。

實踐:模擬存儲型XSS攻擊

例如在一個論壇評論輸入框內寫下:

<script>alert("XSS攻擊")</script>

該內容提交后會保存至該論壇數據庫。而該論壇顯示評論的頁面則會把各用戶提交的評論內容輸出。例如顯示評論頁面可能是這樣的:

<div>
  <p>用戶1</p>
  <div>哈哈哈說得真好</div>
</div>
<div>
  <p>用戶2</p>
  <div>贊同</div>
</div>
<div>
  <p>XSS攻擊者</p>
  <div><script>alert("XSS攻擊")</script>
</div>
</div>

其他用戶訪問該評論顯示頁面時,惡意腳本就會在瀏覽器端執行。

(4) 基於DOM

基於DOM的XSS是指通過惡意腳本修改頁面的DOM結構。是純粹發生在 客戶端的攻擊。

實踐:模擬基於DOM的XSS攻擊

某正常網站的內容會顯示url地址的中的參數。例如url為:

http://xxx.com?name=abc

其頁面smarty模板為:

<div><%$smarty.get.name%></div>

得到頁面為:

<div>abc</div>

那么XSS攻擊者可以制作出這樣的鏈接;

http://xxx.com?name=<script>alert("XSS攻擊")</script>

那么其頁面最終得到的是:

<div>
  <script>alert("XSS攻擊")</script>
</div>

如果其他用戶點擊了XSS攻擊者構造的鏈接,那么頁面中就多了一段可執行腳本。這種攻擊也可以說是反射型的。

4.XSS攻擊的防范

(1) 現代主流瀏覽器內置CSP

內容安全策略(CSP)用於檢測和減輕用於 Web 站點的特定類型的攻擊,例如 XSS 和數據注入等。

CSP本質上是建立白名單,規定了瀏覽器只能執行特定來源的代碼。

通過 Content-Security-PolicyHTTP頭來開啟CSP:

  • 只允許加載本站資源Content-Security-Policy: default-src 'self'
  • 只允許加載HTTPS協議圖片
    Content-Security-Policy: img-src https://*
  • 允許加載任何來源框架 Content-Security-Policy: child-src 'none'

(2) HttpOnly阻止Cookie劫持攻擊

為避免跨域腳本 (XSS) 攻擊,通過JavaScript的 Document.cookie API無法訪問帶有 HttpOnly 標記的Cookie,它們只應該發送給服務端。如果 Cookie 不想被客戶端 JavaScript 腳本調用,那么就應該為其設置 HttpOnly 標記。

如上所述,發起XSS的攻擊者既然可以通過注入惡意腳本獲取用戶的 Cookie 信息。所以,嚴格來說,HttpOnly 並非阻止 XSS 攻擊,而是能阻止 XSS 攻擊后的 Cookie 劫持攻擊。

含有HttpOnly標志的Cookie在HTTP響應頭Set-Cookie:

Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly
實踐

設置含有HttpOnly標志的Cookie:

document.cookie = encodeURIComponent('name')+ '=' + encodeURIComponent('BnnieWang') + ';secure;HttpOnly'
//"name=BnnieWang;secure;HttpOnly"

驗證:執行上述代碼后輸入document.cookie,可以看到得到的cookie中沒有剛剛設置的這個cookie。

Tips: Koa的ctx.cookies.set()方法是默認httpOnly為true

對比cookie的secure標記

標記為 Secure 的Cookie只能通過被HTTPS協議加密過的請求發送給服務端。

但即便設置了 Secure 標記,敏感信息也不應該通過Cookie傳輸,因為Cookie有其固有的不安全性,Secure 標記也無法提供確實的安全保障。也就是說,即使設置了Secure標志,還是可以從前端通過document.cookie獲取該cookie。從 Chrome 52 和 Firefox 52 開始,不安全的站點(http:)無法使用Cookie的 Secure 標記。

(3) 輸入檢查/XSS Filter

對於用戶的任何輸入要進行檢查、過濾和轉義。一般是檢查用戶輸入的數據中是否包含 <,>,script 等特殊字符,如果存在,則對特殊字符進行過濾或編碼。

前端框架中自帶的decodingMap

一些前端框架中,都有一份decodingMap,會對用戶輸入所包含的特殊字符或標簽進行編碼或過濾,以防止XSS攻擊。例如vue中的decodingMap:

// 在 vuejs 中,如果輸入帶 script 標簽的內容,會直接過濾掉

const decodingMap = {

  '&lt;': '<',

  '&gt;': '>',

  '&quot;': '"',

  '&amp;': '&',

  '

  ': '\n'
}


手動對輸入內容進行轉義:
function escape(str) {
  str = str.replace(/&/g, '&amp;');
  str = str.replace(/</g, '&lt;');
  str = str.replace(/>/g, '&gt;');
  str = str.replace(/"/g, '&quto;');
  str = str.replace(/'/g, '&##39;');
  str = str.replace(/\//g, '&##x2F;')
}

通過轉義攻擊腳本:

<script>alert("XSS攻擊")</script>

可轉變為字符串:

&lt;script&gt;alert(&quto;XSS攻擊;&quto;)&lt;&##x2F;script&gt;

注意:富文本顯示的轉義

對於顯示富文本來說,不能用上述方法轉義所有字符,因為這樣會把需要的格式也去掉。例如會把< h1>標題 < /h1>也轉義掉。這種方法通常采用白名單過濾的辦法,把需要的標簽(如< h1>)保留。

例如使用'xss'庫:

const xss = require('xss');
const html = xss('<h1>XSS Demo</h1><script>alert("xss");</script>');
console.log(html)// <h1>XSS Demo</h1>&lt;script&gt;alert("xss");&lt;/script&gt;

這樣就在過濾了script標簽的同時保留了h1標簽。

(4)輸出檢查

在變量輸出到 HTML 頁面時,也可以使用上述(3)類似的編碼或轉義的方式來防御 XSS 攻擊。

二、CSRF

Cross Site Request Forgery,跨站請求偽造。是劫持受信任用戶向服務器發送非預期請求的攻擊方式。例如,這些非預期請求可能在url后加入一些惡意的參數,從而達到攻擊者的目的。

通常情況下,CSRF 攻擊是攻擊者借助受害者的 Cookie 騙取服務器的信任,可以在受害者毫不知情的情況下以受害者名義偽造請求發送給受攻擊服務器,從而在並未授權的情況下執行在權限保護之下的操作。

簡單來說,CSRF就是利用用戶的登錄態發起惡意請求

假設有一個 bbs 站點:http://www.c.com,當登錄后的用戶發起如下 GET 請求時,會刪除 ID 指定的帖子:

http://www.c.com:8002/content/delete/:id

如發起 http://www.c.com:8002/content/delete/87343 請求時,會刪除 id 為 87343 的帖子。當用戶登錄之后,服務器會設置如下 cookie並發送到瀏覽器:

  res.setHeader('Set-Cookie', ['user=22333; expires=Sat, 21 Jul 2018 00:00:00 GMT;']);

然后CSRF 攻擊者准備了一個頁面http://www.a.com:

<p>CSRF 攻擊者准備的網站:</p>

<img src="http://www.c.com:8002/content/delete/87343">

該頁面使用了一個 img 標簽,其地址指向了刪除用戶帖子的鏈接:http://www.c.com:8002/content/delete/87343

可以看到,當登錄用戶訪問攻擊者的網站時,會向 www.c.com 發起一個刪除用戶帖子的請求。由於用戶已經登錄,則www.c.com下已經存在了該user=22333的cookie,那么刪除請求就會順利進行。此時若用戶在切換到 www.c.com 的帖子頁面刷新,會發現ID 為 87343 的帖子已經被刪除。

這個攻擊過程中,攻擊者借助受害者的 Cookie 騙取服務器的信任,但並不能拿到 Cookie,也看不到 Cookie 的內容。而對於服務器返回的結果,由於瀏覽器同源策略的限制,攻擊者也無法進行解析。因此,攻擊者無法從返回的結果中得到任何東西,他所能做的就是給服務器發送請求,以執行請求中所描述的命令,在服務器端直接改變數據的值,而非竊取服務器中的數據。

若 CSRF 攻擊的目標並不需要使用 Cookie,則也不必顧慮瀏覽器的 Cookie 策略了。

2. CSRF的防范

防范CSRF可遵循以下幾種規則:

  • Get 請求不對數據進行修改
  • 不讓第三方網站訪問到用戶Cookie
  • 阻止第三方網站請求接口
  • 請求時附帶驗證信息,如驗證碼或Token

(1)驗證碼

CSRF攻擊往往是在用戶不知情的情況下發起了網絡請求。而驗證碼會保證用戶必須與應用進行交互,才能完成請求。

(2)Referer Check

在HTTP頭中有一個字段叫做Referer,它記錄了該HTTP請求的來源地址。通過Referer Check,可以檢查是否來自合法的"源".

實踐

以上例來說,如果是從www.c.com發起的刪帖請求,那么Referer值是http://www.c.com, 刪帖請求應該被允許;而如果是從CSRF攻擊者構造的頁面www.a.com發起刪帖請求, 那么Referer值是http://www.a.com, 刪帖請求應該被阻止。故只需要對每一個刪帖請求驗證其Referer即可防止CSRF攻擊。

服務端驗證Referer的代碼:

const app = new Koa();
const router = new Router();

router.get('/', async ctx => {
  if (ctx.headers.referer !== 'http://www.c.com:8002/') {
    ctx.body = 'csrf攻擊'
  }
});

(3)請求地址添加token驗證

可以在 HTTP 請求中以參數的形式加入一個隨機產生的 token,並在服務器端建立一個攔截器來驗證這個 token,如果請求中沒有 token 或者 token 內容不正確,則認為可能是 CSRF 攻擊而拒絕該請求。

CSRF 攻擊之所以能夠成功,是因為攻擊者可以完全偽造用戶的請求,該請求中所有的用戶驗證信息都是存在於 Cookie 中,因此攻擊者可以在不知道這些驗證信息的情況下直接利用用戶自己的 Cookie 來通過安全驗證。要抵御 CSRF,關鍵在於在請求中放入攻擊者所不能偽造的信息,並且該信息不存在於 Cookie 之中。為請求添加token驗證可以很好地做到這一點。

給Cookie設置SameSite屬性。這樣服務器可以要求某個cookie在跨站請求時不會被發送,從而可以阻止跨站請求偽造攻擊(CSRF)。但目前SameSite Cookie還處於實驗階段,並不是所有瀏覽器都支持。

三、XSS與CSRF的對比總結

  • XSS是利用用戶對指定網站的信任
  • CSRF是利用網站對用戶的信任

參考資料

https://mp.weixin.qq.com/s?__biz=MzAxODE2MjM1MA==&mid=2651554578&idx=1&sn=89a1743e018bf221688172c96bb4e866&pass_ticket=6PzWxTA51OOBq1JgjhHUaRahdKfET6zcK10abJElQxXb2%2BQmGJQBCisOE3z%2B53bb

https://developer.mozilla.org/zh-CN/docs/Glossary/CSP

https://developer.mozilla.org/zh-CN/docs/Glossary/Cross-site_scripting

https://developer.mozilla.org/zh-CN/docs/Glossary/CSRF

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Cookies


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM