Security Architecture
构建安全的 Web3 后端,掌握认证授权、加密存储、审计日志。
1// SIWE (Sign-In with Ethereum) 实现2type SIWEAuth struct {3 nonceStore NonceStore4 jwtSecret []byte5}6 7func (s *SIWEAuth) GenerateNonce(address common.Address) (string, error) {8 nonce := uuid.New().String()9 if err := s.nonceStore.Set(address, nonce, 5*time.Minute); err != nil {10 return "", err11 }12 return nonce, nil13}14 15func (s *SIWEAuth) Verify(address common.Address, message, signature string) (string, error) {16 // 验证 nonce17 expectedNonce, err := s.nonceStore.Get(address)18 if err != nil {19 return "", ErrNonceExpired20 }21 22 // 解析签名23 sig, err := hexutil.Decode(signature)24 if err != nil {25 return "", ErrInvalidSignature26 }27 28 // 恢复签名者地址29 msgHash := accounts.TextHash([]byte(message))30 sig[64] -= 27 // 调整 V 值31 32 pubKey, err := crypto.SigToPub(msgHash, sig)33 if err != nil {34 return "", ErrInvalidSignature35 }36 37 recoveredAddr := crypto.PubkeyToAddress(*pubKey)38 if recoveredAddr != address {39 return "", ErrAddressMismatch40 }41 42 // 签发 JWT43 token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{44 "address": address.Hex(),45 "exp": time.Now().Add(24 * time.Hour).Unix(),46 })47 48 return token.SignedString(s.jwtSecret)49}1// 使用 KMS 加密私钥2type SecureKeyStore struct {3 kmsClient *kms.Client4 keyID string5}6 7func (s *SecureKeyStore) StorePrivateKey(ctx context.Context, address string, privateKey []byte) error {8 // 使用 KMS 加密9 encrypted, err := s.kmsClient.Encrypt(ctx, &kms.EncryptInput{10 KeyId: aws.String(s.keyID),11 Plaintext: privateKey,12 })13 if err != nil {14 return err15 }16 17 // 存储加密后的私钥18 return s.db.StoreEncryptedKey(address, encrypted.CiphertextBlob)19}20 21func (s *SecureKeyStore) SignTransaction(ctx context.Context, address string, tx *types.Transaction) (*types.Transaction, error) {22 // 获取加密私钥23 encryptedKey, err := s.db.GetEncryptedKey(address)24 if err != nil {25 return nil, err26 }27 28 // KMS 解密29 decrypted, err := s.kmsClient.Decrypt(ctx, &kms.DecryptInput{30 CiphertextBlob: encryptedKey,31 })32 if err != nil {33 return nil, err34 }35 36 // 签名后立即清除内存中的私钥37 defer func() {38 for i := range decrypted.Plaintext {39 decrypted.Plaintext[i] = 040 }41 }()42 43 privateKey, err := crypto.ToECDSA(decrypted.Plaintext)44 if err != nil {45 return nil, err46 }47 48 return types.SignTx(tx, types.LatestSignerForChainID(tx.ChainId()), privateKey)49}1type AuditLog struct {2 ID string3 Timestamp time.Time4 Actor string // 操作者地址5 Action string // 操作类型6 Resource string // 操作对象7 Details JSON // 详细信息8 IPAddress string9 UserAgent string10 Result string // success/failure11 Signature string // 日志签名防篡改12}13 14func (s *AuditService) Log(ctx context.Context, log *AuditLog) error {15 // 生成日志签名16 log.Signature = s.signLog(log)17 18 // 写入不可变存储(可选上链)19 if err := s.store.Append(log); err != nil {20 return err21 }22 23 // 发送到 SIEM 系统24 s.siem.Send(log)25 26 return nil27}