在瀏覽器中存儲token的最佳實踐

在瀏覽器中存儲token的最佳實踐

Web 應用程序不是靜態站點,而是靜態和動態內容的精心組合。更常見的是,Web 應用程序邏輯在瀏覽器中運行。該應用程序不是從服務器獲取所有內容,而是在瀏覽器中運行 JavaScript,從后端 API 獲取數據并相應地更新 Web 應用程序演示。

為了保護對數據的訪問,我們應采用 OAuth 2.0。使用 OAuth 2.0,JavaScript 應用程序需要向 API 的每個請求添加訪問 token 。
出于可用性原因,JavaScript 應用程序通常不會按需請求訪問 token ,而是存儲它。問題是,如何在 JavaScript 中獲取這樣的 token ?當我們獲得 token 時,應用程序應該將 token 存儲在哪里,以便在需要時將其添加到請求中?

本文將討論瀏覽器中可用的不同存儲解決方案,并重點介紹與每個選項相關的安全風險。

獲取訪問 token

在應用程序可以存儲訪問 token 之前,它需要獲取一個。當前的最佳實踐推薦一種獲取訪問 token 的方法:代碼流。代碼流程分為兩步,首先從用戶那里收集授權——授權代碼。然后,應用程序在反向通道請求中用授權代碼交換訪問 token 。此請求稱為 token 請求,如以下示例所示:

const accessToken = await fetch(OAuthServerTokenEndpoint, {
method: "POST",
// 獲取token
body: new URLSearchParams({client_id: "example-client",
grant_type: "authorization_code",
code: authorization_code,code_verifier: pkce_code_verifier
})
})
.then (response => response.json())
.then (tokenResponse => {// 從響應中獲取tokenif (tokenResponse.accessToken) {return tokenResponse.accessToken;}
})

請注意,任何人都可以檢查瀏覽器加載的資源,包括任何JavaScript 代碼。因此,任何用 JavaScript 實現的 OAuth 客戶端都被視為公共客戶端——無法保守秘密,因此無法在 token 請求期間進行身份驗證。

瀏覽器威脅

跨站請求偽造 (CSRF)

在跨站點請求偽造 (CSRF)攻擊中,惡意行為者會誘騙用戶無意中通過瀏覽器執行惡意請求。例如,攻擊者可能會在網站中嵌入精心設計的圖像 src 字符串,從而觸發瀏覽器運行 GET 請求,或者在惡意網站上添加表單來觸發 POST 請求。在任何情況下,瀏覽器都可能會自動向此類請求添加 cookie,包括單點登錄 (SSO) cookie。

CSRF 攻擊通常利用用戶經過身份驗證的會話來執行惡意請求。因此,攻擊者可以代表用戶靜默執行請求并調用用戶可以調用的任何接口。不過,攻擊者無法讀取響應,因此他們通常會提出一次性狀態更改請求,例如更新用戶密碼。

跨站腳本 (XSS)

跨站點腳本 (XSS)漏洞允許攻擊者將惡意客戶端代碼注入到其他受信任的網站中。例如,漏洞可能發生在 Web 應用程序中用戶輸入生成未正確清理的輸出的任何位置。瀏覽器會自動在受信任網站的上下文中運行惡意代碼。

XSS 攻擊可用于竊取訪問和刷新 token 或執行 CSRF 攻擊。不過,XSS 攻擊有一個時間窗口,因為它們只能在有限的時間內運行,例如在 token 的生命周期內或只要存在漏洞的選項卡處于打開狀態。

即使在 XSS 無法用于檢索訪問 token 的情況下,攻擊者也可能利用 XSS 漏洞,使用 CSRF 將經過身份驗證的請求發送到安全的 Web 端點。然后,攻擊者可以冒充用戶,調用用戶可以調用的任何后端接口,并造成嚴重損害。

瀏覽器中的存儲解決方案

當應用程序收到 token 時,它需要存儲該 token 以便在 API 請求中使用它。有多種方法可以在用戶的??瀏覽器中保存數據。應用程序可以使用專用 API(例如 Web Storage API 或 IndexedDB)來存儲 token 。應用程序還可以簡單地將 token 保留在內存中或將它們放入 cookie 中。有些存儲機制是持久性的,而另一些存儲機制在一段時間后或在頁面關閉或刷新時會被擦除。

