顯示具有 資訊安全 標籤的文章。 顯示所有文章
顯示具有 資訊安全 標籤的文章。 顯示所有文章

防禦利用 iframe 的站點劫持攻擊

https://paper.seebug.org/papers/Archive/drops2/Clickjacking%E7%AE%80%E5%8D%95%E4%BB%8B%E7%BB%8D.html



各種防禦與破解的方法整理


推荐的防御方法:


一、X-FRAME-OPTIONS

X-FRAME-OPTIONS是微软提出的一个http头,专门用来防御利用iframe嵌套的点击劫持攻击。

并且在IE8、Firefox3.6、Chrome4以上的版本均能很好的支持。

这个头有三个值:

DENY               // 拒绝任何域加载

SAMEORIGIN         // 允许同源域下加载

ALLOW-FROM         // 可以定义允许frame加载的页面地址

php中设置示例:

header ( "X-FRAME-OPTIONS:DENY");

二、目前最好的 JavaScript 的防御方案为:

<head>
<style> body { display : none;} </style>
</head>
<body>
<script>
if (self == top) {
    var theBody = document.getElementsByTagName('body')[0];
    theBody.style.display = "block";
} else {
    top.location = self.location;
}
</script>




0x00 相关背景介绍

Clickjacking(点击劫持)是由互联网安全专家罗伯特·汉森和耶利米·格劳斯曼在2008年首创的。

是一种视觉欺骗手段,在web端就是iframe嵌套一个透明不可见的页面,让用户在不知情的情况下,点击攻击者想要欺骗用户点击的位置。

由于点击劫持的出现,便出现了反frame嵌套的方式,因为点击劫持需要iframe嵌套页面来攻击。

下面代码是最常见的防止frame嵌套的例子:

if(top.location!=location)
    top.location=self.location;

事实上,这种代码很容易被绕过,在后文中讨论。

0x01 防御的几种方式

防止frame嵌套的js使用代码由高到低比例:

if (top != self)
if (top.location != self.location)
if (top.location != location)
if (parent.frames.length > 0)
if (window != top)
if (window.top !== window.self)
if (window.self != window.top)
if (parent && parent != window)
if (parent && parent.frames && parent.frames.length>0)
if((self.parent&&!(self.parent===self))&&(self.parent.frames.length!=0))

检测到后的处理方案:

top.location = self.location
top.location.href = document.location.href
top.location.href = self.location.href
top.location.replace(self.location)
top.location.href = window.location.href
top.location.replace(document.location)
top.location.href = window.location.href
top.location.href = "URL"
document.write('')
top.location = location
top.location.replace(document.location)
top.location.replace('URL')
top.location.href = document.location
top.location.replace(window.location.href)
top.location.href = location.href
self.parent.location = document.location
parent.location.href = self.document.location
top.location.href = self.location
top.location = window.location
top.location.replace(window.location.pathname)
window.top.location = window.self.location
setTimeout(function(){document.body.innerHTML='';},1);
window.self.onload = function(evt){document.body.innerHTML='';}
var url = window.location.href; top.location.replace(url)

0x02 绕过的几种方式

对于使用parent.location来防御的可以使用多层嵌套的方式绕过。

一、例如防御代码为:

if(top.location!=self.location){
     parent.location = self.location;
}

建立两个页面:

1.html代码为:

<iframe src="2.html">

2.html代码为:

<iframe src="http://www.victim.com">

访问1.html之后可以看到页面并无跳转等动作。

http://static.wooyun.org/20141017/2014101711515250154.png

二、onBeforeUnload函数的利用:

onBeforeUnload的介绍以及各种浏览器的支持情况请见:

http://w3help.org/zh-cn/causes/BX2047

如下的防御代码:

if(top != self) top.location.replace(location);

新建立页面,代码如下:

<script>
var framekiller = true;
window.onbeforeunload = function() { if(framekiller) { return
"Write something here to keep people stay!";} };
</script>
<iframe src="http://www.victim.com/">

打开页面显示如下:

http://static.wooyun.org/20141017/2014101711515274922.png

欺骗用户点击留在此页后显示:

http://static.wooyun.org/20141017/2014101711515228109.png

三、XSS filter的利用

IE8以上以及Chrome浏览器都有XSS筛选器,这些可以用来对付防御frame嵌套的代码。

防御代码如下:

if(top!=self){
    top.location=self.location;
}

新建立页面,代码如下:

<iframe src="http://www.victim.com/?<script>">

访问后页面显示:

http://static.wooyun.org/20141017/2014101711515211018.png

IE的xss筛选器自动拦截了跳转。

斯坦福的文章里写了Chrome也会出现这种情况,并给出了攻击代码:

<iframe src=http://www.victim.com/?v=if(top+!%3D+self)+%7B+top.location%3Dself.location%3B+%7D">

但是测试发现,新版的Chrome并不会拦截了,会直接跳转过去。

如果跟的参数中有变量在页面中显示的,会把变量过滤一遍再输出,但不会阻止跳转。

四、Referer检查的问题

有一些站点允许自己的域名嵌套自己,禁止外站对自己的嵌套。

通常是用document.referer来检测来源是否为自己的域名。

if(top.location!=location){
    if(document.referrer && document.referrer.indexOf("aaa.com")==1)
    {
        top.location.replace(document.location.href);
    }
}

判断字符串中是否含有本域名是常见的错误用法,利用二级域名的方式便可绕过,如:

http://aaa.com.bbb.com

注:从https域下post数据到http域的时候,浏览器不带Referer。

IE有个属性可以设置security为restricted可以禁止iframe里执行js脚本,但是要达到点击劫持的效果,必须要能够执行js所以很鸡肋。

代码如下:

<iframe src="http://www.victim.com/iframe.html" security="restricted"></iframe>

重点是手机站点,很多主站做的很不错,但是手机站点没有做任何防护,很容易造成点击劫持。

五、location劫持

在IE浏览器中,如果能够在防御代码的前面可以插入form表单的话,可以利用form表单对location进行劫持。

<form name=self location="javascript:alert(1)"></form>
<script>
if(top!=self){
   top.location=self.location
}
</script>

用iframe嵌套此代码,可以看到没有跳转,执行了alert(1)。



對稱密鑰加密:進階加密標準(Advanced Encryption Standard,AES)

https://zh.wikipedia.org/wiki/%E9%AB%98%E7%BA%A7%E5%8A%A0%E5%AF%86%E6%A0%87%E5%87%86


Should I use ECB or CBC encryption mode for my block cipher?

https://crypto.stackexchange.com/questions/225/should-i-use-ecb-or-cbc-encryption-mode-for-my-block-cipher

Never use ECB! It is insecure.

I recommend an authenticated encryption mode, like EAX or GCM. If you can't use authenticated encryption, use CBC or CTR mode encryption, and then apply a MAC (e.g., AES-CMAC or SHA1-HMAC) to the resulting ciphertext.


Golang 實現 AES encryption with GCM:


如何取得使用者 IP 的方法與資安探索

https://devco.re/blog/2014/06/19/client-ip-detection/

本文與留言區的討論


重點摘錄:

