Skip to main content

Passkeys Chrome 插件 Wallet

Chrome 插件能否使用 passkeys

是的,Chrome 插件(扩展程序)可以使用 Passkeys。Passkeys 是一种基于公钥加密的身份验证方法,旨在替代传统的密码。它们通常与 WebAuthn(Web Authentication API)一起使用,WebAuthn 是 FIDO2 规范的一部分。

如果你正在开发一个 Chrome 插件,并希望它能够使用 Passkeys 进行身份验证,你可以利用 WebAuthn API 来实现这一功能。以下是一个简要的步骤概述:

  1. 设置 WebAuthn 环境: 确保你的服务器和前端环境支持 WebAuthn。你需要一个安全的(HTTPS)连接,因为 WebAuthn 只能在安全的上下文中使用。

  2. 生成和注册 Passkey:

    • 当用户注册时,使用 WebAuthn API 生成一个新的公钥/私钥对。
    • 将公钥发送到服务器并存储在用户的账户信息中。
  3. 验证 Passkey:

    • 当用户登录时,使用 WebAuthn API 进行身份验证。
    • 服务器会发送一个挑战(challenge)给客户端,客户端使用私钥签名挑战并返回签名。
    • 服务器验证签名是否正确,从而验证用户的身份。

以下是一个简单的示例代码,展示如何在 Chrome 插件中使用 WebAuthn API:

// content_script.js

async function registerPasskey() {
const publicKey = {
challenge: new Uint8Array(32),
rp: {
name: 'Example',
},
user: {
id: new Uint8Array(16),
name: 'user@example.com',
displayName: 'User Example',
},
pubKeyCredParams: [
{
type: 'public-key',
alg: -7,
},
],
};

try {
const credential = await navigator.credentials.create({ publicKey });
console.log('Credential created:', credential);
// Send the credential to the server for registration
} catch (err) {
console.error('Error creating credential:', err);
}
}

async function authenticatePasskey() {
const publicKey = {
challenge: new Uint8Array(32),
allowCredentials: [
{
id: new Uint8Array(16), // The credential ID from registration
type: 'public-key',
},
],
};

try {
const assertion = await navigator.credentials.get({ publicKey });
console.log('Assertion:', assertion);
// Send the assertion to the server for verification
} catch (err) {
console.error('Error getting assertion:', err);
}
}

// Example usage
registerPasskey();
authenticatePasskey();

请注意,这只是一个简化的示例,实际应用中需要更多的错误处理和安全措施。此外,你还需要在服务器端实现相应的逻辑来处理 Passkey 的注册和验证。

通过这种方式,Chrome 插件可以利用 Passkeys 提供更安全和方便的身份验证体验。

给个完整 demo 我测试下

好的,以下是一个完整的示例,展示如何在 Chrome 插件中使用 Passkeys 进行注册和验证。这个示例包括一个简单的服务器端实现和 Chrome 插件的前端代码。

1. 服务器端代码(Node.js + Express)

首先,创建一个简单的服务器来处理注册和验证请求。你需要安装 expressbody-parser 包。

npm install express body-parser

创建一个名为 server.js 的文件,并添加以下代码:

const express = require('express');
const bodyParser = require('body-parser');
const crypto = require('crypto');

const app = express();
app.use(bodyParser.json());

let users = {}; // In-memory user storage for demo purposes

// Utility function to generate challenge
function generateChallenge() {
return crypto.randomBytes(32).toString('base64');
}

// Registration endpoint
app.post('/register', (req, res) => {
const { username, displayName } = req.body;
const userId = crypto.randomBytes(16).toString('base64');
const challenge = generateChallenge();

users[username] = {
id: userId,
displayName: displayName,
challenge: challenge,
credentials: [],
};

const publicKey = {
challenge: Buffer.from(challenge, 'base64'),
rp: {
name: 'Example',
},
user: {
id: Buffer.from(userId, 'base64'),
name: username,
displayName: displayName,
},
pubKeyCredParams: [
{
type: 'public-key',
alg: -7,
},
],
};

res.json(publicKey);
});

// Verification endpoint
app.post('/verify', (req, res) => {
const { username, credential } = req.body;
const user = users[username];
if (!user) {
return res.status(404).json({ error: 'User not found' });
}

const expectedChallenge = user.challenge;
const receivedChallenge = credential.response.clientDataJSON.challenge;

if (expectedChallenge !== receivedChallenge) {
return res.status(400).json({ error: 'Challenges do not match' });
}

// Simplified verification for demo purposes
user.credentials.push(credential);
res.json({ success: true });
});

app.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});

2. Chrome 插件代码

创建一个 Chrome 插件目录,并在其中创建以下文件:

manifest.json

