https://www.cnblogs.com/chyingp/p/websocket-deep-in.html
https://cloud.tencent.com/developer/article/1887095
https://www.ruanyifeng.com/blog/2017/05/websocket.html
websocket是一種網(wǎng)絡(luò)傳輸協(xié)議,可以在單個tcp連接上進(jìn)行全雙工通訊鹏浅,位于osi模型的應(yīng)用層(http也位于應(yīng)用層)
在 WebSocket 握手成功之后菇绵,數(shù)據(jù)的傳輸是通過已經(jīng)建立的 TCP 連接進(jìn)行的,不再需要 HTTP 的傳輸頭等額外的開銷硅瞧。
websocket與http關(guān)系
websocket復(fù)用了http的握手通道页衙,在http連接的基礎(chǔ)上,客戶端發(fā)起協(xié)議升級,采用的是標(biāo)準(zhǔn)的http報文格式俊庇,且只支持get方法,【最后數(shù)據(jù)傳輸是在tcp協(xié)議上進(jìn)行傳輸?shù)募δ樱帐诌B接是http協(xié)議】
客戶端
GET / HTTP/1.1
Host: localhost:8080
Origin: http://127.0.0.1:3000
Connection: Upgrade // 表示協(xié)議升級
Upgrade: websocket // 表示升級到websocket協(xié)議
// websocket版本辉饱,如果服務(wù)器不支持此版本,則會返回Sec-WebSocket-Version 的header拣展,里面有所有他支持的版本
Sec-WebSocket-Version: 13
// 與服務(wù)器的Sec-WebSocket-Accept配套使用彭沼,提供基本的防護(hù),比如無意鏈接备埃、惡意連接
Sec-WebSocket-Key: w4v7O6xFTi36lq3RNcgctw==
服務(wù)器端
HTTP/1.1 101 Switching Protocols // 協(xié)議切換姓惑,完成協(xié)議升級
Connection:Upgrade
Upgrade: websocket
// 這個值與客戶端Sec-WebSocket-Key有關(guān),通過SHA1散列算法獲取摘要信息值按脚,并轉(zhuǎn)成base64字符串
Sec-WebSocket-Accept: Oy4NRAQ13jhfONC7bP8dTKb4PTU=·
websocket的api
var ws = new WebSocket('ws://localhost:8080');
執(zhí)行了上面的語句于毙,websocket就會進(jìn)行連接
websocket.readyState
返回實例對象的當(dāng)前狀態(tài)
- 0(connecting):正在連接
- 1(open):連接成功可以通信
- 2(closing):正在關(guān)閉
- 3(closed):連接已關(guān)閉,或打開鏈接失敗
websocket.onOpen()
用于連接成功后的回調(diào)函數(shù)
websocket.onClose()
用于連接管壁厚的回調(diào)屬性
websocket.onMessage()
收到服務(wù)器數(shù)據(jù)后的回調(diào)函數(shù)
websocket.send()
向服務(wù)器發(fā)送數(shù)據(jù)的函數(shù)
websocket.error()
用于報錯時的回調(diào)函數(shù)
websocket.bufferedAmount
判斷發(fā)送是否結(jié)束(表示還有多少二進(jìn)制字節(jié)的數(shù)據(jù)沒有發(fā)送出去)
var data = new ArrayBuffer(10000000);
socket.send(data);
if (socket.bufferedAmount === 0) {
// 發(fā)送完畢
} else {
// 發(fā)送還沒結(jié)束
}
websocket優(yōu)點
- 基于tcp協(xié)議基礎(chǔ)上的辅搬,服務(wù)器端實現(xiàn)起來比較容易
- 與http有良好的兼容性唯沮,能夠通過http代理(握手階段采用http協(xié)議,不容易被屏蔽)
- 數(shù)據(jù)格式比較輕量堪遂,開銷小
- 沒有同源限制介蛉,客戶端可以與任意服務(wù)器通信
輪詢(短輪詢)、長輪詢和websocket區(qū)別
輪詢(短輪詢):瀏覽器每隔一段時間向服務(wù)器發(fā)送一次請求溶褪,服務(wù)器返回最新的數(shù)據(jù)給瀏覽器
長輪詢:客戶端發(fā)器請求币旧,服務(wù)器端在收到后,會不直接進(jìn)行響應(yīng)竿滨,將請求掛起佳恬,然后判斷請求的數(shù)據(jù)是否有更新捏境,或者超時才會返回給客戶端。 eg:comet的實現(xiàn)方式之一毁葱,另一種(http://www.52im.net/thread-336-1-1.html%235)
websocket:全雙工協(xié)議垫言,服務(wù)器端游數(shù)據(jù)更新后可以直接發(fā)消息給客戶端
代理緩存污染攻擊(ws引入掩碼計算為了防止此攻擊)
- 攻擊者發(fā)送ws協(xié)議升級到攻擊者服務(wù)器
- 升級請求發(fā)送到了代理服務(wù)器,經(jīng)攻擊者服務(wù)器響應(yīng)后倾剿,代理服務(wù)器將響應(yīng)回復(fù)給攻擊者筷频,連接通道打通
- 攻擊者通過WebSocket向攻擊者服務(wù)器發(fā)送數(shù)據(jù),其中包含被攻擊資源的地址前痘,以及一個偽造的host(指向被攻擊資源的服務(wù)器)
- 代理服務(wù)器會緩存數(shù)據(jù)凛捏,當(dāng)下一次被攻擊者發(fā)送請求時,會直接將緩存數(shù)據(jù)發(fā)給被攻擊者
只能說不能完全防范芹缔,但是加大了難度
websocket與cookie和token
websocket通過token傳遞信息坯癣,請求連接的時候一般不會傳入cookie,但配置后可傳(不管是連接還是數(shù)據(jù)傳輸時都是可以的)W钋贰J韭蕖!
原因:
- 理論上websocket連接請求的時候是可以帶上cookie的芝硬,因為他是在http的基礎(chǔ)上建立的蚜点,可以使用http的特性,如在握手時使用cookie進(jìn)行數(shù)據(jù)傳輸和身份認(rèn)證拌阴,但是這個cookoe不受同源策略限制绍绘。【ps:在發(fā)送數(shù)據(jù)時迟赃,因為走的tcp協(xié)議了陪拘,不在需要http的傳輸頭等額外開銷,但是如果需要的話捺氢,可以配置藻丢!】
- websocket是否攜帶cookie是可配置的,一些安全性高的站點可能會禁止websocket攜帶cookie以增加安全性和隱私性
- 實際使用上并沒有帶上cookie摄乒,而是一般使用token進(jìn)行驗證,客戶端請求時攜帶token残黑,服務(wù)端收到請求馍佑,校驗toekn時效性,判斷客戶端是否有操作權(quán)限梨水,token可以避免CSRF攻擊(token可以在客戶端和服務(wù)器端進(jìn)行交換拭荤,每次請求動態(tài)生成,攻擊者無法預(yù)判token值)
websocket配置cookie可攜帶
- 在服務(wù)器端添加自定義頭部信息疫诽,例如Set-Cookie舅世,告訴客戶端允許攜帶cookie旦委,下方以node舉例
// 服務(wù)器端
const WebSocket = require('ws');
const server = new WebSocket.Server({ port: 8080 });
server.on('connection', (socket, req) => {
// 允許攜帶 Cookie
socket.upgradeReq.headers.cookie = req.headers.cookie;
// 處理 WebSocket 連接
// ...
});
- 客戶端設(shè)置相應(yīng)頭部信息,例如** Cookie**頭雏亚,在瀏覽器中使用js缨硝,舉例
const socket = new WebSocket('ws://localhost:8080', {
headers: {
'Cookie': document.cookie
}
});
為什么websocket不建議攜帶cookie
在 WebSocket 連接中攜帶 Cookie 會增加一定的安全風(fēng)險,因此建議只在必要的情況下允許攜帶 Cookie罢低,在實際過程中查辩,按需配置
- 如果攻擊者能夠截獲websocket連接并獲取cookie,就可以冒充用戶网持,獲取用戶敏感信息宜岛,或者進(jìn)行惡意操作
- 用戶隱私問題,websocket攜帶cookie功舀,當(dāng)用戶進(jìn)行一些操作萍倡,網(wǎng)站可能會記錄這些操作并與用戶的cookie連接起來,從而產(chǎn)生一些隱私風(fēng)險
- 如果服務(wù)器用cookie來維持會話狀態(tài)辟汰,那么websocket(攜帶了cookie的)可能會干擾這種狀態(tài)的維護(hù)列敲,導(dǎo)致系統(tǒng)異常
具體情況如下:
websocket是基于tcp協(xié)議通信,不同于http協(xié)議的“請求-響應(yīng)”模式莉擒,一旦建立了連接酿炸,就可以客戶端和服務(wù)器端雙向通信,可以發(fā)送多條消息涨冀,這些消息時使用websocket自己的協(xié)議進(jìn)行傳輸?shù)奶钏叮虼瞬粫駂ttp消息一樣攜帶cookie。因此如果服務(wù)器是使用cookie來維持通信的話鹿鳖,當(dāng)出現(xiàn)多個客戶端連接時扁眯,沒有辦法識別客戶端身份因此會導(dǎo)致會話異常