一、使用代理伺服器的情況下,HTTP Header 會有不同的行為。例如 Elite Proxy 如何隱藏客戶端的真實 IP。以下簡單介紹幾種常見的狀況給各位參考。

直接連線 (沒有使用 Proxy)
REMOTE_ADDR: 客戶端真實 IP
HTTP_VIA: 無
HTTP_X_FORWARDED_FOR: 無

Transparent Proxy
REMOTE_ADDR: 最後一個代理伺服器 IP
HTTP_VIA: 代理伺服器 IP
HTTP_X_FORWARDED_FOR: 客戶端真實 IP,後以逗點串接多個經過的代理伺服器 IP

Anonymous Proxy
REMOTE_ADDR: 最後一個代理伺服器 IP
HTTP_VIA: 代理伺服器 IP
HTTP_X_FORWARDED_FOR: 代理伺服器 IP,後以逗點串接多個經過的代理伺服器 IP

High Anonymity Proxy (Elite Proxy)
REMOTE_ADDR: 代理伺服器 IP
HTTP_VIA: 無
HTTP_X_FORWARDED_FOR: 無 (或以逗點串接多個經過的代理伺服器 IP)


二、攻擊者可以竄改 header 插入特殊字元,對網站進行 SQL Injection 或者 Cross-Site Scripting 攻擊。


三、從資安的角度,應留存下所有可能紀錄到真實 IP 的資料,記錄下所有相關的 header 欄位,包含「REMOTE_ADDR」「X-Forwarded-For」等等,真正有犯罪事件發生時,就可以調出所有完整的 IP 資訊進行人工判斷,從蛛絲馬跡中或許有機會找出真正的 IP。當然從 header 存入的數值也可能會遭到攻擊者竄改插入特殊字元嘗試 SQL Injection,因此存入值必須先經過過濾,或者使用 Prepared Statement 進行存放。

可以參考的 HTTP Header(依照可能存放真實 IP 的順序)

HTTP_CLIENT_IP
HTTP_X_FORWARDED_FOR
HTTP_X_FORWARDED
HTTP_X_CLUSTER_CLIENT_IP
HTTP_FORWARDED_FOR
HTTP_FORWARDED
REMOTE_ADDR (真實 IP 或是 Proxy IP)
HTTP_VIA (參考經過的 Proxy)

「駭客思維」就是找出網站任何可能竄改的弱點,從網頁上的元素到 HTTP Header 都是嘗試的對象。因此身為防禦者一定要清楚的知道哪些數值是不能信賴的。


四、REMOTE_ADDR 只能透過 Proxy、VPN 等方法來改變,沒辦法藉由竄改 Header 來假造。

五、用 Onion Routing 連線的 IP 有辦法被查出嗎? 沒有辦法,只能夠知道「Exit Node」的 IP。

六、一般來說不會透過 Onion Routing 來做 DDoS 攻擊。典型的 的 DDoS 攻擊也無法透過 Onion Routing。

七、Web Server 能夠取得的資訊就是那些欄位,包含 REMOTE_ADDR 以及其他 HTTP Header,因此能夠獲得的資訊有限。直接 TCP 連線的 IP 位置就是 REMOTE_ADDR。

紐約時報:量子加密技術競爭加劇,中國目前領先

https://www.nytimes.com/2018/12/03/technology/quantum-encryption.html


據《紐約時報》報導,包括谷歌到阿里巴巴在內的科技公司都在競相打造世界上第一台量子電腦,這要比當前的電腦強大得多。儘管建造量子電腦的競爭不分伯仲,但中國在量子加密技術方面明顯領先。
紐約時報:量子加密技術競爭加劇,中國目前領先 © 由 Home Media Group (II) 提供 紐約時報:量子加密技術競爭加劇,中國目前領先 ▲ Quantum Xchange正在曼哈頓和紐華克之間建立量子加密連接,而初創企業Qubitekk也在致力於探索量子加密技術。
未來的量子電腦可能會破解保護數字訊息的現行加密技術,使諸如數十億美元的電子商務支出訊息以及存儲在資料庫中的機密訊息等一切資料都面臨風險。
紐約時報:量子加密技術競爭加劇,中國目前領先 © 由 Home Media Group (II) 提供 紐約時報:量子加密技術競爭加劇,中國目前領先 ▲ 曼哈頓下城哈德遜街60號,支持Quantum Xchange加密服務的光纖電纜。
這個問題有答案嗎?量子加密依賴於相同的概念。正如一些科學家在研究量子電腦一樣,另一些科學家也在研究量子安全技術,從而阻礙未來量子電腦的密碼破譯能力。
這是一場涉及國家訊息安全的競賽,儘管建造量子電腦的競爭不分伯仲,但中國在量子加密技術方面明顯領先。與人工智慧等其他尖端技術一樣,中國也將不同類型的量子研究列為重點。
「中國在相關技術研發方面擁有深思熟慮的戰略,」美國橡樹嶺國家實驗室(Oak Ridge National Laboratory)前研究員鄧肯‧厄爾(Duncan Earl)表示。目前厄爾是量子加密技術公司Qubitekk的總裁兼首席技術長。「如果我們認為我們可以等上5到10年再應用這項技術,那就太晚了。」
量子計算基於量子力學理論,後者解釋了極小物質粒子所表現出的奇怪行為。
在傳統計算機中,晶體管存儲訊息的最小單位是「bit」,每個bit不是1就是0。
而當某些物質極小或極冷時,它們的行為就不同了。這種不同狀態的差異性允許一個量子位同時顯現出1和0的狀態,兩個量子位就可以同時容納四個值。隨著量子位的數量增長,量子電腦的功能以指數形式變得更加強大。
和量子運算一樣,量子加密技術依賴於極小物體的非直覺行為。保護資料祕密的密碼是由最小的光子生成的。透過合適的設備很容易判斷它們是否被篡改了,就像藥瓶上的封條一樣。如果實施得當,這項技術可能是牢不可破的。
紐約時報:量子加密技術競爭加劇,中國目前領先 © 由 Home Media Group (II) 提供 紐約時報:量子加密技術競爭加劇,中國目前領先 ▲ 芝加哥大學(University of Chicago)的一個量子研究機構正在研究一種名為量子中繼器(quantum repeaters)的設備,其可以擴大加密的範圍。
目前的量子加密技術還無法確保可以構建出長距離的可行量子加密網路。但如果這真的發生,中國願意付諸實踐,並很可能會帶來巨大回報。
迄今為止,中國已經投資數千萬美元,建立了使用量子加密傳輸資料的網路。去年,中國發射了一顆以古代哲學家墨子命名的衛星,利用量子加密技術成功實現了北京和維也納之間的視訊通話。經過4年的規劃和建設,北京和上海之間的專用量子通訊網路也於去年投入運行。
目前,量子加密只能在有限距離內工作。北京和維也納之間的衛星連接將這一限制擴大到創紀錄的7451公里。在地面,透過使用光纖線路,量子機密技術的最大應用距離擴大到了約241公里。
在中國對量子加密的投資中,墨子號衛星受到的關注最多。衛星研製者中科大學領導建設了總長約1931公里的地面量子加密網。
光纖網路通過的安徽和山東省政府共投入8000萬美元用於該專案。和中國所有重大基礎設施項目一樣,這些計劃得到了中國政府的高層支持。
這條量子加密主線正在延伸到其他城市和地區。到2030年,中國的目標是在全球建立一個共享量子加密密鑰的網路。
一些安全專家質疑量子加密的有效性。它是如此新穎,還沒有經過任何嚴格的測試。而只有經過這些測試,才能使它得到持懷疑態度的密碼學家的認可。
但中科大物理學教授陸朝陽表示,京滬之間的量子加密網路是一次重大升級。
在傳統的通信方式中,竊聽者可以在光纖線路上的每一點攔截資料流。陸教授表示,量子加密技術將1931公里光纖線路上的易損點減少到了幾十個。
「我們承認這是一個過渡解決方案,」他說。「這並不是最終的解決方案。但就安全而言,這已經是一個巨大的進步。」
在美國,業界認為量子加密不過是一項科學實驗。相反,研究人員專注於使用普通數學來構建新的加密形式,以對抗量子電腦。這種技術不需要新的基礎設施。
但現在,在最近量子研究進展的推動下,一些美國公司正在迎頭追趕。
南加州初創企業Qubitekk正在利用這項技術保護田納西州的電網。另一家初創公司Quantum Xchange正在美國東北部建設量子加密網路,希望為華爾街銀行和其他企業提供服務。而長島石溪大學(Stony Brook University)的研究人員正在準備第三次冒險。
像Qubitekk這樣的小型初創企業不太可能為量子加密而投入數百萬美元。但許多專家認為,更重要的工作將發生在研究實驗室,美國能源部(Department of Energy)正在為芝加哥的一個測試網路提供資金,該網路可能會更加先進。
洛斯阿拉莫斯國家實驗室(Los Alamos National laboratory)和橡樹嶺國家實驗室(Oak Ridge National laboratory)正與Qubitekk合作,利用量子加密技術保護電網,而Quantum Xchange正在把設備轉移到哈德遜街60號(Hudson Street)。哈德遜街是古老的西聯電報中心所在地,現在是曼哈頓下城的一個網路中心。
紐約時報:量子加密技術競爭加劇,中國目前領先 © 由 Home Media Group (II) 提供 紐約時報:量子加密技術競爭加劇,中國目前領先 ▲ 戴維‧奧沙洛姆(David Awschalom)負責芝加哥大學的大部份量子研究。
Quantum Xchange正在曼哈頓和紐華克之間建立量子加密連接,計畫將這兩個城市運營的大型銀行連接起來。最終,它希望將這一網路延伸至東海岸。
在像芝加哥大學這樣的地方,研究人員希望更進一步,他們正在探索所謂的量子中繼器,也就是能夠擴展量子加密範圍的設備。
「我們還沒有做到這一點,」芝加哥大學教授戴維‧奧沙洛姆(David Awschalom)說。「但我相信,這將在未來幾年內發生。」
無論如何,量子通信技術需要新的硬體。這包括龐大的光纖網路,或許還有衛星,以及能夠探測單個光子的專用設備。
雖然Qubitekk致力於研究量子加密網路,但它無法獲得完成這項工作所需的特殊光探測器。這家初創公司最初從新澤西州的一家小型製造商Princeton Lightwave那裡購買探測器。但今年4月,這家美國製造商將探測器業務交給了中國的一家公司,但未能及時如願。
這家中國公司已經承諾向Qubitekk提供硬體,但最近告訴它,由於生產問題,額外的檢測器要到3月份才能交付。
紐約時報:量子加密技術競爭加劇,中國目前領先 © 由 Home Media Group (II) 提供 紐約時報:量子加密技術競爭加劇,中國目前領先 ▲ 目前透過諸如Quantum Xchange光纖線路應用量子加密的極限約為241公里。

