블록체인 통합
SirrChat의 블록체인 통합은 EVM 지갑 서명을 사용한 비밀번호 없는 인증을 가능하게 합니다. 이 혁신적인 접근 방식은 기존 비밀번호 취약점을 제거하는 동시에 암호학적으로 안전한 액세스 제어를 제공합니다.
개요
블록체인 인증 모듈(auth.pass_blockchain)을 사용하면 사용자가 기존 비밀번호 대신 이더리움(또는 EVM 호환) 지갑 서명을 사용하여 인증할 수 있습니다.
작동 방식
- 사용자 등록: 사용자의 지갑 주소가 이메일 계정에 등록됩니다
- 인증 요청: 클라이언트가 개인 키로 챌린지 메시지에 서명합니다
- 서명 확인: 서버가 서명에서 공개 키를 복구합니다
- 액세스 부여: 복구된 주소가 등록된 주소와 일치하면 액세스가 부여됩니다
구성
기본 설정
sirrchatd.conf에 블록체인 인증 추가:
conf
# 블록체인 구성
blockchain sirrchatd {
rpc_endpoint https://mainnet.infura.io/v3/YOUR_PROJECT_ID
chain_id 1 # Ethereum Mainnet
}
# 인증 모듈
auth.pass_blockchain blockchain_auth {
blockchain &sirrchatd
storage &local_mailboxes
}
# IMAP 엔드포인트에서 사용
imap tls://0.0.0.0:993 {
auth &blockchain_auth
storage &local_mailboxes
}지원되는 체인
SirrChat은 모든 EVM 호환 블록체인을 지원합니다:
| 체인 | Chain ID | 네트워크 |
|---|---|---|
| Ethereum Mainnet | 1 | 프로덕션 |
| Ethereum Goerli | 5 | 테스트넷 |
| Ethereum Sepolia | 11155111 | 테스트넷 |
| BSC Mainnet | 56 | 프로덕션 |
| BSC Testnet | 97 | 테스트넷 |
| Polygon Mainnet | 137 | 프로덕션 |
| Polygon Mumbai | 80001 | 테스트넷 |
| Arbitrum One | 42161 | 프로덕션 |
| Optimism | 10 | 프로덕션 |
인증 흐름
1. 챌린지 생성
사용자가 인증을 시도할 때 서버는 챌린지 메시지를 생성합니다:
Challenge: <random_nonce>
Timestamp: <unix_timestamp>
Service: sirrchat2. 클라이언트 측 서명
클라이언트가 이더리움 지갑을 사용하여 챌린지에 서명합니다:
javascript
// ethers.js 사용 예제
const message = `Challenge: ${nonce}\nTimestamp: ${timestamp}\nService: sirrchat`;
const signature = await wallet.signMessage(message);3. 서버 측 확인
서버가 서명을 확인하고 주소를 복구합니다:
go
// 내부 확인 프로세스
func (bc *Ethereum) CheckSign(ctx context.Context, pk, sign, message string) (bool, error) {
hash := crypto.Keccak256Hash([]byte(message))
signature := hexutil.MustDecode(sign)
// Recover public key from signature
pubKey, err := crypto.SigToPub(hash.Bytes(), signature)
if err != nil {
return false, err
}
// Get address from public key
recoveredAddr := crypto.PubkeyToAddress(*pubKey)
// Compare with registered address
return recoveredAddr.Hex() == pk, nil
}사용자 관리
블록체인 사용자 등록
bash
# 이메일 계정에 지갑 주소 등록
sirrchatd creds create-blockchain \
--email user@example.com \
--address 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb
# 블록체인 사용자 목록
sirrchatd creds list-blockchain지갑 주소 업데이트
bash
# 기존 계정의 지갑 주소 업데이트
sirrchatd creds update-blockchain \
--email user@example.com \
--address 0xNewAddress블록체인 인증 제거
bash
# 블록체인 인증 제거 (이메일 계정은 유지)
sirrchatd creds remove-blockchain --email user@example.com클라이언트 구현
이메일 클라이언트 구성
블록체인 인증을 사용하도록 이메일 클라이언트 구성:
IMAP 설정:
- 서버: your-domain.com
- 포트: 993
- 보안: SSL/TLS
- 사용자 이름: user@example.com
- 비밀번호:
<signature>(지갑 서명)
커스텀 클라이언트 예제
커스텀 클라이언트에서 블록체인 인증을 구현하는 간단한 예제:
javascript
const ethers = require('ethers');
class BlockchainEmailAuth {
constructor(walletAddress, privateKey) {
this.wallet = new ethers.Wallet(privateKey);
this.address = walletAddress;
}
async generateAuthCredentials(challenge, timestamp) {
const message = `Challenge: ${challenge}\nTimestamp: ${timestamp}\nService: sirrchat`;
const signature = await this.wallet.signMessage(message);
return {
username: `user@example.com`,
password: signature,
address: this.address
};
}
async connectIMAP(host, port) {
// Get challenge from server
const { challenge, timestamp } = await this.getChallengeFromServer();
// Generate credentials
const creds = await this.generateAuthCredentials(challenge, timestamp);
// Connect to IMAP server
// ... use creds to authenticate
}
}보안 고려 사항
모범 사례
- 개인 키를 공유하지 마세요: 개인 키는 절대로 전송하거나 서버에 저장해서는 안 됩니다
- 하드웨어 지갑 사용: 프로덕션 사용 시 하드웨어 지갑 통합 고려
- 논스 만료 구현: 챌린지 논스는 짧은 기간 후 만료되어야 합니다
- 속도 제한: 인증 시도에 대한 속도 제한 구현
- 감사 로깅: 보안 모니터링을 위해 모든 인증 시도 기록
재생 공격 방지
서버는 재생 공격 방지 기능을 포함합니다:
conf
auth.pass_blockchain blockchain_auth {
blockchain &sirrchatd
storage &local_mailboxes
# 챌린지 구성
challenge_expiry 300s # 5분
nonce_cache_size 10000
}기존 인증 대비 장점
보안 이점
- 비밀번호 저장 없음: 비밀번호 데이터베이스 침해 제거
- 암호학적 확인: 검증된 타원 곡선 암호화 기반
- 비밀번호 재사용 없음: 각 서명이 고유함
- 피싱 방지: 자격 증명을 공개하도록 속일 수 없음
사용자 경험
- 비밀번호 관리 불필요: 사용자가 비밀번호를 기억할 필요 없음
- 멀티 디바이스: 모든 디바이스에서 동일한 지갑 사용 가능
- 복구 옵션: 비밀번호 재설정 대신 지갑 복구 메커니즘 사용
Web3 애플리케이션과의 통합
DApp 통합
DApp에 이메일 기능 통합:
javascript
// 예제: DApp에서 이메일 전송
async function sendEmailFromDApp(web3Provider) {
const signer = web3Provider.getSigner();
const address = await signer.getAddress();
// Get challenge
const challenge = await fetchChallenge();
// Sign challenge
const signature = await signer.signMessage(challenge.message);
// Authenticate and send email
await sendEmail({
from: `${address}@yourdomain.com`,
signature: signature,
to: 'recipient@example.com',
subject: 'Hello from DApp',
body: 'This email was sent using blockchain authentication!'
});
}문제 해결
일반적인 문제
서명 확인 실패
bash
# 주소가 등록되었는지 확인
sirrchatd creds list-blockchain | grep user@example.com
# 챌린지 형식 확인
# 클라이언트와 서버가 동일한 메시지 형식을 사용하는지 확인RPC 연결 문제
bash
# RPC 엔드포인트 테스트
curl -X POST https://mainnet.infura.io/v3/YOUR_PROJECT_ID \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}'고급 구성
다중 체인 지원
conf
# 여러 체인 지원
blockchain eth_mainnet {
rpc_endpoint https://mainnet.infura.io/v3/YOUR_PROJECT_ID
chain_id 1
}
blockchain bsc_mainnet {
rpc_endpoint https://bsc-dataseed1.binance.org
chain_id 56
}
auth.pass_blockchain multi_chain_auth {
blockchain ð_mainnet &bsc_mainnet
storage &local_mailboxes
}커스텀 확인 로직
커스텀 확인을 위해 블록체인 모듈 확장:
go
// 커스텀 확인 구현
type CustomBlockchainAuth struct {
baseAuth *blockchain.Ethereum
}
func (c *CustomBlockchainAuth) VerifyWithNFT(ctx context.Context, address, signature string) (bool, error) {
// Verify signature
valid, err := c.baseAuth.CheckSign(ctx, address, signature, message)
if err != nil || !valid {
return false, err
}
// Additional NFT ownership check
hasNFT, err := c.checkNFTOwnership(ctx, address)
return hasNFT, err
}API 참조
핵심 인터페이스
go
type BlockChain interface {
// Send raw transaction to blockchain
SendRawTx(ctx context.Context, rawTx string) error
// Get blockchain type
ChainType(ctx context.Context) string
// Verify signature and check if it matches public key
CheckSign(ctx context.Context, pk, sign, message string) (bool, error)
}리소스
블록체인 인증은 암호학적 확인을 통해 보안을 강화하면서 비밀번호를 제거합니다.