做者:valentinog
譯者:前端小智
來源:valentinog
點贊再看,微信搜索
【大遷世界】,B站關注
【前端小智】這個沒有大廠背景,但有着一股向上積極心態人。本文
GitHub
https://github.com/qq44924588... 上已經收錄,文章的已分類,也整理了不少個人文檔,和教程資料。
最近開源了一個 Vue 組件,還不夠完善,歡迎你們來一塊兒完善它,也但願你們能給個 star 支持一下,謝謝各位了。html
github 地址:https://github.com/qq44924588...前端
cookie 是後端能夠存儲在用戶瀏覽器中的小塊數據。 Cookie 最多見用例包括用戶跟蹤,個性化以及身份驗證。vue
Cookies 具備不少隱私問題,多年來一直受到嚴格的監管。python
在本文中,主要側重於技術方面:學習如何在前端和後端建立,使用 HTTP cookie。git
後端示例是Flask編寫的。若是你想跟着學習,能夠建立一個新的Python虛擬環境,移動到其中並安裝Flaskgithub
mkdir cookies && cd $_ python3 -m venv venv source venv/bin/activate pip install Flask
在項目文件夾中建立一個名爲flask app.py
的新文件,並使用本文的示例在本地進行實驗。web
首先,cookies 從何而來? 誰建立 cookies ?數據庫
雖然可使用document.cookie
在瀏覽器中建立 cookie,但大多數狀況下,後端的責任是在將響應客戶端請求以前在請求中設置 cookie。json
後端是指能夠經過如下方式建立 Cookie:flask
後端能夠在 HTTP 請求求中 Set-Cookie 屬性來設置 cookie,它是由鍵/值對以及可選屬性組成的相應字符串:
Set-Cookie: myfirstcookie=somecookievalue
何時須要建立 cookie? 這取決於需求。
cookie 是簡單的字符串。在項目文件夾中建立一個名爲flask_app.py
的Python文件,並輸入如下內容:
from flask import Flask, make_response app = Flask(__name__) @app.route("/index/", methods=["GET"]) def index(): response = make_response("Here, take some cookie!") response.headers["Set-Cookie"] = "myfirstcookie=somecookievalue" return response
而後運行應用程序:
FLASK_ENV=development FLASK_APP=flask_app.py flask run
當該應用程序運行時,用戶訪問http://127.0.0.1:5000/index/
,後端將設置一個具備鍵/值對的名爲Set-Cookie
的響應標頭。
(127.0.0.1:5000
是開發中的 Flask 應用程序的默認偵聽地址/端口)。
Set-Cookie
標頭是瞭解如何建立cookie的關鍵:
response.headers["Set-Cookie"] = "myfirstcookie=somecookievalue"
大多數框架都有本身設置 cookie 的方法,好比Flask的set_cookie()
。
訪問http://127.0.0.1:5000/index/
後,後端將在瀏覽器中設置cookie。 要查看此cookie,能夠從瀏覽器的控制檯調用document.cookie
:
或者能夠在開發人員工具中選中Storage
選項卡。單擊cookie,會看到 cookie 具體的內容:
在命令行上,還可使用curl
查看後端設置了哪些 cookie
curl -I http://127.0.0.1:5000/index/
能夠將 Cookie 保存到文件中以供之後使用:
curl -I http://127.0.0.1:5000/index/ --cookie-jar mycookies
在 stdout 上顯示 cookie:
curl -I http://127.0.0.1:5000/index/ --cookie-jar -
請注意,沒有HttpOnly
屬性的cookie
,在瀏覽器中可使用document.cookie
上訪問,若是設置了 HttpOnly
屬性,document.cookie
就讀取不到。
Set-Cookie: myfirstcookie=somecookievalue; HttpOnly
如今,該cookie 仍將出如今 Storage
選項卡中,可是 document.cookie
返回的是一個空字符串。
從如今開始,爲方便起見,使用Flask的 response.set_cookie()
在後端上建立 cookie。
你的瀏覽器獲得一個 cookie。如今怎麼辦呢?一旦有了 cookie,瀏覽器就能夠將cookie發送回後端。
這有許多用途發如:用戶跟蹤、個性化,以及最重要的身份驗證。
例如,一旦你登陸網站,後端就會給你一個cookie:
Set-Cookie: userid=sup3r4n0m-us3r-1d3nt1f13r
爲了在每一個後續請求中正確識別 咱們的身份,後端會檢查來自請求中瀏覽器的 cookie
要發送Cookie,瀏覽器會在請求中附加一個Cookie
標頭:
Cookie: userid=sup3r4n0m-us3r-1d3nt1f13r
默認狀況下,cookie 在用戶關閉會話時即關閉瀏覽器時過時。要持久化cookie,咱們能夠經過expires
或Max-Age
屬性
Set-Cookie: myfirstcookie=somecookievalue; expires=Tue, 09 Jun 2020 15:46:52 GMT; Max-Age=1209600
注意:Max-Age優先於expires。
考慮該後端,該後端在訪問http://127.0.0.1:5000/
時爲其前端設置了一個新的 cookie。 相反,在其餘兩條路徑上,咱們打印請求的cookie
:
from flask import Flask, make_response, request app = Flask(__name__) @app.route("/", methods=["GET"]) def index(): response = make_response("Here, take some cookie!") response.set_cookie(key="id", value="3db4adj3d", path="/about/") return response @app.route("/about/", methods=["GET"]) def about(): print(request.cookies) return "Hello world!" @app.route("/contact/", methods=["GET"]) def contact(): print(request.cookies) return "Hello world!"
運行該應用程序:
FLASK_ENV=development FLASK_APP=flask_app.py flask run
在另外一個終端中,若是咱們與根路由創建鏈接,則能夠在Set-Cookie
中看到cookie:
curl -I http://127.0.0.1:5000/ --cookie-jar cookies HTTP/1.0 200 OK Content-Type: text/html; charset=utf-8 Content-Length: 23 Set-Cookie: id=3db4adj3d; Path=/about/ Server: Werkzeug/1.0.1 Python/3.8.3 Date: Wed, 27 May 2020 09:21:37 GMT
請注意,此時 cookie 具備Path
屬性:
Set-Cookie: id=3db4adj3d; Path=/about/
/about/
路由並保存 cookit
curl -I http://127.0.0.1:5000/about/ --cookie cookies
在 Flask 應用程序的終端中運行以下命令,能夠看到:
ImmutableMultiDict([('id', '3db4adj3d')]) 127.0.0.1 - - [27/May/2020 11:27:55] "HEAD /about/ HTTP/1.1" 200 -
正如預期的那樣,cookie 返回到後端。 如今嘗試訪問 /contact/
路由:
url -I http://127.0.0.1:5000/contact/ --cookie cookies
在 Flask 應用程序的終端中運行以下命令,能夠看到:
ImmutableMultiDict([]) 127.0.0.1 - - [27/May/2020 11:29:00] "HEAD /contact/ HTTP/1.1" 200 -
這說明啥?cookie 的做用域是Path
。具備給定路徑屬性的cookie不能被髮送到另外一個不相關的路徑,即便這兩個路徑位於同一域中。
這是cookie權限的第一層。
在cookie建立過程當中省略Path
時,瀏覽器默認爲/
。
cookie 的 Domain
屬性的值控制瀏覽器是否應該接受cookie以及cookie返回的位置。
讓咱們看一些例子。
你們都說簡歷沒項目寫,我就幫你們找了一個項目,還附贈【搭建教程】。
查看 https://serene-bastion-01422.herokuapp.com/get-wrong-domain-cookie/
設置的cookie:
Set-Cookie: coookiename=wr0ng-d0m41n-c00k13; Domain=api.valentinog.com
這裏的 cookie 來自serene-bastion-01422.herokuapp.com,可是Domain
屬性具備api.valentinog.com。
瀏覽器沒有其餘選擇來拒絕這個 cookie。好比 Chrome 會給出一個警告(Firefox沒有)
查看 https://serene-bastion-01422.herokuapp.com/get-wrong-subdomain-cookie/
設置的cookie:
Set-Cookie: coookiename=wr0ng-subd0m41n-c00k13; Domain=secure-brushlands-44802.herokuapp.com
這裏的 Cookie 來自serene-bastion-01422.herokuapp.com
,但「Domain」屬性是secure-brushlands-44802.herokuapp.com
。
它們在相同的域上,可是子域名不一樣。 一樣,瀏覽器也拒絕此cookie:
查看 https://www.valentinog.com/get-domain-cookie.html
設置的cookie:
set-cookie: cookiename=d0m41n-c00k13; Domain=valentinog.com
此cookie是使用 Nginx add_header在Web服務器上設置的:
add_header Set-Cookie "cookiename=d0m41n-c00k13; Domain=valentinog.com";
這裏使用 Nginx 中設置cookie的多種方法。 Cookie 是由 Web 服務器或應用程序的代碼設置的,對於瀏覽器來講可有可無。
重要的是 cookie 來自哪一個域。
在此瀏覽器將愉快地接受cookie,由於Domain
中的主機包括cookie所來自的主機。
換句話說,valentinog.com
包括子域名www.valentinog.com
。
同時,對valentinog.com
的新請求,cookie 都會攜帶着,以及任何對valentinog.com
子域名的請求。
這是一個附加了Cookie的 www
子域請求:
下面是對另外一個自動附加cookie的子域的請求
查看 https://serene-bastion-01422.herokuapp.com/get-domain-cookie/:
設置的 cookie:
Set-Cookie: coookiename=d0m41n-c00k13; Domain=herokuapp.com
這裏的 cookie 來自serene-bas-01422.herokuapp.com
,Domain
屬性是herokuapp.com
。瀏覽器在這裏應該作什麼
你可能認爲serene-base-01422.herokuapp.com
包含在herokuapp.com
域中,所以瀏覽器應該接受cookie。
相反,它拒絕 cookie,由於它來自公共後綴列表中包含的域。
Public Suffix List(公共後綴列表)。此列表列舉了頂級域名和開放註冊的域名。瀏覽器禁止此列表上的域名被子域名寫入Cookie。
查看 https://serene-bastion-01422.herokuapp.com/get-subdomain-cookie/:
設置的 cookie:
Set-Cookie: coookiename=subd0m41n-c00k13
當域在cookie建立期間被省略時,瀏覽器會默認在地址欄中顯示原始主機,在這種狀況下,個人代碼會這樣作:
response.set_cookie(key="coookiename", value="subd0m41n-c00k13")
當 Cookie 進入瀏覽器的 Cookie 存儲區時,咱們看到已應用Domain
:
如今,咱們有來自serene-bastion-01422.herokuapp.com
的 cookie, 那 cookie 如今應該送到哪裏?
若是你訪問https://serene-bastion-01422.herokuapp.com/
,則 cookie 隨請求一塊兒出現:
可是,若是訪問herokuapp.com
,則 cookie 不會隨請求一塊兒出現:
歸納地說,瀏覽器使用如下啓發式規則來決定如何處理cookies(這裏的發送者主機指的是你訪問的實際網址):
Domain
的值包含在公共後綴列表中,則拒絕 cookieDomain
中的域或子域與訪問在主機匹配,則接受 Cookie一旦瀏覽器接受了cookie,而且即將發出請求,它就會說:
Domain
中看到的值徹底匹配,剛會回傳 cookiesub.example.dev
之類的子域,包含在example.dev
之類的 Domain 中,則將回傳 cookieexample.dev
之類的主域,而 Domain 是sub.example.dev
之類,則不會回傳cookie。Domain 和 Path 屬性一直是 cookie 權限的第二層。
Cookies 能夠經過AJAX請求傳播。 AJAX 請求是使用 JS (XMLHttpRequest或Fetch)進行的異步HTTP請求,用於獲取數據並將其發送回後端。
考慮 Flask的另外一個示例,其中有一個模板,該模板又會加載 JS 文件:
from flask import Flask, make_response, render_template app = Flask(__name__) @app.route("/", methods=["GET"]) def index(): return render_template("index.html") @app.route("/get-cookie/", methods=["GET"]) def get_cookie(): response = make_response("Here, take some cookie!") response.set_cookie(key="id", value="3db4adj3d") return response
如下是 templates/index.html
模板:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <button>FETCH</button> </body> <script src="{{ url_for('static', filename='index.js') }}"></script> </html>
下面是 static/index.js
的內容:
const button = document.getElementsByTagName("button")[0]; button.addEventListener("click", function() { getACookie(); }); function getACookie() { fetch("/get-cookie/") .then(response => { // make sure to check response.ok in the real world! return response.text(); }) .then(text => console.log(text)); }
當訪問http://127.0.0.1:5000/
時,咱們會看到一個按鈕。 經過單擊按鈕,咱們向/get-cookie/
發出獲取請求並獲取Cookie。 正如預期的那樣,cookie 落在瀏覽器的 Cookie storage中。
對 Flask 應用程序進行一些更改,多加一個路由:
from flask import Flask, make_response, request, render_template, jsonify app = Flask(__name__) @app.route("/", methods=["GET"]) def index(): return render_template("index.html") @app.route("/get-cookie/", methods=["GET"]) def get_cookie(): response = make_response("Here, take some cookie!") response.set_cookie(key="id", value="3db4adj3d") return response @app.route("/api/cities/", methods=["GET"]) def cities(): if request.cookies["id"] == "3db4adj3d": cities = [{"name": "Rome", "id": 1}, {"name": "Siena", "id": 2}] return jsonify(cities) return jsonify(msg="Ops!")
另外,調整一下 JS 代碼,用於下請求剛新增的路由:
const button = document.getElementsByTagName("button")[0]; button.addEventListener("click", function() { getACookie().then(() => getData()); }); function getACookie() { return fetch("/get-cookie/").then(response => { // make sure to check response.ok in the real world! return Promise.resolve("All good, fetch the data"); }); } function getData() { fetch("/api/cities/") .then(response => { // make sure to check response.ok in the real world! return response.json(); }) .then(json => console.log(json));
當訪問http://127.0.0.1:5000/
時,咱們會看到一個按鈕。 經過單擊按鈕,咱們向/get-cookie/
發出獲取請求以獲取Cookie。 Cookie出現後,咱們就會對/api/cities/
再次發出Fetch請求。
在瀏覽器的控制檯中,能夠看到請求回來 的數據。另外,在開發者工具的Network
選項卡中,能夠看到一個名爲Cookie的頭,這是經過AJAX請求傳給後端。
只要前端與後端在同一上下文中,在前端和後端之間來回交換cookie就能夠正常工做:咱們說它們來自同一源。
這是由於默認狀況下,Fetch 僅在請求到達觸發請求的來源時才發送憑據,即 Cookie
。
考慮另外一種狀況,在後端獨立運行,能夠這樣啓動應用程序:
FLASK_ENV=development FLASK_APP=flask_app.py flask run
如今,在 Flask 應用程序以外的其餘文件夾中,建立index.html
:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <button>FETCH</button> </body> <script src="index.js"></script> </html>
使用如下代碼在同一文件夾中建立一個名爲index.js
的 JS 文件:
button.addEventListener("click", function() { getACookie().then(() => getData()); }); function getACookie() { return fetch("http://localhost:5000/get-cookie/").then(response => { // make sure to check response.ok in the real world! return Promise.resolve("All good, fetch the data"); }); } function getData() { fetch("http://localhost:5000/api/cities/") .then(response => { // make sure to check response.ok in the real world! return response.json(); }) .then(json => console.log(json)); }
在同一文件夾中,從終端運行:
npx serve
此命令爲您提供了要鏈接的本地地址/端口
,例如http://localhost:42091/
。 訪問頁面並嘗試在瀏覽器控制檯打開的狀況下單擊按鈕。 在控制檯中,能夠看到:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:5000/get-cookie/. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing)
由於 http://localhost:5000/
與http://localhost:42091/.
不一樣。 它們是不一樣的域,所以會 CORS
的限制。
你們都說簡歷沒項目寫,我就幫你們找了一個項目,還附贈【搭建教程】。
CORS 是一個 W3C 標準,全稱是「跨域資源共享」(Cross-origin resource sharing)。它容許瀏覽器向跨域的服務器,發出XMLHttpRequest請求,從而克服了 AJAX 只能同源使用的限制。
整個 CORS 通訊過程,都是瀏覽器自動完成,不須要用戶參與。對於開發者來講,CORS 通訊與普通的 AJAX 通訊沒有差異,代碼徹底同樣。瀏覽器一旦發現 AJAX 請求跨域,就會自動添加一些附加的頭信息,有時還會多出一次附加的請求,但用戶不會有感知。所以,實現 CORS 通訊的關鍵是服務器。只要服務器實現了 CORS 接口,就能夠跨域通訊。
默認狀況下,除非服務器設置了Access-Control-Allow-Origin
的特定HTTP標頭,不然瀏覽器將阻止AJAX對非相同來源的遠程資源的請求。
要解決此第一個錯誤,咱們須要爲Flask配置CORS:
pip install flask-cors
而後將 CORS 應用於 Flask:
from flask import Flask, make_response, request, render_template, jsonify from flask_cors import CORS app = Flask(__name__) CORS(app=app) @app.route("/", methods=["GET"]) def index(): return render_template("index.html") @app.route("/get-cookie/", methods=["GET"]) def get_cookie(): response = make_response("Here, take some cookie!") response.set_cookie(key="id", value="3db4adj3d") return response @app.route("/api/cities/", methods=["GET"]) def cities(): if request.cookies["id"] == "3db4adj3d": cities = [{"name": "Rome", "id": 1}, {"name": "Siena", "id": 2}] return jsonify(cities) return jsonify(msg="Ops!")
如今嘗試在瀏覽器控制檯打開的狀況下再次單擊按鈕。在控制檯中你應該看到
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:5000/api/cities/. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing)
儘管咱們犯了一樣的錯誤,但此次的罪魁禍首是第二個路由。
你能夠經過查看 「Network」 標籤中的請求來確認,沒有發送此類Cookie:
爲了在不一樣來源的Fetch請求中包含cookie,咱們必須提credentials
標誌(默認狀況下,它是相同來源)。
若是沒有這個標誌,Fetch 就會忽略 cookie,能夠這樣修復:
const button = document.getElementsByTagName("button")[0]; button.addEventListener("click", function() { getACookie().then(() => getData()); }); function getACookie() { return fetch("http://localhost:5000/get-cookie/", { credentials: "include" }).then(response => { // make sure to check response.ok in the real world! return Promise.resolve("All good, fetch the data"); }); } function getData() { fetch("http://localhost:5000/api/cities/", { credentials: "include" }) .then(response => { // make sure to check response.ok in the real world! return response.json(); }) .then(json => console.log(json)); }
credentials: "include"
必須在第一個 Fetch 請求中出現,才能將Cookie保存在瀏覽器的Cookie storage 中:
fetch("http://localhost:5000/get-cookie/", { credentials: "include" })
它還必須在第二個請求時出現,以容許將cookie傳輸回後端
fetch("http://localhost:5000/api/cities/", { credentials: "include" })
再試一次,咱們還須要在後端修復另外一個錯誤:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:5000/get-cookie/. (Reason: expected ‘true’ in CORS header ‘Access-Control-Allow-Credentials’).
爲了容許在CORS請求中傳輸cookie,後端還須要設置 Access-Control-Allow-Credentials
標頭。
CORS(app=app, supports_credentials=True)
要點:爲了使Cookie在不一樣來源之間經過AJAX請求傳遞,能夠這樣作:
Access-Control-Allow-Credentials
和 Access-Control-Allow-Origin
用於後端cookie能夠經過AJAX請求傳遞,可是它們必須遵照咱們前面描述的域規則。
Secure 屬性是說若是一個 cookie 被設置了Secure=true
,那麼這個cookie只能用https協議發送給服務器,用 http 協議是不發送的。換句話說,cookie 是在https
的狀況下建立的,並且他的Secure=true,那麼以後你一直用https訪問其餘的頁面(好比登陸以後點擊其餘子頁面),cookie會被髮送到服務器,你無需從新登陸就能夠跳轉到其餘頁面。可是若是這是你把url改爲http協議訪問其餘頁面,你就須要從新登陸了,由於這個cookie不能在http協議中發送。
能夠這樣設置 Secure 屬性
response.set_cookie(key="id", value="3db4adj3d", secure=True)
若是要在真實環境中嘗試,請能夠運行如下命令,並注意curl
在此處是不經過HTTP
保存cookie:
curl -I http://serene-bastion-01422.herokuapp.com/get-secure-cookie/ --cookie-jar -
相反,經過HTTPS,cookie 出如今cookie jar
中:
curl -I https://serene-bastion-01422.herokuapp.com/get-secure-cookie/ --cookie-jar -
cookie jar 文件:
serene-bastion-01422.herokuapp.com FALSE / TRUE 0
不要被Secure
欺騙:瀏覽器經過HTTPS
接受cookie,可是一旦cookie進入瀏覽器,就沒有任何保護。
由於帶有 Secure 的 Cookie 通常也不用於傳輸敏感數據.
若是cookie中設置了HttpOnly屬性,那麼經過js腳本將沒法讀取到cookie信息,這樣能有效的防止XSS攻擊,竊取cookie內容,這樣就增長了cookie的安全性,即使是這樣,也不要將重要信息存入cookie。
XSS 全稱Cross SiteScript,跨站腳本攻擊,是Web程序中常見的漏洞,XSS屬於被動式且用於客戶端的攻擊方式,因此容易被忽略其危害性。其原理是攻擊者向有XSS漏洞的網站中輸入(傳入)惡意的HTML代碼,當其它用戶瀏覽該網站時,這段HTML代碼會自動執行,從而達到攻擊的目的。如,盜取用戶Cookie、破壞頁面結構、重定向到其它網站等。
若是有設置 HttpOnly 看起來是這樣的:
Set-Cookie: "id=3db4adj3d; HttpOnly"
在 Flask 中
response.set_cookie(key="id", value="3db4adj3d", httponly=True)
這樣,cookie 設置了HttpOnly
屬性,那麼經過js腳本將沒法讀取到cookie信息。若是在控制檯中進行檢查,則document.cookie
將返回一個空字符串。
什麼時候使用HttpOnly
? cookie 應該始終是HttpOnly
的,除非有特定的要求將它們暴露給運行時 JS。
查看https://serene-bastion-01422.herokuapp.com/get-cookie/
中所攜帶的 Cookie
Set-Cookie: simplecookiename=c00l-c00k13; Path=/
first-party
是指你登陸或使用的網站所發行的 cookie,而third-party
cookie 常爲一些廣告網站,有侵犯隱私以及安全隱患。
咱們將這類 Cookie 稱爲 first-party
。 也就是說,我在瀏覽器中訪問該URL,而且若是我訪問相同的URL或該站點的另外一個路徑(假設Path爲/
),則瀏覽器會將cookie發送回該網站。
如今考慮在https://serene-bastion-01422.herokuapp.com/get-frog/
上的另外一個網頁。 該頁面設置了一個cookie,此外,它還從https://www.valentinog.com/cookie-frog.jpg
託管的遠程資源中加載圖像。
該遠程資源又會自行設置一個cookie:
咱們將這種 cookie 稱爲third-party
(第三方) Cookie。
第三方 Cookie 除了用於 CSRF 攻擊,還能夠用於用戶追蹤。好比,Facebook 在第三方網站插入一張看不見的圖片。
![](facebook.com)
瀏覽器加載上面代碼時,就會向 Facebook 發出帶有 Cookie 的請求,從而 Facebook 就會知道你是誰,訪問了什麼網站。
Cookie 的SameSite 屬性用來限制third-party
Cookie,從而減小安全風險。它能夠設置三個值。
Strict
最爲嚴格,徹底禁止第三方 Cookie,跨站點時,任何狀況下都不會發送 Cookie。換言之,只有當前網頁的 URL 與請求目標一致,纔會帶上 Cookie。
Set-Cookie: CookieName=CookieValue; SameSite=Strict;
這個規則過於嚴格,可能形成很是很差的用戶體驗。好比,當前網頁有一個 GitHub 連接,用戶點擊跳轉就不會帶有 GitHub 的 Cookie,跳轉過去老是未登錄狀態。
Lax
規則稍稍放寬,大多數狀況也是不發送第三方 Cookie,可是導航到目標網址的 Get 請求除外。
Set-Cookie: CookieName=CookieValue; SameSite=Lax;
導航到目標網址的 GET 請求,只包括三種狀況:連接,預加載請求,GET 表單。詳見下表。
設置了Strict
或Lax
之後,基本就杜絕了 CSRF 攻擊。固然,前提是用戶瀏覽器支持 SameSite
屬性。
Chrome 計劃將Lax
變爲默認設置。這時,網站能夠選擇顯式關閉SameSite
屬性,將其設爲None。不過,前提是必須同時設置Secure
屬性(Cookie 只能經過 HTTPS 協議發送),不然無效。
下面的設置無效。
Set-Cookie: widget_session=abc123; SameSite=None
下面的設置有效。
Set-Cookie: widget_session=abc123; SameSite=None; Secure
身份驗證是 web 開發中最具挑戰性的任務之一。關於這個主題彷佛有不少困惑,由於JWT
中的基於令牌的身份驗證彷佛要取代「舊的」、可靠的模式,如基於會話的身份驗證。
來看看 cookie 在這裏扮演什麼角色。
身份驗證是 cookie 最多見的用例之一。
當你訪問一個請求身份驗證的網站時,後端將經過憑據提交(例如經過表單)在後臺發送一個Set-Cookie
標頭到前端。
型的會話 cookie 以下所示:
Set-Cookie: sessionid=sty1z3kz11mpqxjv648mqwlx4ginpt6c; expires=Tue, 09 Jun 2020 15:46:52 GMT; HttpOnly; Max-Age=1209600; Path=/; SameSite=Lax
這個Set-Cookie
頭中,服務器能夠包括一個名爲session
、session id
或相似的cookie
。
這是瀏覽器能夠清楚看到的惟一標識符。 每當經過身份驗證的用戶向後端請求新頁面時,瀏覽器就會發回會話cookie
。
基於會話的身份驗證是有狀態的,由於後端必須跟蹤每一個用戶的會話。這些會話的存儲多是:
在這三個會話存儲中,Redis 之類應優先於數據庫或文件系統。
請注意,基於會話的身份驗證與瀏覽器的會話存儲無關。
之因此稱爲基於會話的會話,是由於用於用戶識別的相關數據存在於後端的會話存儲中,這與瀏覽器的會話存儲不一樣。
只要能使用就使用它。基於會話的身份驗證是一種最簡單、安全、直接的網站身份驗證形式。默認狀況下,它能夠在Django
等全部流行的web框架上使用。
可是,它的狀態特性也是它的主要缺點,特別是當網站是由負載均衡器提供服務時。在這種狀況下,像粘貼會話,或者在集中的Redis存儲上存儲會話這樣的技術會有所幫助。
你們都說簡歷沒項目寫,我就幫你們找了一個項目,還附贈【搭建教程】。
JWT是 JSON Web Tokens
的縮寫,是一種身份驗證機制,近年來愈來愈流行。
JWT 很是適合單頁和移動應用程序,但它帶來了一系列新挑戰。 想要針對API進行身份驗證的前端應用程序的典型流程以下:
這種方法帶來的主要問題是:爲了使用戶保持登陸狀態,我將該令牌存儲在前端的哪一個地方?
對於前端開發來講,最天然的事情是將令牌保存在localStorage
中。 因爲許多緣由,這很糟糕。
localStorage
很容易從 JS 代碼訪問,並且它很容易成爲XSS攻擊的目標。
爲了解決此問題,大多數開發人員都將JWT令牌保存在cookie
中,覺得HttpOnly和Secure
能夠保護cookie,至少能夠免受XSS攻擊。
將 SameSite
設置爲 strict
就能夠徹底保護 JWT免受CSRF攻擊
設置爲SameSite = Strict
的新SameSite
屬性還將保護您的「熟化」 JWT免受CSRF攻擊。 可是,因爲SameSite = Strict
不會在跨域請求上發送cookie,所以,這也徹底使JWT的用例無效。
那SameSite=Lax
呢? 此模式容許使用安全的HTTP方法(即GET,HEAD,OPTIONS和TRACE)將 cookie發送回去。 POST 請求不會以任何一種方式傳輸 cookie。
實際上,將JWT
標記存儲在cookie
或localStorage
中都不是好主意。
若是你確實要使用JWT而不是堅持使用基於會話的身份驗證並擴展會話存儲,則可能要使用帶有刷新令牌的JWT
來保持用戶登陸。
自1994年以來,HTTP cookie一直存在,它們無處不在。
Cookies是簡單的文本字符串,但能夠經過Domain和Path
對其權限進行控制,具備Secure的Cookie,只能經過 HTTP S進行傳輸,而可使用 HttpOnly
從 JS隱藏。
可是,對於全部預期的用途,cookie均可能使用戶暴露於攻擊和漏洞之中。
瀏覽器的供應商和Internet工程任務組(Internet Engineering Task Force)年復一年地致力於提升cookie的安全性,最近的一步是SameSite
。
那麼,什麼纔算是比較安全cookie? ,以下幾點:
人才們的 【三連】 就是小智不斷分享的最大動力,若是本篇博客有任何錯誤和建議,歡迎人才們留言,最後,謝謝你們的觀看。
代碼部署後可能存在的BUG無法實時知道,過後爲了解決這些BUG,花了大量的時間進行log 調試,這邊順便給你們推薦一個好用的BUG監控工具 Fundebug。
原文:https://gizmodo.com/the-compl...
文章每週持續更新,能夠微信搜索 【大遷世界 】 第一時間閱讀,回覆 【福利】 有多份前端視頻等着你,本文 GitHub https://github.com/qq449245884/xiaozhi 已經收錄,歡迎Star。