歐洲的一些小公司也在銷售類似的探測器,全球各地的實驗室也在競相開發更先進的設備。但就目前而言,尤其是在美國,這種設備的供應量非常有限。

資安人員與駭客都愛用的搜尋引擎:Shodan

https://en.wikipedia.org/wiki/Shodan_(website)

Shodan is a search engine that lets the user find specific types of computers (webcams, routers, servers, etc.) connected to the internet using a variety of filters.

Shodan collects data mostly on web servers (HTTP/HTTPS - port 80, 8080, 443, 8443), as well as FTP (port 21), SSH (port 22), Telnet (port 23), SNMP (port 161), IMAP (port 993), SMTP (port 25), SIP (port 5060), and Real Time Streaming Protocol (RTSP, port 554). The latter can be used to access webcams and their video stream.

The website began as Matherly's pet project, based on the fact that large numbers of devices and computer systems are connected to the Internet. Shodan users are able to find systems including traffic lights, security cameras, home heating systems as well as control systems for water parks, gas stations, water plants, power grids, nuclear power plants and particle-accelerating cyclotrons;[citation needed] most have little security. Many devices use "admin" as their user name and "1234" as their password, and the only software required to connect to them is a web browser.

In May 2013, CNN Money released an article detailing how SHODAN can be used to find dangerous systems on the Internet, including traffic light controls. They show screenshots of those systems, which provided the warning banner "DEATH MAY OCCUR !!!" upon connecting.

In September 2013, Shodan was referenced in a Forbes article claiming it was used in order to find the security flaws in TRENDnet security cameras. The next day, Forbes followed up with a second article talking about the types of things that can be found using Shodan. This included Caterpillar trucks whose onboard monitoring systems were accessible, heating and security control systems for banks, universities, and corporate giants, surveillance cameras, and fetal heart monitors.

In January 2015, Shodan was discussed in a CSO Online article addressing its pros and cons. According to one opinion, presented in the article as that of Hagai Bar-El, Shodan actually gives the public a good service, although it highlights vulnerable devices. This perspective is also described in one of his essays.

In December 2015, various news outlets, including Ars Technica, reported that a security researcher used Shodan to identify accessible MongoDB databases on thousands of systems, including one hosted by Kromtech, the developer of the MacOS security tool MacKeeper.

The primary users of Shodan are cybersecurity professionals, researchers and law enforcement agencies. While cybercriminals can also use the website, some typically have access to botnets that could accomplish the same task without detection.

手機應用開發:token、cookie的區別


cookie最初是解决http连接无状态问题的产物,用于客户端和服务端共同维护一些状态数据。

cookie会被附加到http请求中,这不需要开发者做额外的支持。cookie存在一个最大长度的问题(4KB?)。

token通常作为验证后的凭证,免除在一定时间内的重复验证。

token的存储和参数传递都需要开发者来处理。

使用cookie来维持登录态,在实现过程中实际上是在cookie中添加一个token来维持一个登录态。

cookie和token都是一个字符串,具体在这个字符串里面存放什么都可以商量。

一般做法是这样的: 这里只讨论登录名和密码,不考虑设备id等其他一些参数。
客户端 登录请求参数:account,md5(password+salt)
服务端验证后 返回:result,token

md5(password+salt)的目的不在于抵御重放攻击,而是为了保护用户真正的密码不被泄露。

md5以及其他摘要算法(sha1、sha256等)并不属于加密算法。

