如何在浏览器扩展中存储用户密码?技术实现咨询
浏览器扩展存储用户凭证的实现方案
首先,你得先在扩展的manifest.json里声明storage权限,不然没法用Chrome的存储API,另外你代码里用到了tabs.update,所以tabs权限也得加上:
{ "manifest_version": 3, // 其他必填配置(比如name、version等) "permissions": ["storage", "tabs"] }
核心注意点:别存明文密码!
密码属于敏感数据,直接存明文风险极高,必须加密后再存储。这里用浏览器原生支持的Web Crypto API做AES-GCM加密,是安全可靠的方案。
实现加密存储逻辑
先写加密、解密的工具函数:
// 生成加密密钥 async function generateKey() { return window.crypto.subtle.generateKey( { name: "AES-GCM", length: 256 }, true, ["encrypt", "decrypt"] ); } // 加密数据 async function encryptData(data, key) { const encoder = new TextEncoder(); const dataBytes = encoder.encode(data); const iv = window.crypto.getRandomValues(new Uint8Array(12)); // AES-GCM推荐12字节IV const encrypted = await window.crypto.subtle.encrypt( { name: "AES-GCM", iv: iv }, key, dataBytes ); // 把IV和加密后的数据转成Base64,方便存储 return { iv: btoa(String.fromCharCode(...iv)), encryptedData: btoa(String.fromCharCode(...new Uint8Array(encrypted))) }; } // 解密数据 async function decryptData(encryptedObj, key) { const iv = new Uint8Array(atob(encryptedObj.iv).split("").map(c => c.charCodeAt(0))); const encryptedData = new Uint8Array(atob(encryptedObj.encryptedData).split("").map(c => c.charCodeAt(0))); const decrypted = await window.crypto.subtle.decrypt( { name: "AES-GCM", iv: iv }, key, encryptedData ); const decoder = new TextDecoder(); return decoder.decode(decrypted); }
修改现有代码,加入存储逻辑
当用户输入正确密码后,加密并存储到Chrome本地存储(chrome.storage.local,如果需要同步到用户Chrome账号,改用chrome.storage.sync):
button.addEventListener("click", async function () { let inputVal = document.getElementById("input").value; const correctPassword = "ramo"; if (inputVal === correctPassword) { text.style.display = "none"; chrome.tabs.update({ url: "https://www.youtube.com" }); // 加密并存储密码 const key = await generateKey(); // 把密钥转成可存储的Base64格式 const exportedKey = await window.crypto.subtle.exportKey("raw", key); const keyBase64 = btoa(String.fromCharCode(...new Uint8Array(exportedKey))); const encryptedObj = await encryptData(correctPassword, key); // 存储密钥和加密后的密码 await chrome.storage.local.set({ encryptedPassword: encryptedObj, encryptionKey: keyBase64 }); } else { toggleText(); } });
后续验证逻辑:读取存储的凭证
下次用户打开扩展时,先读取存储的加密数据,解密后和用户输入比对,避免重复输入:
// 页面加载时检查是否已存储凭证 async function checkStoredCredentials() { const storedData = await chrome.storage.local.get(["encryptedPassword", "encryptionKey"]); if (storedData.encryptedPassword && storedData.encryptionKey) { // 导入密钥 const keyBytes = new Uint8Array(atob(storedData.encryptionKey).split("").map(c => c.charCodeAt(0))); const key = await window.crypto.subtle.importKey( "raw", keyBytes, { name: "AES-GCM", length: 256 }, true, ["encrypt", "decrypt"] ); // 解密密码 const decryptedPassword = await decryptData(storedData.encryptedPassword, key); // 自动填充输入框,或直接用解密后的密码做验证 document.getElementById("input").value = decryptedPassword; } } // 页面加载时调用 document.addEventListener("DOMContentLoaded", checkStoredCredentials);
额外提醒
- 如果是存储用户自定义密码(不是固定的"ramo"),逻辑完全一致:先验证输入合法性,再加密存储
chrome.storage.local的数据隔离在扩展沙箱内,比普通localStorage更安全,但加密步骤不能省,防止扩展被攻破后数据泄露- 跨设备同步凭证用
chrome.storage.sync,但注意该存储有容量限制(单扩展最多100KB)
内容的提问来源于stack exchange,提问作者Sao Petrik
相关产品推荐
相关产品推荐

