비공개 페이마스터 릴레이
Anon 릴레이는 Oblivious HTTP(OHTTP)로 지갑의 네트워크 신원과 페이마스터 요청을 분리합니다. 릴레이는 브라우저 연결을 받지만 복호화하지 못합니다. 페이마스터는 브라우저가 아닌 릴레이로부터 받아 복호화·처리합니다.
목표는 어느 단일 운영자도 사용자 IP와 페이마스터 거래 요청을 연결할 수 없게 하는 것입니다. 결과 거래가 온체인에 공개하는 정보는 숨기지 않습니다.
Wallet Independent relay Paymaster
| | |
| HPKE-encrypted request | |
|-------------------------->| opaque request |
| |----------------------------->|
| | decrypt, validate,
| | sponsor, and submit
| |<-----------------------------|
| encrypted response | |
|<--------------------------| |
sees: request + own IP sees: client IP + ciphertext sees: request + relay IP
비공개 요청 내용
지갑은 서명 거래, 영지식 증명, 수수료 견적·토큰을 로컬에서 준비해 내부 요청으로 인코딩하고 현재 페이마스터 HPKE 공개 키로 암호화합니다.
릴레이는 OHTTP 암호문만 받아 거래, 증명, 토큰, 주소, 응답을 읽지 못합니다. HPKE 개인 키를 가진 페이마스터가 엽니다. 비공개 Railgun 작업의 쉴드 세부 정보는 프로토콜 증명이 계속 보호하며, 릴레이는 브라우저 연결과 제출 간 전송 계층 연결 방지를 더합니다.
요청 흐름
- 지갑에는 릴레이 URL과 독립적으로 고정한 Ed25519 서명 키가 필요합니다. 운영값은 well-known 검색 문서에도 있습니다.
- 릴레이에서
GET /ohttp-configs를 받아 고정 키로 HPKE KeyConfig를 검증합니다. 릴레이의 키 바꿔치기를 막습니다. - 가스 견적·지원 토큰 등 신원 없는 공개 읽기도 릴레이로 가져옵니다. 허용 목록에 있으며 상위
Cache-Control에 따라 캐시할 수 있습니다. - 비공개 실행·상태 요청을 HPKE로 봉인해
POST /gateway에message/ohttp-req로 보냅니다. - 릴레이는 고정 대상에 암호문을 전달합니다. 사용자 입력으로 대상을 선택하지 않는 폐쇄형 프록시입니다.
- 페이마스터가 복호화 후 증명, 서명 견적, 수수료, 거래를 검증하고 승인 작업을 온체인에 제출합니다.
- 암호화된 응답을 릴레이가 읽지 못한 채
message/ohttp-res로 돌려줍니다.
각 주체의 관찰 범위
| 주체 | 볼 수 있음 | 설계상 볼 수 없음 |
|---|---|---|
| 지갑 | 자체 요청·키·응답·연결 | 다른 사용자 활동 |
| 릴레이 | IP, 암호문 크기, 시점, 허용 공개 읽기 경로·쿼리 | OHTTP 평문, 페이마스터 개인 키 |
| 페이마스터 | 복호화 요청, 결과, 시점, 릴레이 IP | 릴레이·인입이 IP 전달을 제거한 경우 클라이언트 IP |
| 체인 관찰자 | 결과 거래의 공개 데이터·시점 | 전송 중 OHTTP 평문 |
보안 보장
- 릴레이에서 내용 기밀성. HPKE로 비공개 요청·응답을 암호화하며 릴레이에 복호화·서명 키가 없습니다.
- 페이마스터에서 신원 분리. IP 헤더가 전달되지 않으면 지갑 대신 릴레이 연결을 받습니다.
- 키 대체 저항성. 릴레이 경로 밖에서 고정한 Ed25519 키로 회전 HPKE 구성을 검증합니다. 검색은 고정 신뢰 기준의 대체가 아닙니다.
- 암호문 무결성. 변조된 암호문은 인증 검증에 실패합니다. 릴레이는 여전히 폐기·지연·재전송할 수 있어 앱은 재시도에도 안전해야 합니다.
- 제한된 전달. 고정 대상, 명시적 공개 경로, Go의 1 MiB 한도, 엄격한 미디어 유형을 사용하며 범용 프록시가 아닙니다.
- 브라우저 자격 증명 없음. 와일드카드 CORS를 사용하고 쿠키·인증 헤더·브라우저 자격 증명을 사용하지 않습니다.
한계와 가정
신뢰를 분리하는 도구이며 완전한 익명 네트워크는 아닙니다.
- 두 서비스는 독립적이고 공모하지 않는 주체가 운영해야 합니다. 관찰 결과를 합치면 IP와 요청을 연결할 수 있습니다.
- 전역 관찰자는 크기와 시점을 연관 지을 수 있습니다. 믹스넷 수준 트래픽 분석 저항성은 없습니다.
- 릴레이는 IP와 메타데이터를 기록할 수 있습니다. 위협 모델에 맞는 독립성·데이터 정책을 선택하세요.
- 직접 호출하면 주소가 드러납니다. 구성, 견적, 실행, 상태 모두 릴레이를 거쳐야 합니다.
- 공개 체인 메타데이터, 시점, 주소 재사용, 거래가 밝히는 값은 숨기지 않습니다.
- 가용성은 보장되지 않습니다. 차단·지연·속도 제한·선택적 거절이 가능합니다.
공개 릴레이 사용
Anon은 브라우저 호환 https://relay.anon.inc를 제공합니다. URL과 서명 키는 https://anon.inc/.well-known/anon-paymaster.json에 있습니다.
다른 공개 릴레이의 조건:
- 사용할 페이마스터를 대상으로 함;
- 같은
/ohttp-configs,/gateway, 가스 견적·지원 토큰 경로 구현; - 클라이언트 출처 허용 또는 호환 CORS 제공;
- 페이마스터와 독립 운영;
- 허용 가능한 가용성·로그·보존 정책.
클라이언트가 임의의 대상으로 돌릴 수 없습니다. 고정 대상은 공개 프록시 악용을 막는 의도적 설계이며, 운영자가 대상별 호환 인스턴스를 배포해야 합니다.
자체 릴레이 운영
전체 Go, Docker, Cloudflare Worker 구현은 github.com/anondotinc/paymaster-relay에 공개되어 있습니다. 테스트, 배포 구성, 상태 검사, 브라우저 사전 요청 검증을 포함합니다.
Go와 Docker
Go 서비스는 새 상위 요청을 구성하고 클라이언트 헤더를 전달하지 않아 가장 강한 IP 분리를 제공합니다. 컨테이너, VM, Kubernetes에서 실행할 수 있습니다.
git clone https://github.com/anondotinc/paymaster-relay.git
cd paymaster-relay
docker build -t anon-ohttp-relay .
docker run --rm -p 8080:8080 \
-e OHTTP_GATEWAY_URL="https://paymaster.example.com" \
anon-ohttp-relay
컨테이너 앞에서 TLS를 종료하고 릴레이 경로만 노출하세요. 적절한 본문·속도 제한을 적용하고 본문 로깅을 피하세요.
Cloudflare Worker
소유한 영역·도메인이 있는 Cloudflare 계정에 배포할 수 있습니다. 저장소를 포크하고 worker/wrangler.toml을 수정합니다.
- 고유 Worker
name선택; - 도메인
routes[].pattern교체; TARGET을 대상 HTTPS OHTTP 게이트웨이로 설정.
저장소 루트에서 배포·검증합니다.
make cloudflare-login
make deploy RELAY_URL=https://relay.example.com
Cloudflare가 배포 중 DNS와 인증서를 관리합니다.
Cloudflare IP 주의: 비 Cloudflare 원본으로 보내는 Worker 하위 요청에서
CF-Connecting-IP는 클라이언트 주소를 포함하며 Worker가 바꿀 수 없다고 명시되어 있습니다. 페이마스터 인입에서 로깅·처리 전에 방문자 IP 헤더를 제거해야 합니다. 보장할 수 없다면 Go 릴레이를 사용하세요. HTTP 헤더 참고.
운영자 점검 목록
- 페이마스터 조직과 독립 운영합니다.
- 의도한 HTTPS 게이트웨이만 대상으로 합니다.
- 쿠키, 인증값, 사용자 에이전트, IP 헤더를 전달하지 않습니다.
- 본문 로그를 끄고 메타데이터 보존을 최소화합니다.
- 정확한 OHTTP 미디어 유형을 유지합니다.
- 공개 읽기 목록을 좁게 유지하고 상위 캐시 수명을 따릅니다.
- 안정적 사용자 식별자를 만들지 않는 속도 제한을 적용합니다.
/health를 감시하고 배포 후/gateway브라우저 사전 요청을 확인합니다.- URL, 운영자, 로그 정책, 지원 대상을 공개합니다.