如果希望整个通信不是明文传输,可以使用HTTPS,或者自己实现一套服务器认证,公钥交换以及加密解密的规则。

走 https 了,還需要對參數加密以防止重放攻擊嗎?
https://www.oschina.net/question/1047640_2180952
=> 走https之后,记得不要url后跟参数,因为会被浏览器,路由器记到历史记录里。不要用cookie存明文。其他的应该无所谓了。关键是app这边加密并没有用啊,因为别人可以看到你源码的。app加密,服务器解密,这样可以防止信息泄漏。服务器加密,app解密,这个没用,你源码都在别人手里了


抵御重放攻击,可以在请求中加入时间戳,对整个请求体做签名,服务器验签后检查时间戳以及account,来决定是否响应。
https://baike.baidu.com/item/%E9%87%8D%E6%94%BE%E6%94%BB%E5%87%BB

(1)加随机数。该方法优点是认证双方不需要时间同步,双方记住使用过的随机数,如发现报文中有以前使用过的随机数,就认为是重放攻击。缺点是需要额外保存使用过的随机数,若记录的时间段较长,则保存和查询的开销较大。

(2)加时间戳。该方法优点是不用额外保存其他信息。缺点是认证双方需要准确的时间同步,同步越好,受攻击的可能性就越小。但当系统很庞大,跨越的区域较广时,要做到精确的时间同步并不是很容易。

(3)加流水号。就是双方在报文中添加一个逐步递增的整数,只要接收到一个不连续的流水号报文(太大或太小),就认定有重放威胁。该方法优点是不需要时间同步,保存的信息量比随机数方式小。缺点是一旦攻击者对报文解密成功,就可以获得流水号,从而每次将流水号递增欺骗认证端。

在实际中,常将方法(1)和方法(2)组合使用,这样就只需保存某个很短时间段内的所有随机数,而且时间戳的同步也不需要太精确。


登录后实际上就是授权票据的传输,票据通常就是一个或多个字符串,被称为token,你可以把它放到cookie里面,也可以跟在参数上,那这两种有什么区别呢?

1.如果放在cookie里面,浏览器的安全策略会帮你做些安全检查,比如跨域不传输,非安全协议不传输,禁止脚本操作cookie等等,如果跟在参数上是没有这些功能的

2.无论是app,webview,还是浏览器,经常需要把地址分享到第三方,如果习惯在url上带token,那么,分享是要把token去掉才行,如果放在cookie就不用了,cookie不会被分享出去的

3.如果参数传输token,无论post get ,只要是需要鉴权的请求,你都要手动把token搭上,如果放在cookie,你只要放一次,只要补跨域,不过期,浏览器自己会在请求时给你传过去,省心省力,妈妈再也不担心漏掉token了,cookie还有许多其它规范,不再赘述

4.cookie有自己的规范和约束,不是哪哪都能用,所以很多时候必须请求参数里带token,比如常见的跨域授权后跳转


=> cookie是浏览器负责维护的,不灵活。现在的“终端”不止浏览器了

=> cookie 可以用来保存 token,也可以用来保存其他东西;
同样的,token 既能保存在 cookie 中,也能保存在其他地方。
所以,不是一个维度的东西

=> 作为安卓bug员,乱说一点吧,你截获密码密文,app要你输入明文,如果你输入密文会再次加密传递,除非你篡改app或者用请求软件模拟请求,这个还得反编译,现在大一点的软件都有加固混淆啥的,反编译也不是很容易,越涉及到金钱,安全性越高,而且后台的哥们也不是吃干饭的,他们还有别的通信安全策略,总体来说,除了有仇或者巨大利益,不然很少有人去黑...

=> 最近在写angular。 登录时服务器给客户端token存在本地,每次请求客户端都会附在http header,让服务器都会先验证token再操作。


參考文獻:

[iOS 开发]如何处理 iOS 原生网络请求中的 cookie ?
https://www.jianshu.com/p/d144bd7226b7

Wikipedia - HTTP cookie:
https://en.wikipedia.org/wiki/HTTP_cookie

聊一聊 cookie:
https://segmentfault.com/a/1190000004556040

NSHTTPCookieStorage 官方文档:
https://developer.apple.com/reference/foundation/nshttpcookiestorage
中文版:http://www.jianshu.com/p/b10652a1803e

iOS平台下cookie的使用:
http://www.jianshu.com/p/65094611980c

iOS HTTP网络请求Cookie的读取与写入(NSHTTPCookieStorage)
http://www.skyfox.org/ios-url-request-cookie.html

NSHTTPCookieStorage state not saved on app exit. Any definitive knowledge/documentation out there?
http://stackoverflow.com/questions/5837702/nshttpcookiestorage-state-not-saved-on-app-exit-any-definitive-knowledge-docume

app开发token、cookie的区别,账号密码加密又是如何保证安全?
https://www.zhihu.com/question/39137156

为什么 APP 要用 token 而不用 session 认证?
https://www.v2ex.com/t/148426

How to manage sessions with AFNetworking?
http://stackoverflow.com/questions/10984374/how-to-manage-sessions-with-afnetworking/11039784#11039784

Persisting Cookies In An iOS Application?
http://stackoverflow.com/questions/4597763/persisting-cookies-in-an-ios-application

NSHTTPCookieStorage and Cookie Expiration Date
http://stackoverflow.com/questions/7203641/nshttpcookiestorage-and-cookie-expiration-date/7209706#7209706

Can I set the cookies to be used by a WKWebView?http://stackoverflow.com/questions/26573137/can-i-set-the-cookies-to-be-used-by-a-wkwebview

haifengkao/YWebView:https://github.com/haifengkao/YWebView

https://www.jianshu.com/p/4fb94b4a281e

https://www.jianshu.com/p/e56fbc8940b2


Access-Control-Allow-Origin 跨域訪問相關議題

理解 Ajax 與跨來源請求:https://blog.techbridge.cc/2017/05/20/api-ajax-cors-and-jsonp/

原來 CORS 沒有我想像中的簡單:https://blog.techbridge.cc/2018/08/18/cors-issue/

HTML2Canvas:用Javascript來做螢幕截圖,仍然會受到 跨域訪問 限制
http://www.ladesign.tw/paper/info/jquery_html2canvas_download



ajax 设置Access-Control-Allow-Origin实现跨域访问
https://blog.csdn.net/fdipzone/article/details/46390573

摘要:
ajax跨域访问是一个老问题了,解决方法很多,比较常用的是JSONP方法,JSONP方法是一种非官方方法,而且这种方法只支持GET方式,不如POST方式安全。

如果跨域使用POST方式,可以使用创建一个隐藏的iframe来实现,与ajax上传图片原理一样,但这样会比较麻烦。

ps. 如何創建一個隱藏的 iframe:http://21st.each1.net/2018/07/csrf-cross-site-request-forgery.html

因此,通过设置Access-Control-Allow-Origin来实现跨域访问比较简单。

例如:客户端的域名是www.client.com,而请求的域名是www.server.com

如果直接使用ajax访问,会有错误

在被请求的Response header中加入