本地存儲

使用 JavaScript 中的全局對象通過 Web Storage API 訪問本地存儲localStorage。存儲在本地存儲中的數據可跨瀏覽器選項卡和會話使用,這意味著它不會過期,也不會在瀏覽器關閉時被刪除。因此,通過 localStorage 存儲的數據可以在應用程序的所有選項卡中訪問。

// 保存數據
localStorage.setItem("token", accessToken);
// 加載數據
let accessToken = localStorage.getItem("token");

每當應用程序調用 API 時,它都會從存儲中獲取 token 并將其手動添加到請求中。然而,由于本地存儲可通過 JavaScript 獲得,這意味著該解決方案也容易受到跨站點腳本攻擊 (XSS)。

如果我們使用 localStorage 來持久保存訪問 token ,并且攻擊者設法在我們的應用程序中運行外部 JavaScript 代碼,則攻擊者可以竊取任何 token 并直接調用 API。此外,XSS還允許攻擊者操縱應用程序本地存儲中的數據,這意味著攻擊者可以更改 token 。

請注意,本地存儲中的數據是永久存儲的,這意味著存儲在其中的任何 token 都駐留在用戶設備(筆記本電腦、計算機、移動設備或其他設備)的文件系統上,即使在瀏覽器關閉后也可以被其他應用程序訪問。因此,在使用 localStorage 時,請考慮安全性。考慮并防范瀏覽器外部的攻擊媒介,例如惡意軟件、被盜設備或磁盤。

根據上述討論,請遵循以下建議:

  • 不要在本地存儲中存儲 token 等敏感數據。
  • 不要信任本地存儲中的數據(尤其是用于身份驗證和授權的數據)。

會話存儲

會話存儲是Web Storage API 提供的另一種存儲機制。與本地存儲不同,當選項卡或瀏覽器關閉時,使用sessionStorage對象存儲的任何數據都會被擦除。此外,存儲在會話存儲中的數據無法在其他選項卡中訪問。只有當前選項卡和源中的 JavaScript 代碼可以使用相同的會話存儲進行讀寫。

// 存儲token
sessionStorage.setItem("token", accessToken);
// 獲取token
let accessToken = sessionStorage.getItem("token");

會話存儲可以被認為比本地存儲更安全,因為瀏覽器會在窗口關閉時自動刪除任何 token ,因此不會留下任何 token 。此外,由于會話存儲不在選項卡之間共享,攻擊者無法從另一個選項卡(或窗口)讀取 token ,這減少了 XSS 攻擊的影響。

實際上,使用 sessionStorage 存儲 token 時的主要安全問題是 XSS。如果我們的應用程序容易受到 XSS 攻擊,攻擊者可以從存儲中竊取 token 并在 API 調用中重放它。因此,會話存儲不適合存儲 token 等敏感數據。

indexedDB

IndexedDB 是一個用于在瀏覽器中異步存儲大量數據的 API。但是,在存儲 token 時,通常不需要瀏覽器 API 提供的功能。由于應用程序會在每次 API 調用時發送 token ,因此最好將其大小保持在最低限度。

與迄今為止討論的其他客戶端存儲機制一樣,對使用索引數據庫 API 存儲的數據的訪問受到同源策略的限制。只有同源的資源和服務工作者才能訪問數據。從安全角度來看,IndexedDB 與本地存儲相當:

  • token 可能會通過文件系統泄漏。
  • token 可能會通過 XSS 攻擊泄漏。

因此,請勿在 IndexedDB 中存儲訪問 token 或其他敏感數據。IndexedDB更適合應用程序離線工作所需的數據,例如圖像。

存儲在內存中

存儲 token 的一種非常安全的方法是將其保存在內存中。與其他方法相比, token 不存儲在文件系統中,從而降低了設備文件系統的風險。

最佳實踐建議將 token 存儲在內存中時將其保留在閉包中。例如,我們可以定義一個單獨的方法來使用 token 調用 API。它不會向主應用程序(主線程)透露 token 。下面是如何使用 JavaScript 處理內存中的 token 的示例。

