高級
NIP-46 遠端簽名
深入了解 Nostr Connect 遠端簽名協議,實現跨設備安全簽名。
12 分鐘
什麼是 NIP-46?
NIP-46(Nostr Connect)定義了一種遠端簽名協議,讓應用程式可以向遠端簽名器 (如手機 App、硬體設備)請求簽名,而私鑰永遠不會離開簽名器。 這類似於 WalletConnect 在以太坊生態系統中的作用。
安全優勢: 私鑰保存在你信任的設備上(如手機),網頁應用只能請求簽名, 無法存取或匯出你的私鑰。每個請求都需要你在簽名器上確認。
運作原理
1
建立連接
客戶端生成臨時密鑰對,通過 bunker:// URI 或 nostrconnect:// 與簽名器建立連接
2
加密通訊
雙方通過中繼器交換 NIP-04/NIP-44 加密的訊息
3
請求簽名
客戶端發送簽名請求(如 sign_event),簽名器顯示確認對話框
4
返回結果
用戶確認後,簽名器返回已簽名的事件或加密結果
連接 URI 格式
bunker:// URI
由簽名器提供,客戶端掃描或輸入來連接:
bunker://<remote-signer-pubkey>?relay=<relay-url>&secret=<secret>
# 範例
bunker://a]7f6...?relay=wss://relay.nsec.app&secret=abc123
# 參數說明
- remote-signer-pubkey: 簽名器的公鑰
- relay: 用於通訊的中繼器
- secret: 可選的連接密鑰 nostrconnect:// URI
由客戶端生成,簽名器掃描來連接:
nostrconnect://<client-pubkey>?relay=<relay>&metadata=<metadata>
# 範例
nostrconnect://b8e3...?relay=wss://relay.damus.io&metadata={
"name": "My App",
"url": "https://myapp.com",
"description": "A cool Nostr app"
}
# 參數說明
- client-pubkey: 客戶端的臨時公鑰
- relay: 用於通訊的中繼器
- metadata: 應用程式資訊(JSON 編碼) RPC 方法
| 方法 | 說明 | 參數 |
|---|---|---|
| connect | 建立連接 | pubkey, secret?, perms? |
| get_public_key | 取得公鑰 | - |
| sign_event | 簽署事件 | event (JSON) |
| nip04_encrypt | NIP-04 加密 | pubkey, plaintext |
| nip04_decrypt | NIP-04 解密 | pubkey, ciphertext |
| nip44_encrypt | NIP-44 加密 | pubkey, plaintext |
| nip44_decrypt | NIP-44 解密 | pubkey, ciphertext |
| ping | 心跳檢測 | - |
訊息格式
請求訊息
// 請求格式(加密前)
{
"id": "<random-id>",
"method": "sign_event",
"params": ["<event-json>"]
}
// 作為 kind 24133 事件發送
{
"kind": 24133,
"pubkey": "<client-pubkey>",
"content": "<nip04-encrypted-request>",
"tags": [
["p", "<remote-signer-pubkey>"]
],
...
} 回應訊息
// 成功回應
{
"id": "<request-id>",
"result": "<signed-event-json>"
}
// 錯誤回應
{
"id": "<request-id>",
"error": "User rejected the request"
} 程式碼範例
使用 nostr-tools
import { Nip46Signer } from 'nostr-tools/nip46'
// 從 bunker:// URI 建立連接
const bunkerUri = 'bunker://a7f6...?relay=wss://relay.nsec.app'
const signer = new Nip46Signer(bunkerUri)
// 等待連接建立
await signer.connect()
// 取得公鑰
const pubkey = await signer.getPublicKey()
console.log('公鑰:', pubkey)
// 簽署事件
const unsignedEvent = {
kind: 1,
created_at: Math.floor(Date.now() / 1000),
tags: [],
content: 'Hello from Nostr Connect!'
}
const signedEvent = await signer.signEvent(unsignedEvent)
console.log('已簽名:', signedEvent)
// 加密訊息
const encrypted = await signer.nip04Encrypt(recipientPubkey, 'Secret message')
// 斷開連接
signer.close() 生成 nostrconnect:// URI
import { generateSecretKey, getPublicKey } from 'nostr-tools'
function generateConnectUri(relay, appMetadata) {
// 生成客戶端臨時密鑰
const clientSecret = generateSecretKey()
const clientPubkey = getPublicKey(clientSecret)
// 編碼 metadata
const metadata = encodeURIComponent(JSON.stringify(appMetadata))
// 構建 URI
const uri = `nostrconnect://${clientPubkey}?relay=${encodeURIComponent(relay)}&metadata=${metadata}`
return { uri, clientSecret, clientPubkey }
}
// 使用
const { uri } = generateConnectUri(
'wss://relay.damus.io',
{
name: 'My Nostr App',
url: 'https://myapp.com',
description: 'A cool Nostr application'
}
)
// 顯示 QR 碼讓簽名器掃描
displayQRCode(uri) 權限系統
簽名器可以要求客戶端聲明需要的權限:
// 權限字串格式
perms=sign_event:1,sign_event:4,nip04_encrypt,nip04_decrypt
// 常見權限
- sign_event:<kind> // 簽署特定類型事件
- nip04_encrypt // NIP-04 加密
- nip04_decrypt // NIP-04 解密
- nip44_encrypt // NIP-44 加密
- nip44_decrypt // NIP-44 解密
// 範例:只允許發布貼文和私訊
perms=sign_event:1,sign_event:4,nip04_encrypt,nip04_decrypt 支援的簽名器
nsec.app
Web網頁版遠端簽名器
Amber
AndroidAndroid 簽名器
Nostr Signer
iOSiOS 簽名器
Keystache
macOSmacOS 簽名器
nsecBunker
Server自架伺服器簽名器
Alby
Extension支援 NIP-46 的擴充
NIP-07 vs NIP-46
| 特性 | NIP-07 | NIP-46 |
|---|---|---|
| 簽名位置 | 同一設備(瀏覽器擴充) | 遠端設備(手機、伺服器) |
| 通訊方式 | 本地 JavaScript API | 中繼器加密訊息 |
| 跨設備 | 不支援 | 支援 |
| 適用場景 | 桌面網頁應用 | 任何環境(含行動裝置) |
| 延遲 | 低(本地) | 較高(網路) |
安全考量
優點
- • 私鑰永不離開簽名器
- • 每次請求可審核
- • 支援細粒度權限控制
- • 可跨設備使用
注意事項
- • 依賴中繼器可用性
- • 連接密鑰需妥善保管
- • 網路延遲影響體驗
- • 需要簽名器在線
常見使用場景
手機作為簽名器
在電腦上使用網頁應用,簽名請求發送到手機上的 Amber/Nostr Signer 確認。
團隊共享帳號
使用 nsecBunker 伺服器管理密鑰,多人可請求簽名而不需分享私鑰。
自動化服務
Bot 或服務可以請求人工審核後簽名,避免自動化洩露私鑰風險。
冷儲存簽名
私鑰存放在離線設備,通過 QR 碼傳遞簽名請求和結果。
開發建議: 應用程式應同時支援 NIP-07 和 NIP-46,讓用戶可以選擇使用瀏覽器擴充或遠端簽名器。 使用 nostr-tools 的統一介面可以簡化實作。
已複製連結