// 指定允许其他域名访问
header('Access-Control-Allow-Origin:*');
// 响应类型
header('Access-Control-Allow-Methods:POST');
// 响应头设置
header('Access-Control-Allow-Headers:x-requested-with,content-type');
就可以实现ajax POST跨域访问了。

實現的代碼摘要如下:

client.html 路径:http://www.client.com/client.html

<script type="text/javascript">
    $.post("http://www.server.com/server.php",{name:"fdipzone",gender:"male"})
      .done(function(data){
        document.getElementById("show").innerHTML = data.name + ' ' + data.gender;
      });
</script>

server.php 路径:http://www.server.com/server.php

<?php
$ret = array(
    'name' => isset($_POST['name'])? $_POST['name'] : '',
    'gender' => isset($_POST['gender'])? $_POST['gender'] : ''
);

header('content-type:application:json;charset=utf8');
header('Access-Control-Allow-Origin:*');
header('Access-Control-Allow-Methods:POST');
header('Access-Control-Allow-Headers:x-requested-with,content-type');

echo json_encode($ret);
?>

Access-Control-Allow-Origin:* 表示允许任何域名跨域访问
如果需要指定某域名才允许跨域访问,只需把Access-Control-Allow-Origin:*改为Access-Control-Allow-Origin:允许的域名

例如:header('Access-Control-Allow-Origin:http://www.client.com');

如果需要设置多个域名允许访问,这里需要用php处理一下

例如允许 www.client.com 与 www.client2.com 可以跨域访问

server.php 修改为

<?php
$ret = array(
    'name' => isset($_POST['name'])? $_POST['name'] : '',
    'gender' => isset($_POST['gender'])? $_POST['gender'] : ''
);

header('content-type:application:json;charset=utf8');

$origin = isset($_SERVER['HTTP_ORIGIN'])? $_SERVER['HTTP_ORIGIN'] : '';

$allow_origin = array(
    'http://www.client.com',
    'http://www.client2.com'
);

if(in_array($origin, $allow_origin)){
    header('Access-Control-Allow-Origin:'.$origin);
    header('Access-Control-Allow-Methods:POST');
    header('Access-Control-Allow-Headers:x-requested-with,content-type');
}

echo json_encode($ret);
?>




PushState + Ajax = Pjax

單頁面應用(Single Page Application)簡稱 SPA,使用 SPA 理念構建的應用優點有用戶體驗好、速度快,內容的改變不需要重新加載整個頁面,避免了不必要的跳轉和重複渲染,從而相對減輕了服務器壓力。

實作上,使用 HTML5 的 PushState + Ajax 可實現不刷新整個頁面卻可讓地址欄變換、頁面局部刷新的效果。

在 SEO 方面,Google官方宣布不再繼續支持2009年以來的AJAX的googlebot檢索。
Google建議在建置網站時應該使用漸進增強的原則。
如果已經實施了Google關於AJAX的建議 ,Google表示網站仍然會被索引,但建議網站應支援新的隨時間變化的作法。

具體解釋window.history:
https://tw.saowen.com/a/022ff7a00a0cc0214313135aba4cbc178a59784adda3bf0a6120038b205eac9c

PushState+Ajax實現簡單的單頁面應用SPA:
https://www.itread01.com/articles/1476680423.html

ajax与HTML5 history pushState/replaceState实例
https://www.zhangxinxu.com/study/201306/ajax-page-html5-history-api.html?area=pudong

Javascript實現前端簡單路由:
https://www.itread01.com/articles/1476578707.html

PushState and Ajax
http://www.ayqy.net/blog/pjaxpushstate-and-ajax/

pjax = pushState + ajax (一個開源的 jQuery plugin)
https://github.com/defunkt/jquery-pjax


了解 Ajax 漏洞

Ajax 吸引 Web 開發人員的地方也是對其安全性最易受威脅的地方。眾多安全專家一致認為 Web 應用程序是網絡犯罪的一大目標,但是 Web 安全通常只是企業安全預算的一小部分。由於 Ajax 被用於開發很多可在 Web 上看到的應用程序,因此它的流行使其成為攻擊者在 JavaScript 代碼中尋找漏洞的目標。

Ajax 存在的核心是可以用它來創建數據驅動網站。真正吸引攻擊者的不是可以將 Ajax 用作 Web 應用程序開發工具,而是數據,不管是金融數據、個人數據還是機密數據,都是珍貴的在線商品,Ajax 再次發現自己成為了網絡犯罪的焦點。

在使用 Ajax 進行開發時,可以採用以下步驟防止出現 XSS 漏洞