function protectedCalls(tokenResponse) {const accessToken = tokenResponse.accessToken;return {// 使用內存中的token發送請求getOrders: () => {const req = new Request("https://server.example/orders");req.headers.set("Authorization", accessToken);return fetch(req)}}
}
const apiClient = protectedCalls(tokenResponse);
apiClient.getOrders();

請注意,攻擊者在獲取 token 后可能無法直接訪問 token ,因此可能無法直接使用 token 調用 API。即便如此,他們也可以隨時通過apiClient保存 token 引用的 API 調用 API。然而,任何此類攻擊都僅限于選項卡打開的時間段以及界面提供的功能。

除了與潛在 XSS 漏洞相關的安全問題之外,將 token 保留在內存中對于用戶體驗也有很大的缺點,因為 token 會在頁面重新加載時丟失。然后,應用程序必須獲取新的 token ,這可能會觸發新的用戶身份驗證。安全的設計應該考慮用戶體驗。

當使用 JavaScript 閉包或服務工作人員處理 token 和 API 請求時,XSS 攻擊可能會針對 OAuth 流(例如回調或靜默流)來獲取 token 。他們可能會取消注冊并繞過任何服務,或者使用原型污染通過覆蓋諸如window.fetch. 因此,考慮 JavaScript 閉包是為了方便,而不是安全。

cookie

Cookie 是存儲在瀏覽器中的數據片段。根據設計,瀏覽器會向服務器的每個請求添加 cookie。因此,應用程序必須謹慎使用 cookie。如果配置不仔細,瀏覽器可能會在跨站點請求中附加 cookie,并允許跨站點請求偽造 (CSRF) 攻擊。

Cookie 具有控制其安全屬性的屬性。例如,SameSite 屬性可以幫助降低 CSRF 攻擊的風險。當 Cookie 的 SameSite 屬性設置為 時Strict,瀏覽器會將其添加到源自 Cookie 來源站點且目標站點相同的請求中。當請求嵌入任何第三方網站(例如通過鏈接)時,瀏覽器不會添加 cookie。

我們可以通過 JavaScript 設置和檢索 cookie。然而,當使用 JavaScript 讀取 cookie 時,應用程序容易受到 XSS(除了 CSRF 之外)的攻擊。因此,首選方案是使用一個后端組件來設置 cookie 并將其標記為HttpOnly. 該標志可以減少 XSS 攻擊造成的數據泄露,因為它向瀏覽器表明 cookie 不能通過 JavaScript 獲得。

為了防止 cookie 通過中間人攻擊泄漏(這可能會導致會話劫持),cookie 只能通過加密連接 (HTTPS) 發送。要指示瀏覽器僅在 HTTPS 請求中發送 cookie,cookie 必須設置安全屬性。

Set-Cookie:token=myvalue;SameSite=Strict;Secure;HttpOnly

與瀏覽器中的任何其他永久存儲解決方案一樣,即使瀏覽器關閉后,cookie 也可能駐留在文件系統上(例如,cookie 不必過期,或者瀏覽器可以保留會話 cookie 作為恢復會話功能的一部分)。為了降低從文件系統中竊取 token 的風險,請僅將加密 token 存儲在 cookie 中。因此,后端組件必須僅在 Set-Cookie 標頭中返回加密 token 。

帶有 Cookie 的 OAuth 語義

Cookie 仍然是傳輸 token 和充當 API 憑證的最佳選擇,因為即使攻擊者成功利用 XSS 漏洞,也無法從 Cookie 中檢索訪問 token 。然而,要實現這一點,必須正確配置 cookie。

首先,將 cookie 標記為HttpOnly無法通過 JavaScript 訪問,以解決 XSS 攻擊的風險。另一個重要屬性是secure ,可確保 cookie 僅通過 HTTPS 發送,以減輕中間人攻擊。

其次,頒發僅在幾分鐘內有效的短期訪問 token 。在最壞的情況下,具有最短生命周期的訪問 token 只能在可接受的短時間內被濫用。通常認為 15 分鐘的有效時間是合適的。讓 cookie 和 token 大約在同一時間過期。

第三,將 token 視為敏感數據。僅在 cookie 中存儲加密 token 。如果攻擊者設法獲得加密 token ,他們將無法從中解析任何數據。攻擊者也無法將加密的 token 重放給任何其他 API,因為其他 API 無法解密該 token 。加密 token 只是限制了被盜 token 的影響。

第四,限制發送 API 憑證的時間。僅將 cookie 發送到需要 API 憑據的資源。這意味著確保瀏覽器僅將 cookie 添加到實際需要訪問 token 的 API 調用中。為此,cookie 需要具有適當的設置,例如SameSite=Strict指向 API 端點的域和路徑的域屬性。

最后,當使用刷新 token 時,請確保將它們存儲在自己的 cookie 中。無需在每個 API 請求中都發送它們,因此請確保情況并非如此。僅當刷新過期的訪問 token 時才必須添加刷新 token 。這意味著持有刷新 token 的 cookie 與具有訪問 token 的 cookie 的設置略有不同。

結論

使用 OAuth 和 token 可以最好地保護 API 訪問。沒有安全的解決方案可以在瀏覽器中存儲 token 。所有可用的解決方案在某種程度上都容易受到 XSS 的攻擊。因此,保護??任何應用程序的首要任務應該是防止 XSS 漏洞。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/210902.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/210902.shtml
英文地址,請注明出處:http://en.pswp.cn/news/210902.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Tomcat部署開源站點JPress

前言 JPress使用Java開發,是我們常見的開源博客系統。JPress是一個開源的WordPress插件,它提供了一個簡單而強大的方式來創建企業級站點。該插件包括許多特性,例如主題定制、頁面構建器、性能優化、SEO、安全、電子商務和社交媒體整合等。使用…

Linux卸載MySql(簡潔版)

安裝MySql https://blog.csdn.net/tongxin_tongmeng/article/details/128263398 停止服務 service mysql stop 刪除服務 chkconfig --del mysql 刪除目錄 rm -rf /opt/mysql 刪除配置 rm -f /etc/my.cnf 刪除啟動腳本 rm -f /etc/init.d/mysql 刪除用戶和組 userdel mysql &am…

C_1練習題答案

1.在一個C程序中() A. main函數必須出現在所有函數之前 B. main函數可以出現在任何地方 C. main函數必須出現在所有函數之后 D. main 函數必須出現在固定位置 B 2.下列不合法的用戶標識符是() A. j2_KEY B. Double C. 4d_a D.8 C 3,在“文件包含”預處理語句的使用過程…

thinkphp6入門(12)-- 一對一關聯模型

定義一對一關聯,例如,一個用戶都有一個個人資料。 一、兩表 1.用戶表:user 2.工作經驗表:work_experience user表的id關聯work_experience表的user_id。 注意看,user_id1的有2條工作經驗 二、數據模型 主表模型:…

Linux 定時任務備份MySQL數據庫

Linux 定時任務基本知識 crontab yum install crontabs (安裝 crontabs) systemctl enable crond (設為開機啟動) systemctl start crond(啟動crond服務) systemctl status crond (查看狀態&a…

STM32F407-14.3.9-02輸出比較模式

輸出比較模式 輸出比較模式生成波形時 當采用上升沿或下降沿計數時,更改ARR的值可改變周期; 更改CCRx的值會影響到生成波形的相位。波形的占空比永遠50% 當采用中心對齊模式時, 更改ARR的值可以改變周期,更改CCRx的值可以改…

操作系統考研筆記(王道408)

文章目錄 前言計算機系統概述OS的基本概念OS的發展歷程OS的運行機制OS體系結構OS引導虛擬機 進程和線程進程和線程基礎進程進程狀態進程控制進程通信線程線程實現 CPU調度調度的層次進程調度細節調度算法評價指標批處理調度算法交互式調度方法 同步與互斥基本概念互斥互斥軟件實…

Plantuml之類圖語法介紹(十六)

簡介: CSDN博客專家,專注Android/Linux系統,分享多mic語音方案、音視頻、編解碼等技術,與大家一起成長! 優質專欄:Audio工程師進階系列【原創干貨持續更新中……】🚀 優質專欄:多媒…

STM32基于USB串口通信應用開發

?作者簡介:熱愛科研的嵌入式開發者,修心和技術同步精進, 代碼獲取、問題探討及文章轉載可私信。 ? 愿你的生命中有夠多的云翳,來造就一個美麗的黃昏。 🍎獲取更多嵌入式資料可點擊鏈接進群領取,謝謝支持!…

人工智能:走向智能化未來的探索

前言 人工智能(Artificial Intelligence,簡稱AI)是當今科技領域最引人注目的發展方向之一。從虛構作品中的機器人到現實生活中的智能助手,AI正深刻地改變著我們的生活方式、工作方式以及與技術互動的方式。本文將深入探討人工智能…

對無向圖進行鄰接矩陣的轉化,并且利用DFS(深度優先)和BFS(廣度優先)算法進行遍歷輸出, 在鄰接矩陣存儲結構上,完成最小生成樹的操作。

一 實驗目的 1.掌握圖的相關概念。 2.掌握用鄰接矩陣和鄰接表的方法描述圖的存儲結構。 3.掌握圖的深度優先搜索和廣度優先搜索遍歷的方法及其計算機的實現。 4.理解最小生成樹的有關算法 二 實驗內容及要求 實驗內容&#…

模電·放大電路的分析方法——圖解法

放大電路的分析方法——圖解法 靜態工作點的分析電壓放大倍數的分析波形非線性失真的分析直流負載線與交流負載線圖解法的適用范圍 在實際測出放大管的輸入特性、輸出特性和已知放大電路中其它各元件參數的情況下,利用作圖的方法對放大電路進行分析即為圖解法。 靜…

postgresql自帶指令命令系列三

目錄 簡介 bin目錄 28.pg_verifybackup 29.pg_waldump 30.postgres 31.postmaster -> postgres 32.psql 33.reindexdb 34.vacuumdb 35.vacuumlo 總結: 簡介 在安裝postgresql數據庫的時候會需要設置一個關于postgresql數據庫的PATH變量 export PATH/…

笙默考試管理系統-MyExamTest----codemirror(51)

笙默考試管理系統-MyExamTest----codemirror(51) 目錄 笙默考試管理系統-MyExamTest----codemirror(51) 一、 笙默考試管理系統-MyExamTest----codemirror 二、 笙默考試管理系統-MyExamTest----codemirror 三、 笙默考試…

python模塊rsa,非對稱加密算法庫

一、簡介 RSA(Rivest-Shamir-Adleman)是一種非對稱加密算法,廣泛應用于數據加密和數字簽名等安全領域。以下是對RSA算法的介紹以及其優缺點: 1.密鑰生成:RSA算法生成一對密鑰,包括公鑰和私鑰。公鑰用于加密…

Linux CentOS 7.6安裝jdk1.8教程

安裝教程 第一種方式(通過yum安裝):第一步:輸入查找命令:第二步:輸入安裝命令:第三步:安裝完成,輸入安裝命令后,等到出現Complete!代表安裝完成第…

PyTorch實現邏輯回歸

最終效果 先看下最終效果: 這里用一條直線把二維平面上不同的點分開。 生成隨機數據 #創建訓練數據 x torch.rand(10,1)*10 #shape(10,1) y 2*x (5 torch.randn(10,1))#構建線性回歸參數 w torch.randn((1))#隨機初始化w,要用到自動梯度求導 b …

使用 ROS 和 Geomagic Haptic 驅動 Franka 機械臂

文章目錄 前言一、安裝 franka_ros二、安裝 OpenHaptics for Linux三、安裝 3D Systems Geomagic Touch ROS Driver四、安裝 franka_interactive_controllers五、使用 Geomagic Haptic 驅動 Franka 機械臂 前言 本文為在雙系統上使用 ROS 和 Geomagic Haptic 驅動 Franka 機械…

滑動窗口(單調隊列)

154. 滑動窗口 - AcWing題庫 給定一個大小為 n≤10^6≤10^6 的數組。 有一個大小為 k 的滑動窗口,它從數組的最左邊移動到最右邊。 你只能在窗口中看到 k 個數字。 每次滑動窗口向右移動一個位置。 以下是一個例子: 該數組為 [1 3 -1 -3 5 3 6 7]&…

HashMap的那些事

一、HashMap與HashTable的區別 1.來歷 HashTable是一種鍵值映射的數據結構,自從java發布就存在,而HashMap是jdk1.2后才出現的,雖然說HashTable出現得早且線程安全,但是效率很低已經棄用了,現在HashMap逐漸成為主流 …