테마
Security — Threat model + defense layers
위협 모델
| # | 위협 | 영향 | 방어 |
|---|---|---|---|
| T-1 | MFA bombing (approval fatigue) | 사용자 무심코 [승인] 탭 | 6자리 number_match + 10분 cool-down + in-flight 흡수 + Rack::Attack throttle |
| T-2 | 에이전트 토큰 탈취 | 임의 승인 요청 발사 | signed 모드 = Ed25519 키 분리 (토큰만으론 무효), 즉시 revoke 가능, IP 화이트리스트 옵션 |
| T-3 | 푸시 미도달 (Focus 모드) | TTL 초과 → 작업 차단 | iOS time-sensitive notification + FCM HIGH priority + 사용자 정의 TTL 30s-30min |
| T-4 | 책임 전가 (사용자 부인) | 분쟁 시 "내가 누른 게 아니다" | WebAuthn assertion + display_payload_hash 봉인 + binding_message + 디바이스 ID + IP 기록 |
| T-5 | 감사 로그 유출 | 고가치 거래 데이터 노출 | Application-layer encryption (encrypts :context_ciphertext), hash chain + DB WORM trigger, retention 정책 분리 |
| T-6 | 에이전트가 logi 우회 | 룰 무시하고 직접 실행 | logi 가 막을 수 없음 — 사후 감사 대조 cookbook 제공 |
| T-7 | 에이전트 ID 도용 | 다른 에이전트 척 행세 | 등록 시 비대칭키 발급, 요청 서명에 사용, 사용자 인박스에 "검증됨" 뱃지 |
| T-8 | Replay 공격 | 캡처된 서명을 재전송 | timestamp ±5분 + nonce 1회용 (5분 윈도우) + idempotency_key 1회용 |
| T-9 | display tampering | 에이전트 표시 ≠ 서버 기록 | display_payload_hash 가 사용자가 본 모든 필드 SHA-256 봉인. 결정 시 검증 |
| T-10 | auth_mode 다운그레이드 | signed 에이전트를 bearer_only 로 강등 시도 | auth_mode 는 DB row 에서만 로드. 요청 파라미터 무시 |
| T-11 | Host bypass | 공격자 호스트에서 mobile API 호출 | 모바일 endpoint 는 api.1pass.dev exact-match host constraint (end_user_host_constraint) |
| T-12 | Hash chain race | 동시 write 로 체인 분기 | chronological.lock.last + transaction (Authentication::AuditLogger 패턴 차용) |
방어 layer 상세
6자리 Number Matching
사용자 폰 화면과 에이전트 측 화면에 동일한 6자리가 표시됩니다. 일치 확인 후 Face ID. 100만 분의 1 추측 확률.
SecureRandom.random_number(1_000_000) 균등 분포. modulo 편향 없음.
2자리 (1%) 는 안전하지 않습니다 — random_number(100) 균등 분포라도 100번 시도면 당장 통과합니다.
Ed25519 서명 (signed mode)
매 요청의 canonical 문자열에 method/path/timestamp/nonce/body-digest/agent-id 가 모두 들어갑니다. 어느 하나라도 변조되면 서명이 깨집니다.
키는 등록 시 한 번만 표시되고, 서버는 public key 만 보관 — 키 유출 시 사용자가 콘솔에서 rotate_credentials! 를 누르면 in-flight 요청 포함 전부 무효화됩니다.
in-flight suppression
같은 (user, agent, action_type) 으로 pending/delivered 가 이미 있으면 새 요청은 기존 row 를 그대로 반환. 새 push 안 보냅니다. 1초에 100번 POST 해도 사용자 폰엔 알림 1건만.
Cool-down
거절 결정 후 10분간 동일 action_type 새 요청 → 429 차단. 무한 재시도 차단.
WORM (Write-Once-Read-Many)
agent_action_audit_logs 는:
- Rails
readonly?true —update!/destroy!시도 시ActiveRecord::ReadOnlyRecord - PostgreSQL trigger — raw SQL
UPDATE/DELETE도 차단 (logi.allow_agent_audit_purge세션 플래그로만 우회) - Hash chain — 한 row 만 위조해도 그 이후 체인이 깨짐
사용자 통제
logi 모바일 앱의 "에이전트" 탭에서 사용자는:
- 등록된 에이전트 목록 / 마지막 사용 시각 확인
- 개별 에이전트 즉시 revoke
- 의심스러운 활동을 logi 보안팀에 신고
bearer_only 모드 사용 시 주의
| 항목 | 권고 |
|---|---|
| 환경 | demo / dev / 로컬 테스트만 |
| 토큰 만료 | default 30일, 짧을수록 좋음 |
| IP 화이트리스트 | 필수. 단일 IP / 좁은 CIDR |
| Production | 환경변수 AGENT_BEARER_ONLY_ALLOWED=false 로 차단 가능 |
| 감사 | 모든 요청에 auth_mode 가 기록되므로 사후 분리 가능 |
bearer_only 토큰 1개 유출 = 즉시 임의 승인 요청 100% 가능. signed 모드를 default 로 받으세요.
보안 이슈 신고
security@1pass.dev 로 PGP 또는 평문 모두 환영. 24시간 내 회신.
bounty 프로그램은 준비 중입니다. 별도 페이지로 추후 공지 예정.