確保 JavaScript 變量被引用。
使用 JavaScript 十六進制編碼。
使用 JavaScript Unicode 編碼。
避免反斜杠編碼(\"、\' 或 \\)。
使用 JSON.parse 或 json2.js 庫來分析 JSON。
避免使用 eval() 方法分析 JSON,它執行任何包含 JSON 的腳本。

要避免Ajax 橋接漏洞,在橋接時除了需要與第三方的站點之間建立信任,也應該審核第三方站點以何種方式訪問您的站點,並掃描可能被橋接利用的任何漏洞。

與 Ajax 相關的資安議題應詳閱 https://www.ibm.com/developerworks/cn/web/wa-vulnerabilities/index.html


資安風險:

駭客的攻擊方向之一恐怕會是尋找該應用的 Javascript 編程漏洞,另一個攻擊方向可能是 XSS、SQL注入,或是將目標放在大量的用戶資訊等容易被輕忽的XML或 JSON 資料傳遞。
比如說先取得明星的粉絲 Email ,再假借明星的名義對粉絲販售商品。

由於在用戶端有各種不確定性,比如用戶可能會使用各種方式來另開分頁,所以許多細節都必須考慮在 SPA 應用編程內,而 Javascript 程式碼必須赤裸裸地開源在前端,越複雜的程式碼,透露的資訊越多,為攻擊者提供了越多的線索 (資深的程式師從一段編程,看到的不只是程序是否存在安全議題,也看得到該程式碼創作者可能是個人還是團隊、軟體管理的情況、編程習慣、資歷等)。

Ajax 受到喜愛的原因是提高了 UI/UX 用戶體驗的同時還降低了 Server 負擔,然而,顧及用戶端的許多使用細節,就是得應用更大量的前端編程;當前端設計越複雜,如果只是 CSS 這些不涉及資安的層面,對維護者的心理壓力尚輕;若一旦涉及資安,就變成越養越大的不定時炸彈了。

所以,適度地使用 Ajax 會有好處,但是過度使用則會帶來隱憂,取捨並達到平衡點就好。

Javascript 使用 XMLHttpRequest (AJAX 應用)

使用 XMLHttpRequest(XHR)物件與伺服器互動,你可以從 URL 擷取資料且不須刷新整個頁面。這使得網頁可以只更新其中的一部分而不中斷使用者的操作。XMLHttpRequest 被大量使用於 AJAX 應用。

僅管名字用的是 XML 與 HTTP,XMLHttpRequest 其實可以用來接收任何類型的資料,並不限於 XML。同時它也支援 HTTP 以外的通訊協定(包括 file 與 ftp)。

如果你的通訊涉及接收從server來的事件或是訊息資料,可以考慮透過EventSource介面使用server-sent 事件。對於全雙工的通訊,WebSockets 可能是較佳的選擇。

https://developer.mozilla.org/zh-TW/docs/Web/API/XMLHttpRequest


實作時常用到的參數詳解:
http://www.w3school.com.cn/ajax/ajax_xmlhttprequest_send.asp
https://itbilu.com/javascript/js/EkIzWrt7.html
https://itbilu.com/javascript/js/NkzjoC4j.html


javascript 實現 ajax 的幾種方法:
http://www.phpernote.com/javascript-function/904.html


Ajax 的安全議題:https://21st.each1.net/2018/10/pushstate-ajax-pjax.html

如何防禦 CSRF (Cross Site Request Forgery) 跨站請求偽造


client side 的 Double Submit Cookie

https://blog.techbridge.cc/2017/02/25/csrf-introduction/

https://security.stackexchange.com/questions/59470/double-submit-cookies-vulnerabilities


反思:
本文作者文末針對 SPA 的需求,提出由 client side 來生成 csrf token,
這部分恐怕是有疑慮的,因為由 client side 來生成 csrf token, cookie 的 HttpOnly 參數就只能設定為 false... 那麼,駭客就能拿到這個 csrf token 了 ?


以下為存檔備份,以防資料來源網站撤除資料,平時到出處網站閱讀在視覺體驗方面會比較舒適:

前言

最近剛好碰到一些 CSRF 的案例,趁著這次機會好好研究了一下。深入研究之後才發現這個攻擊其實滿可怕的,因為很容易忽略它。但幸好現在有些 Framework 都有內建防禦 CSRF 的功能,可以很簡單的開啟。
但儘管如此,我認為還是有必要瞭解一下 CSRF 到底在幹嘛,是透過怎樣的手段攻擊,以及該如何防禦。就讓我們先來簡單的介紹一下它吧!
CSRF 是一種 Web 上的攻擊手法,全稱是 Cross Site Request Forgery,跨站請求偽造。不要跟 XSS 搞混了,他們兩種是不同的東西,那到底什麼是 CSRF 呢?先從我自身的一個案例談起好了。

偷懶的刪除功能

以前我有做個一個簡單的後台頁面,就想成是一個部落格吧!可以發表、刪除以及編輯文章,介面大概長得像這樣:
delete
可以看到刪除的那個按鈕,點下去之後就可以把一篇文章刪掉。當初因為偷懶,想說如果我把這個功能做成 GET,我就可以直接用一個連結完成刪除這件事,在前端幾乎不用寫到任何程式碼:





1
<a href='/delete?id=3'>刪除</a>

很方便對吧?然後我在網頁後端那邊做一下驗證,驗證 request 有沒有帶 session id 上來,也驗證這篇文章是不是這個 id 的作者寫的,都符合的話才刪除文章。
嗯,聽起來該做的都做了啊,我都已經做到:「只有作者本人可以刪除自己的文章」了,應該很安全了,難道還有哪裡漏掉了嗎?
沒錯,的確是「只有作者本人可以刪除自己的文章」,但如果他不是自己「主動刪除」,而是在不知情的情況下刪除呢?你可能會覺得我在講什麼東西,怎麼會有這種事情發生,不是作者主動刪的還能怎麼刪?
好,我就來讓你看看還能怎麼刪!
今天假設小黑是一個邪惡的壞蛋,想要讓小明在不知情的情況下就把自己的文章刪掉,該怎麼做呢?
他知道小明很喜歡心理測驗,於是就做了一個心理測驗網站,並且發給小明。但這個心理測驗網站跟其他網站不同的點在於,「開始測驗」的按鈕長得像這樣:





1
<a href='https://small-min.blog.com/delete?id=3'>開始測驗</a>

小明收到網頁之後很開心,就點擊「開始測驗」。點擊之後瀏覽器就會發送一個 GET 請求給https://small-min.blog.com/delete?id=3,並且因為瀏覽器的運行機制,一併把 small-min.blog.com 的 cookie 都一起帶上去。
Server 端收到之後檢查了一下 session,發現是小明,而且這篇文章也真的是小明發的,於是就把這篇文章給刪除了。
這就是 CSRF,你現在明明在心理測驗網站,假設是 https://test.com 好了,但是卻在不知情的狀況下刪除了 https://small-min.blog.com 的文章,你說這可不可怕?超可怕!
這也是為什麼 CSRF 又稱作 one-click attack 的緣故,你只要點一下就中招了。
你可能會說:「可是這樣小明不就知道了嗎,不就連過去部落格了?不符合『不知情的狀況』啊!」
好,那如果我們改成這樣呢:





1
2
<img src='https://small-min.blog.com/delete?id=3' width='0' height='0' />
<a href='/test'>開始測驗</a>

在開啟頁面的同時,一樣發送一個刪除的 request 出去,但這次小明是真的完全不知道這件事情。這樣就符合了吧!
CSRF 就是在不同的 domain 底下卻能夠偽造出「使用者本人發出的 request」。要達成這件事也很簡單,因為瀏覽器的機制,你只要發送 request 給某個網域,就會把關聯的 cookie 一起帶上去。如果使用者是登入狀態,那這個 request 就理所當然包含了他的資訊(例如說 session id),這 request 看起來就像是使用者本人發出的。

那我把刪除改成 POST 不就好了嗎?

沒錯,聰明!我們不要那麼懶,好好把刪除的功能做成 POST,這樣不就無法透過 <a> 或是 <img> 來攻擊了嗎?除非有哪個 HTML 元素可以發送 POST request!
有,正好有一個,就叫做 form。





1
2
3
4
<form action="https://small-min.blog.com/delete" method="POST">
<input type="hidden" name="id" value="3"/>
<input type="submit" value="開始測驗"/>
</form>

小明點下去以後,照樣中招,一樣刪除了文章。你可能又會疑惑說,但是這樣小明不就知道了嗎?我跟你一樣很疑惑,於是我 Google 到了這篇:Example of silently submitting a POST FORM (CSRF)
這篇提供的範例如下,網頁的世界真是博大精深:





1
2
3
4
5
6
<iframe style="display:none" name="csrf-frame"></iframe>
<form method='POST' action='https://small-min.blog.com/delete' target="csrf-frame" id="csrf-form">
<input type='hidden' name='id' value='3'>
<input type='submit' value='submit'>
</form>
<script>document.getElementById("csrf-form").submit()</script>

開一個看不見的 iframe,讓 form submit 之後的結果出現在 iframe 裡面,而且這個 form 還可以自動 submit,完全不需要經過小明的任何操作。
到了這步,你就知道改成 POST 是沒用的。

那我後端改成只接收 json 呢?

聰明的你靈機一動:「既然在前端只有 form 可以送出 POST 的話,那我的 api 改成用 json 收資料不就可以了嗎?這樣總不能用 form 了吧!」
spring 的 document告訴你:這還是沒用的!





1
2
3
4
5
<form action="https://small-min.blog.com/delete" method="post" enctype="text/plain">
<input name='{"id":3, "ignore_me":"' value='test"}' type='hidden'>
<input type="submit"
value="delete!"/>
</form>

這樣子會產生如下的 request body:





1
2
3
{ "id": 3,
"ignore_me": "=test"
}

但這邊值得注意的一點是,form能夠帶的 content type 只有三種:application/x-www-form-urlencoded, multipart/form-data 跟 text/plain。在上面的攻擊中我們用的是最後一種,text/plain,如果你在你的後端 Server 有檢查這個 content type 的話,是可以避免掉上面這個攻擊的。
只是,上面這幾個攻擊我們都還沒講到一種情況:如果你的 api 接受 cross origin 的 request 呢?
意思就是,如果你的 api 的 Access-Control-Allow-Origin 設成 * 的話,代表任何 domain 都可以發送 ajax 到你的 api server,這樣無論你是改成 json,或甚至把 method 改成 PUT, DELETE 都沒有用。
我們舉的例子是刪除文章,這你可能覺得沒什麼,那如果是銀行轉帳呢?攻擊者只要在自己的網頁上寫下轉帳給自己帳號的 code,再把這個網頁散佈出去就好,就可以收到一大堆錢。
講了這麼多,來講該怎麼防禦吧!先從最簡單的「使用者」開始講。

使用者的防禦

CSRF 攻擊之所以能成立,是因為使用者在被攻擊的網頁是處於已經登入的狀態,所以才能做出一些行為。雖然說這些攻擊應該由網頁那邊負責處理,但如果你真的很怕,怕網頁會處理不好的話,你可以在每次使用完網站就登出,就可以避免掉 CSRF。
或者呢,關閉執行 js 或把上面這些 pattern 的程式碼過濾掉不要執行,也是一個方法(但應該很難判定哪些是 CSRF 攻擊的程式碼)。
所以使用者能做的其實有限,真的該做事的是 Server 那邊!

Server 的防禦

CSRF 之所以可怕是因為 CS 兩個字:Cross Site,你可以在任何一個網址底下發動攻擊。CSRF 的防禦就可以從這個方向思考,簡單來說就是:「我要怎麼擋掉從別的 domain 來的 request」
你仔細想想,CSRF 的 reuqest 跟使用者本人發出的 request 有什麼區別?區別在於 domain 的不同,前者是從任意一個 domain 發出的,後者是從同一個 domain 發出的(這邊假設你的 api 跟你的前端網站在同一個 domain)

檢查 Referer

request 的 header 裡面會帶一個欄位叫做 referer,代表這個 request 是從哪個地方過來的,可以檢查這個欄位看是不是合法的 domain,不是的話直接 reject 掉即可。
但這個方法要注意的地方有三個,第一個是有些瀏覽器可能不會帶 referer,第二個是有些使用者可能會關閉自動帶 referer 的這個功能,這時候你的 server 就會 reject 掉由真的使用者發出的 request。
第三個是你判定是不是合法 domain 的程式碼必須要保證沒有 bug,例如:





1
2
3
4
const referer = request.headers.referer;
if (referer.indexOf('small-min.blog.com') > -1) {
// pass
}

你看出上面這段的問題了嗎?如果攻擊者的網頁是small-min.blog.com.attack.com的話,你的檢查就破功了。
所以,檢查 referer 並不是一個很完善的解法

加上圖形驗證碼、簡訊驗證碼等等

就跟網路銀行轉帳的時候一樣,都會要你收簡訊驗證碼,多了這一道檢查就可以確保不會被 CSRF 攻擊。
圖形驗證碼也是,攻擊者並不知道圖形驗證碼的答案是什麼,所以就不可能攻擊了。
這是一個很完善的解決方法,但如果使用者每次刪除 blog 都要打一次圖形驗證碼,他們應該會煩死吧!

加上 CSRF token

要防止 CSRF 攻擊,我們其實只要確保有些資訊「只有使用者知道」即可。那該怎麼做呢?
我們在 form 裡面加上一個 hidden 的欄位,叫做csrftoken,這裡面填的值由 server 隨機產生,並且存在 server 的 session 中。





1
2
3
4
5
<form action="https://small-min.blog.com/delete" method="POST">
<input type="hidden" name="id" value="3"/>
<input type="hidden" name="csrftoken" value="fj1iro2jro12ijoi1"/>
<input type="submit" value="刪除文章"/>
</form>

按下 submit 之後,server 比對表單中的csrftoken與自己 session 裡面存的是不是一樣的,是的話就代表這的確是由使用者本人發出的 request。這個 csrftoken 由 server 產生,並且每一段不同的 session 就應該要更換一次。
那這個為什麼可以防禦呢?因為攻擊者並不知道 csrftoken 的值是什麼,也猜不出來,所以自然就無法進行攻擊了。
可是有另外一種狀況,假設你的 server 支持 cross origin 的 request,會發生什麼事呢?攻擊者就可以在他的頁面發起一個 request,順利拿到這個 csrf token 並且進行攻擊。不過前提是你的 server 接受這個 domain 的 request。
接著讓我們來看看另外一種解法
上一種解法需要 server 的 state,亦即 csrf token 必須被保存在 server 當中,才能驗證正確性。而現在這個解法的好處就是完全不需要 server 儲存東西。
這個解法的前半段與剛剛的相似,由 server 產生一組隨機的 token 並且加在 form 上面。但不同的點在於,除了不用把這個值寫在 session 以外,同時也讓 client side 設定一個名叫 csrftoken 的 cookie,值也是同一組 token。





1
2
3
4
5
6
7
Set-Cookie: csrftoken=fj1iro2jro12ijoi1
<form action="https://small-min.blog.com/delete" method="POST">
<input type="hidden" name="id" value="3"/>
<input type="hidden" name="csrftoken" value="fj1iro2jro12ijoi1"/>
<input type="submit" value="刪除文章"/>
</form>

你可以仔細思考一下 CSRF 攻擊的 request 與使用者本人發出的 request 有什麼不一樣?不一樣的點就在於,前者來自不同的 domain,後者來自相同的 domain。所以我們只要有辦法區分出這個 request 是不是從同樣的 domain 來,我們就勝利了。
而 Double Submit Cookie 這個解法正是從這個想法出發。
當使用者按下 submit 的時候,server 比對 cookie 內的 csrftoken 與 form 裡面的 csrftoken,檢查是否有值並且相等,就知道是不是使用者發的了。
為什麼呢?假設現在攻擊者想要攻擊,他可以隨便在 form 裡面寫一個 csrf token,這當然沒問題,可是因為瀏覽器的限制,他並不能在他的 domain 設定 small-min.blog.com 的 cookie 啊!所以他發上來的 request 的 cookie 裡面就沒有 csrftoken,就會被擋下來。
當然,這個方法看似好用,但也是有缺點的,可以參考:Double Submit Cookies vulnerabilities,攻擊者如果掌握了你底下任何一個 subdomain,就可以幫你來寫 cookie,並且順利攻擊了。
會特別提到 client side,是因為我之前所碰到的專案是 Single Page Application,上網搜尋一下就會發現有人在問:「SPA 該如何拿到 CSRF token?」,難道要 server 再提供一個 api 嗎?這樣好像有點怪怪的。
但是呢,我認為我們可以利用 Double Submit Cookie 的精神來解決這個問題。而解決這問題的關鍵就在於:由 client side 來生 csrf token。就不用跟 server api 有任何的互動。
其他的流程都跟之前一樣,生成之後放到 form 裡面以及寫到 cookie。或者說如果你是 SPA 的話,也可以把這資訊直接放到 request header,你就不用在每一個表單都做這件事情,只要統一加一個地方就好。
事實上,我自己常用的 library axios 就有提供這樣的功能,你可以設置 header 名稱跟 cookie 名稱,設定好以後你每一個 request,它都會自動幫你把 header 填上 cookie 裡面的值。





1
2
3
4
5
// `xsrfCookieName` is the name of the cookie to use as a value for xsrf token
xsrfCookieName: 'XSRF-TOKEN', // default
// `xsrfHeaderName` is the name of the http header that carries the xsrf token value
xsrfHeaderName: 'X-XSRF-TOKEN', // default

那為什麼由 client 來生這個 token 也可以呢?因為這個 token 本身的目的其實不包含任何資訊,只是為了「不讓攻擊者」猜出而已,所以由 client 還是由 server 來生成都是一樣的,只要確保不被猜出來即可。Double Submit Cookie 靠的核心概念是:「攻擊者的沒辦法讀寫目標網站的 cookie,所以 request 的 csrf token 會跟 cookie 內的不一樣」

browser 本身的防禦

我們剛剛提到了使用者自己可以做的事、網頁前後端可以做的事情,那瀏覽器呢?之所以能成立 CSRF,是因為瀏覽器的機制所導致的,有沒有可能從瀏覽器方面下手,來解決這個問題呢?
有!而且已經有了。而且啟用的方法非常非常簡單。
Google 在 Chrome 51 版的時候正式加入了這個功能:SameSite cookie,對詳細運行原理有興趣的可參考:draft-west-first-party-cookies-07。
先引一下 Google 的說明:
Same-site cookies (ne “First-Party-Only” (ne “First-Party”)) allow servers to mitigate the risk of CSRF and information leakage attacks by asserting that a particular cookie should only be sent with requests initiated from the same registrable domain.
啟用這個功能有多簡單?超級無敵簡單。
你原本設置 Cookie 的 header 長這樣:





1
Set-Cookie: session_id=ewfewjf23o1;

你只要在後面多加一個 SameSite 就好:





1
Set-Cookie: session_id=ewfewjf23o1; SameSite

但其實 SameSite 有兩種模式,Lax跟Strict,默認是後者,你也可以自己指定模式:





1
2
Set-Cookie: session_id=ewfewjf23o1; SameSite=Strict
Set-Cookie: foo=bar; SameSite=Lax

我們先來談談默認的 Strict模式,當你加上 SameSite 這個關鍵字之後,就代表說「我這個 cookie 只允許 same site 使用,不應該在任何的 cross site request 被加上去」。
意思就是你加上去之後,我們上面所講的<a href="">, <form>, new XMLHttpRequest,只要是瀏覽器驗證不是在同一個 site 底下發出的 request,全部都不會帶上這個 cookie。
可是這樣其實會有個問題,連<a href="..."都不會帶上 cookie 的話,當我從 Google 搜尋結果或者是朋友貼給我的連結點進某個網站的時候,因為不會帶 cookie 的關係,所以那個網站就會變成是登出狀態。這樣子的使用者體驗非常不好。
有兩種解法,第一種是跟 Amazon 一樣,準備兩組不同的 cookie,第一組是讓你維持登入狀態,第二組則是做一些敏感操作的時候會需要用到的(例如說購買、設定帳戶等等)。第一組不設定 SameSite,所以無論你從哪邊來,都會是登入狀態。但攻擊者就算有第一組 cookie 也不能幹嘛,因為不能做任何操作。第二組因為設定了 SameSite 的緣故,所以完全避免掉 CSRF。
但這樣子還是有點小麻煩,所以你可以考慮第二種,就是調整為 SameSite 的另一種模式:Lax。
Lax 模式放寬了一些限制,例如說<a>, <link rel="prerender">, <form method="GET"> 這些都還是會帶上 cookie。但是 POST 方法 的 form,或是只要是 POST, PUT, DELETE 這些方法,就不會帶上 cookie。
所以一方面你可以保有彈性,讓使用者從其他網站連進你的網站時還能夠維持登入狀態,一方面也可以防止掉 CSRF 攻擊。但 Lax 模式之下就沒辦法擋掉 GET 形式的 CSRF,這點要特別注意一下。
講到這種比較新的東西,相信大家一定都很想知道瀏覽器的支援度如何,caniuse告訴我們說:目前只有 Chrome 支援這個新的特性(畢竟是 Google 自己推的方案,自己當然要支持一下)。
雖然瀏覽器的支援度不太高,但日後其他瀏覽器可能也會跟進實做這個方案,不妨在現在就把 SameSite 加上去,以後就不用再為 CSRF 煩惱了。
我其實只是大略的介紹一下,draft-west-first-party-cookies-07 裡面講到很多細節,例如說到底怎樣算是 cross site? 一定要在同一個 domain 嗎?那 sub domain 行不行?
好奇的可以自己研究一下,或者是這篇:SameSite Cookie,防止 CSRF 攻击也有提到。
SameSite 相關的參考資料:
  1. Preventing CSRF with the same-site cookie attribute
  2. 再见,CSRF:讲解set-cookie中的SameSite属性
  3. SameSite Cookie,防止 CSRF 攻击
  4. SameSite——防御 CSRF & XSSI 新机制
  5. Cross-Site Request Forgery is dead!

總結

這篇主要介紹了 CSRF 的攻擊原理以及兩種防禦方法,針對比較常見的場景做介紹。一般在做網頁開發的時候,比起 XSS,CSRF 是一個比較常被忽略的重點。在網頁上有任何比較重要的操作時,都要特別留意是否有被 CSRF 的風險。
這次找了很多參考資料,但發現跟 CSRF 有關的文章其實都大同小異,想知道更細節的地方需要花很多的心力去找,但幸好 Stackoverflow 上面也有不少資料可以參考。因為我在資訊安全這塊沒有涉獵太多,如果文章有哪部分講錯的話,還麻煩各位在留言不吝指出。
也感謝我朋友 shik 的指點,告訴我有 SameSite 這麼一個東西,讓我補上最後一段。
希望這篇文章能讓大家對 CSRF 有更全面的認識。

參考資料

  1. Cross-Site Request Forgery (CSRF)
  2. Cross-Site Request Forgery (CSRF) Prevention Cheat Sheet
  3. 一次较为深刻的CSRF认识
  4. [技術分享] Cross-site Request Forgery (Part 2)
  5. Spring Security Reference
  6. CSRF 攻击的应对之道

程式語言編年史

程式語言編年史原文 下面這張圖片描繪了整個程式語言的歷史。包括各種程式語言的發明人、程式語言的特點和適用領域、被什麼網站或公司使用等 (檢視 完整高清圖 )。 之所以會有那麼多不同的程式語言是因為設計程式語言的初衷不同、對語言學習曲線的追求不同、不同程式之間的執行成本差異...