{
"manifest_version": 3,
"name": "Passkey Demo",
"version": "1.0",
"permissions": ["activeTab"],
"action": {
"default_popup": "popup.html"
},
"background": {
"service_worker": "background.js"
}
}

popup.html

<!DOCTYPE html>
<html>
<head>
<title>Passkey Demo</title>
<script src="popup.js"></script>
</head>
<body>
<h1>Passkey Demo</h1>
<button id="register">Register</button>
<button id="authenticate">Authenticate</button>
</body>
</html>

popup.js

document.getElementById('register').addEventListener('click', async () => {
const username = 'user@example.com';
const displayName = 'User Example';

const response = await fetch('http://localhost:3000/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ username, displayName }),
});

const publicKey = await response.json();

try {
const credential = await navigator.credentials.create({ publicKey });
console.log('Credential created:', credential);

await fetch('http://localhost:3000/verify', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
username,
credential,
}),
});
} catch (err) {
console.error('Error creating credential:', err);
}
});

document.getElementById('authenticate').addEventListener('click', async () => {
const username = 'user@example.com';

const response = await fetch('http://localhost:3000/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ username }),
});

const publicKey = await response.json();

try {
const assertion = await navigator.credentials.get({ publicKey });
console.log('Assertion:', assertion);

await fetch('http://localhost:3000/verify', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
username,
credential: assertion,
}),
});
} catch (err) {
console.error('Error getting assertion:', err);
}
});

background.js

chrome.runtime.onInstalled.addListener(() => {
console.log('Passkey Demo extension installed');
});

3. 运行和测试

  1. 启动服务器: 在终端中运行 node server.js 启动服务器。

  2. 加载 Chrome 插件:

    • 打开 Chrome 浏览器,进入 chrome://extensions/
    • 打开右上角的“开发者模式”。
    • 点击“加载已解压的扩展程序”,选择你的插件目录。
  3. 测试注册和验证:

    • 点击浏览器工具栏中的插件图标,打开插件的弹出页面。
    • 点击“Register”按钮进行注册。
    • 点击“Authenticate”按钮进行验证。

请注意,这个示例只是一个基础的演示,实际应用中需要更多的安全措施和错误处理。

像 matemask 之类的浏览器钱包不使用 passkeys 技术,是因为 passkeys 技术有服务端,如果用了就会导致中心化,降低抗审查能力,失去区块链去中心化抗审查的初衷

你提到的观点是正确的。Passkeys 技术(基于 WebAuthn)通常需要一个服务器端来管理用户的公钥和验证流程,这确实会引入一定程度的中心化。而去中心化和抗审查是区块链技术的核心理念之一,因此像 MetaMask 这样的浏览器钱包选择了不同的身份验证方法,以保持去中心化和抗审查的特性。

以下是一些原因,解释为什么浏览器钱包如 MetaMask 没有使用 Passkeys 技术:

1. 去中心化

  • 中心化存储问题:Passkeys 需要服务器来存储用户的公钥信息,这意味着存在一个中心化的存储点。对于去中心化应用(DApps)和钱包来说,依赖中心化存储违背了去中心化的理念。
  • 自主性:区块链钱包通常让用户完全控制他们的私钥和助记词,这样用户可以完全自主地管理他们的资产,而不需要依赖任何中心化的实体。

2. 抗审查

  • 审查风险:中心化的服务器可能受到监管机构的审查和控制,从而影响用户的访问和使用。而去中心化的设计可以更好地抵御审查和控制。
  • 隐私保护:去中心化钱包不需要用户提供个人信息来进行身份验证,这在保护用户隐私方面具有显著优势。

3. 技术实现

  • 私钥管理:浏览器钱包如 MetaMask 使用的是基于助记词生成私钥的方式,这种方式简单且用户可以完全掌控自己的私钥。
  • 兼容性:区块链钱包需要与各种去中心化应用兼容,而这些应用通常依赖用户提供的私钥来签署交易。Passkeys 的使用可能会增加复杂性和兼容性问题。

4. 用户体验

  • 易用性:虽然 Passkeys 提供了更好的用户体验(如不需要记住密码),但在区块链领域,用户已经习惯了使用助记词和私钥管理他们的资产。
  • 恢复机制:区块链钱包通常有助记词作为恢复机制,而 Passkeys 依赖于设备本身,一旦设备丢失或损坏,恢复会比较困难。

总结

虽然 Passkeys 提供了安全且用户友好的身份验证方式,但由于其中心化的特性和对服务器端的依赖,它不适合去中心化和抗审查是核心要求的区块链应用。因此,像 MetaMask 这样的浏览器钱包选择了不同的身份验证方法,以保持去中心化和抗审查的特性。

如果你有兴趣开发一个去中心化的浏览器钱包,建议继续使用现有的基于助记词和私钥的身份验证方法,同时关注如何提升用户体验和安全性。