# Same-Origin Policy, CORS and CSRF
## Same-Origin Policy
Same-Origin Policy 同源政策是網路網路安全建立的基礎。用來限制不同網域間資源的互動。
Origin 是由三個部分所組成所組成。
- Protocol 像是:http, https (兩者不一樣)
- Hostname 在這裡指的是 full domain name
- Port 即是 domain name 後面接的 port
Same-Origin 同源是對網頁( Web Page )來說以上三者都要相同,就稱為同源。
Example: 取自 [MDN](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Same_origin_policy_for_JavaScript)
![](https://i.imgur.com/bNCvyhv.png)
另外,subdomain 也會被視為是不同的來源。但是有方法將他們設定為同源:
```
在 subdomain 以及 原本的網頁都設置
document.domain = "company.com";
```
但是要注意,透過 document.domain 這種方式設定時,port 預設為 **null**
同源政策原本是用來防止存取其他網站的 DOM,目前除了 DOM 之外,還限制以下存取權限:
- Cookies
- LocalStorage
- IndexedDB
- Ajax
舉例:如果我們要透過 ajax 發送 XMLHttpRequest (XHR) 請求其他網域的資源,會被禁止。
![](https://i.imgur.com/y8EdPGv.jpg)
有沒有什麼方法是可以不被同源政策限制的?
1. JSONP
2. Websocket
3. CORS
4. Cross-document messaging。
JSONP 因為是使用 <script src=""></script> 的方式來存取,所以一定只能發送 GET method ( 由此可知你知道 script tag 可以 cross origin。)
![](https://i.imgur.com/0xIKqHS.png)
example: https://www.w3schools.com/js/js_json_jsonp.asp
可以跨源的 html tag 還有哪些?
https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Same_origin_policy_for_JavaScript
## CORS (Cross-Origin Resource Sharing)
讀音似 course
這就是一種可以讓跨站存取的方式,讓 Ajax 發送的 XMLHttpRequest (XHR) 可以跨站存取資源。
![](https://i.imgur.com/8fkNMWf.png)
假設 `origin-domain` 網域上的網頁內容想要呼叫 `other-domain` 網域內的內容,以下程式碼可能會在 `origin-domain` 上執行:
```jsx=
var invocation = new XMLHttpRequest();
var url = 'http://other-domain/resources/public-data/';
function callOtherDomain() {
if(invocation) {
invocation.open('GET', url, true);
invocation.onreadystatechange = handler;
invocation.send();
}
}
```
你的 XMLHttpRequest (XHR) 會是:
```
GET /resources/public-data/ HTTP/1.1
Host: other-domain
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Referer: http://origin-domain/examples/access-control/simpleXSInvocation.html
Origin: http://origin-domain
```
回傳的 Response 是:
```
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2.0.61
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml
[XML Data]
```
對於 Server 端來說,如果要提供跨站存取的權限就是設置 Response Header: Access-Control-Allow-Origin。在實作方面可以寫 Middleware 去加工。
## CSRF (Cross Site Request Forgery)
讀音: sea-surf
基於同源政策,會修改到資料的操作一定都在同源的情況下發生,除非你提供了 CORS,給予額外的權限。
但是,即使有了同源政策,並且 CORS 預設也是不允許其他網域存取的情況下,還會有安全問題嗎?有的,CSRF 就是一個例子。
SOP, CORS 最多只能防禦住 XMLHttpRequest
> If data is sent in any other format (JSON, XML) a standard method is to issue a POST request using **XMLHttpRequest** with CSRF attacks prevented by SOP and CORS; there is a technique to send arbitrary content from a simple HTML form using ENCTYPE attribute; such a fake request can be distinguished from legitimate ones by text/plain content type, but if this is not enforced on the server, CSRF can be executed
> [name=Wikipedia CSRF]
**CSRF 的攻擊行為**
在受害者不知情的情況下,被其他網域借用身份來完成受害者未經同意的 HTTP request。CSRF 不直接盜取使用者資料,而是透過使用者對 Browser 的信任進而完成攻擊。
![](https://i.imgur.com/sM7FVJv.png)
**CSRF 的主因**
將驗證身份的資料存在 Cookies, 藉由 Cookies 的傳遞來驗證身份。
這是當驗證系統採用的是 Session-based Authentication 時所產生的安全問題,因為是借用 受害者 Session 所達成的攻擊方式,所以又稱為是 Session Riding。
Session-based Authentication 對於 Client 端就是會把一些資料儲存在 Cookies 中。不論這是 Session 本身資料也好,或是 Session id ,只要這個 Cookies 存有可以驗證使用者身份的資料(Seesion 本身 or Session id),就會造成 CSRF。
![](https://i.imgur.com/wr7BKLD.jpg)
**CSRF 的攻擊手法**
![](https://i.imgur.com/QEfo0xn.png)
使用者曾經在 A 網站登入,並尚未登出。並且在 B 這個惡意網站操作的時候,B 網站嵌入了看不到的 HTTP request 給 A 網站。這個 HTTP request 是會改變使用者在資料庫中的資料,進而造成權益上的受損。當使用者在 B 惡意網站觸發 HTTP request 的時候,因為尚未登出,所以 Cookies 還在(存在browser),可以用來驗證身份而導致操作成功。
任何可以產生跨域請求的 html tag 都是 CSRF 攻擊發生的媒介。
- img
- iframe: http://stackoverflow.com/questions/17940811/example-of-silently-submitting-a-post-form-csrf
- 攻擊的例子可以查看這裡:http://blog.techbridge.cc/2017/02/25/csrf-introduction/
**防禦的有效方法**: 在會改到資料的 HTTP request 使用 csrf token 作為額外驗證方式。
- Synchronizer Token Pattern
- Double Submit Cookie (Cookie Token)
以上兩者,均在 Django 中有實作支援。Django 是預先驗證 Cookie token, 再使用 Synchronizer token: [source code](https://github.com/django/django/blob/master/django/middleware/csrf.py#L133)
**Synchronizer Token Pattern**
針對每一個 request, 都由 server 產生出一個 token 當作驗證的方法。這些 Token 可以經由 hash algorithm 以隨機次數 hash 出來。(hash chain)
這種方法的缺點在於 maintain token 以及驗證 token 對於後端實作來說會比較麻煩。如果這個 token 是嵌入在 html form 中的話,當我們發送完,按上一步想要在發送一次時, token 可能會變成是 invalid (會不會變成 invalid 取決於實作)。
**Double Submit Cookie (Cookie Token)**
![](https://i.imgur.com/PLmKaqz.jpg)
每當使用者登入後,就發一個 Cookie CSRF Token 給使用者。
這項防禦方法是基於使用 Javascript 來發送 Request。在 Same-Origin Policy 的前提下,只有使用者當前的頁面能夠存取到 Cookie 中的 CSRF Token,其他頁面無法存取。
當我們要發 Sensitive HTTP Request (POST, DELETE ...) 的時候,就將這個從 Cookies 取出來的 CSRF token 設置到 Request Header 中,讓 Server 驗證。
p.s 在這種情況下會需要用 Javascript 讀取 Cookie 中的數值,所以這個 Cookie 不能被設置為 HttpOnly。
------------------------------------------
但是我覺得最好的防禦方法:不要使用 Session Authentication
例如使用 Token authentication 就不需要考慮 CSRF 的問題。
## Reference
- 阮一峰 Same-Origin Policy(註:有些不見得正確) http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html
- 阮一峰 CORS(註:有些不見得正確) http://www.ruanyifeng.com/blog/2016/04/cors.html
- Same-Origin Policy Wikipedia:
https://en.wikipedia.org/wiki/Same-origin_policy#cite_note-4
- Same-Origin RFC6454:
https://tools.ietf.org/html/rfc6454
- MDN Same-Origin Policy: https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy
- MDN Same-Origin Policy for file:
https://developer.mozilla.org/zh-TW/docs/Same-origin_policy_for_file:_URIs
- JSONP: http://www.cnblogs.com/dowinning/archive/2012/04/19/json-jsonp-jquery.html
- MDN CORS: https://developer.mozilla.org/zh-TW/docs/Web/HTTP/Access_control_CORS
- MDN CORS preflight request:
https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request
- W3 CORS for Developer:
https://w3c.github.io/webappsec-cors-for-developers/#cross-origin-send-permissions-pre-javascript-browsers
- Django REST framework Working with AJAX, CSRF & CORS:
http://www.django-rest-framework.org/topics/ajax-csrf-cors/#working-with-ajax-csrf-cors
- 實現與防範 CSRF 跨網站請求偽造攻擊:
https://dotblogs.com.tw/joysdw12/archive/2013/09/16/asp-net-cross-site-request-forgery.aspx
- Wikipedia CSRF:
https://en.wikipedia.org/wiki/Cross-site_request_forgery
- OWASP Cross-Site Request Forgery (CSRF) Prevention Cheat Sheet:
https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet
- 讓我們來談談 CSRF:
http://blog.techbridge.cc/2017/02/25/csrf-introduction/
## Note
> Lastly, certain types of attacks, such as **DNS rebinding** or **server-side proxies**, permit the host name check to be partly subverted, and make it possible for rogue web pages to directly interact with sites through addresses other than their "true", canonical origin. The impact of such attacks is limited to very specific scenarios, since the browser still believes that it is interacting with the attacker's site, and therefore does not disclose **third-party cookies** or other sensitive information to the attacker.
> [name=wikepedia]
- DNS rebind attack:
http://searchsecurity.techtarget.com/definition/DNS-rebinding-attack