Files
MyDoc/Baron Safe 기반 휴대폰 승인 로그인 제안안22.md

29 KiB

# Baron Safe 기반 휴대폰 승인 로그인 제안안

작성일: 2026-06-23

## 1. 목적

본 문서는 Baron SSO에서 논의 중인 "휴대전화번호 기반 간편 로그인"을 표준 기술에 가깝게 보완하기 위한 방안으로, 가칭 `baron-safe` 모바일 앱을 이용한 승인 기반 로그인 구조를 제안한다.

기존의 "휴대전화번호만 입력하면 즉시 로그인" 방식은 전화번호를 사용자 식별자(identifier)로만 사용하고, 사용자가 실제 번호 소유자이거나 현재 로그인 요청을 승인했다는 인증 근거가 부족하다. 반면 `baron-safe` 앱을 사전에 등록된 인증 장치(Authentication Device)로 사용하면, 사용자는 요청 RP와 요청 기기 정보를 확인한 뒤 직접 승인할 수 있고, Baron SSO는 승인 결과를 근거로 OIDC 로그인을 진행할 수 있다.

본 제안의 목표는 다음과 같다.

- 휴대전화번호 기반 UX의 간편함은 유지한다.
- 전화번호 단독 인증의 보안 취약점을 제거한다.
- OIDC/OAuth2 표준 모델과 최대한 정합성 있는 구조로 설계한다.
- RP별 보안 수준과 감사 추적성을 유지한다.
- 향후 WebAuthn, FIDO2, CIBA 등 표준 확장으로 발전 가능한 아키텍처를 확보한다.

## 2. 제안 배경

Baron SSO 통합로그인을 사용하는 대상은 일반 소비자 서비스처럼 불특정 다수의 익명 사용자가 아니다. 주된 사용자는 Baron 내부 구성원, 협력사 또는 고객사 구성원, 그리고 Baron SSO와 연동된 우리 회사 RP를 인지하고 사용하려는 등록 사용자로 한정된다.

따라서 로그인 편의성을 위해 보안을 낮추는 방향보다, 등록 사용자에게 한 번의 앱 설치와 기기 등록 절차를 요구하더라도 이후 모든 RP 로그인에서 더 명확한 본인 확인과 승인 추적성을 확보하는 방향이 조직 보안과 운영 책임 측면에서 더 타당하다.

`baron-safe` 앱 설치는 사용자에게 초기 번거로움을 줄 수 있다. 그러나 Baron SSO가 보호하는 대상은 내부 업무 시스템, 고객/협력사 연동 RP, 조직 데이터 접근 권한이므로, 해당 번거로움은 보안상 합리적인 비용으로 볼 수 있다. 특히 앱 기반 승인은 사용자가 "어떤 RP가, 어떤 기기에서, 언제 로그인을 요청했는지" 확인한 뒤 승인하도록 만들기 때문에, 단순 휴대전화번호 입력 방식보다 오인 로그인, 전화번호 도용, 내부 계정 오남용 위험을 줄일 수 있다.

즉, `baron-safe`는 범용 소비자 서비스의 추가 장벽이라기보다 Baron SSO 생태계에 참여하는 등록 사용자에게 제공되는 전용 안전 확인 채널로 정의하는 것이 적절하다.

## 3. 핵심 결론

`baron-safe` 앱 승인 방식은 기존 "폰번호만으로 즉시 로그인"보다 훨씬 안전하고, 표준 기술적으로도 설명 가능한 구조다.

Baron SSO의 사용자 범위가 등록된 내부/외부 사용자로 제한된다는 점을 고려하면, 앱 설치 및 기기 등록 절차는 과도한 진입 장벽이라기보다 SSO 연동 RP 전체에 공통 적용할 수 있는 보안 기반 장치로 볼 수 있다. 특히 전화번호 단독 로그인에서 부족했던 "현재 사용자가 실제로 이 요청을 승인했다"는 근거를 앱 승인과 기기 서명으로 확보할 수 있다.

이 방식은 OpenID Connect CIBA(Client-Initiated Backchannel Authentication) 모델과 가장 유사하다. CIBA는 RP가 사용자의 식별자를 기반으로 인증 요청을 시작하고, 사용자는 RP 요청 기기가 아닌 별도의 인증 장치에서 인증 및 동의를 수행하는 흐름이다.

Baron SSO에 적용하면 다음처럼 대응된다.

| CIBA 용어 | Baron SSO 대응 |
| --- | --- |
| OpenID Provider(OP) | Baron SSO + Hydra/Kratos/Backend |
| Relying Party(RP) | Baron SSO를 사용하는 업무 시스템 |
| Consumption Device(CD) | 사용자가 로그인을 시도한 브라우저/PC/키오스크 |
| Authentication Device(AD) | `baron-safe`가 설치된 사용자 휴대폰 |
| Backchannel Authentication Request | RP 또는 Baron SSO가 생성하는 로그인 승인 요청 |
| auth_req_id | Baron SSO 내부 로그인 승인 요청 ID |
| Poll/Ping/Push mode | 요청 기기가 승인 결과를 기다리는 방식 |

참고 표준:

- OpenID Connect Client-Initiated Backchannel Authentication Flow - Core 1.0  
  https://openid.net/specs/openid-client-initiated-backchannel-authentication-core-1_0.html
- OAuth 2.0 Device Authorization Grant, RFC 8628  
  https://www.rfc-editor.org/rfc/rfc8628
- OAuth 2.0 Pushed Authorization Requests, RFC 9126  
  https://www.rfc-editor.org/rfc/rfc9126

## 4. 기존 폰번호 단독 로그인과의 차이

| 항목 | 폰번호 단독 즉시 로그인 | Baron Safe 승인 로그인 |
| --- | --- | --- |
| 사용자 입력 | 전화번호 | 전화번호 |
| 사용자 인증 근거 | 없음 또는 약함 | 등록된 앱/기기의 승인 |
| 요청 정보 확인 | 없음 | RP, IP, 기기, 시간 표시 |
| 사용자 행위 | 번호 입력만 | 앱에서 명시적 승인 |
| 세션 발급 근거 | 전화번호 식별 결과 | 승인 요청에 대한 서명된 응답 |
| 표준성 | 비표준 인증 우회에 가까움 | CIBA 스타일 Out-of-Band 인증 |
| 감사 가능성 | 낮음 | 요청/승인/거절/기기 정보 추적 가능 |
| 권장 여부 | 비권장 | 조건부 권장 |

핵심 차이는 전화번호가 인증 수단이 아니라 식별자로만 사용된다는 점을 명확히 분리하는 것이다. 실제 인증은 `baron-safe`에 등록된 인증 장치와 사용자 승인 행위가 담당한다.

## 5. 전체 아키텍처

```mermaid
sequenceDiagram
    autonumber
    actor User as 사용자
    participant CD as 요청 기기(브라우저/RP/키오스크)
    participant RP as 요청 RP
    participant SSO as Baron SSO Backend
    participant HY as Ory Hydra
    participant KR as Ory Kratos
    participant PUSH as FCM/APNs
    participant APP as Baron Safe 앱

    User->>CD: 휴대전화번호 입력
    CD->>RP: 로그인 시작
    RP->>HY: OIDC Authorization Request
    HY->>SSO: login_challenge 전달
    SSO->>SSO: 전화번호 정규화 및 등록 기기 조회
    SSO->>SSO: 승인 요청 생성(auth_req_id, nonce, expires_at)
    SSO->>PUSH: 승인 알림 전송
    PUSH->>APP: Push Notification
    APP->>User: RP/기기/IP/시간 표시
    User->>APP: 앱 잠금해제/생체인증 후 승인
    APP->>SSO: 서명된 승인 응답 제출
    SSO->>SSO: 기기 공개키/nonce/만료/상태 검증
    SSO->>KR: 세션 확인 또는 세션 수립
    SSO->>HY: AcceptLoginRequest(subject)
    HY->>RP: redirectTo / authorization code
    RP->>HY: token 교환
    HY->>RP: ID Token / Access Token / Refresh Token
```

## 6. 프로세스별 상세 설계

### 6.1 사전 등록 프로세스

`baron-safe` 앱은 단순 알림 앱이 아니라 사용자 계정에 바인딩된 인증 장치로 등록되어야 한다.

프로세스:

1. 사용자가 Baron SSO에 기존 표준 방식으로 로그인한다.
2. 사용자 설정 또는 관리자 초대 화면에서 `baron-safe` 기기 등록을 시작한다.
3. 앱이 기기 내 안전 저장소에서 key pair를 생성한다.
4. 앱이 public key, device id, push token, platform 정보를 Baron SSO에 등록한다.
5. Baron SSO는 해당 기기를 사용자 계정에 연결한다.
6. 등록 완료 후 해당 기기에서 승인 요청을 받을 수 있다.

생성되는 데이터:

| 데이터 | 생성 주체 | 저장 위치 | 설명 |
| --- | --- | --- | --- |
| device_id | Baron Safe 또는 Backend | Backend DB | 기기 식별자 |
| public_key | Baron Safe | Backend DB | 승인 응답 서명 검증용 |
| private_key | Baron Safe | 기기 보안 저장소 | 서버로 전송 금지 |
| push_token | OS/FCM/APNs | Backend DB | 알림 발송용 |
| user_id | Kratos/Baron SSO | Backend DB | 사용자-기기 연결 |
| device_name | Baron Safe | Backend DB | 사용자 표시용 |
| registered_at | Backend | Backend DB | 등록 시각 |
| last_used_at | Backend | Backend DB | 마지막 승인 시각 |

표준 기술:

- JWK/JWS: 기기 public key 등록 및 승인 응답 서명 검증
- TLS: 앱-서버 통신 보호
- OS Secure Enclave/Keystore/Keychain: private key 보호
- 선택 적용: WebAuthn/FIDO2/passkey 기반 기기 등록

주의 사항:

- push token은 인증 수단이 아니다. 알림 전달 주소일 뿐이다.
- 실제 인증 근거는 기기 private key로 서명한 승인 응답과 사용자 확인 행위다.
- 기기 분실/교체/폐기 절차가 반드시 필요하다.

### 6.2 로그인 요청 생성 프로세스

프로세스:

1. 사용자가 RP 또는 Baron SSO 로그인 화면에서 휴대전화번호를 입력한다.
2. Baron SSO가 전화번호를 정규화한다.
3. 해당 번호의 사용자와 등록된 `baron-safe` 기기를 조회한다.
4. OIDC `login_challenge`와 RP client 정보를 조회한다.
5. Baron SSO가 승인 요청을 생성한다.
6. 승인 요청은 Redis 또는 DB에 TTL과 함께 저장된다.

생성되는 데이터:

| 데이터 | 예시 | 설명 |
| --- | --- | --- |
| auth_req_id | `ars_...` | 승인 요청 고유 ID |
| login_challenge | Hydra 값 | OIDC 로그인 요청 연결 |
| client_id | `hanmac-erp` | 요청 RP 식별자 |
| client_name | `한맥 ERP` | 앱 화면 표시용 |
| requested_subject | Kratos identity id | 승인 대상 사용자 |
| phone_hash | SHA-256 등 | 전화번호 원문 노출 최소화 |
| nonce | 난수 | 재전송 공격 방지 |
| request_ip | `203.0.113.xxx` | 요청 기기 정보 |
| user_agent | Chrome on Windows | 요청 기기 정보 |
| expires_at | 요청 만료 시각 | 예: 2분 |
| status | `pending` | pending/approved/rejected/expired |

표준 기술:

- OIDC Authorization Request
- Hydra login challenge
- CIBA의 `auth_req_id` 모델과 유사한 승인 요청 ID
- OAuth/OIDC client metadata

주의 사항:

- 전화번호 미등록/기기 미등록 여부가 외부에 드러나면 사용자 열람 공격이 가능하다.
- 응답 메시지는 "승인 요청을 확인해 주세요"처럼 일반화하는 것이 안전하다.
- 요청 TTL은 짧게 설정한다. 예: 60~180초.

### 6.3 앱 알림 및 요청 표시 프로세스

프로세스:

1. Baron SSO가 등록된 기기의 push token으로 알림을 보낸다.
2. 알림에는 민감정보를 최소화하고, 상세 정보는 앱이 서버에서 조회한다.
3. 앱은 `auth_req_id`로 승인 요청 상세를 조회한다.
4. 앱은 사용자에게 RP 정보와 요청 기기 정보를 표시한다.

앱 표시 정보:

| 항목 | 예시 |
| --- | --- |
| 요청 서비스 | 한맥 ERP |
| 요청 시간 | 2026-06-23 15:30 |
| 요청 기기 | Chrome on Windows |
| 요청 위치/IP | 203.0.113.xxx |
| 요청 방식 | Baron Safe 승인 로그인 |
| 만료 시간 | 2분 후 만료 |

표준 기술:

- FCM/APNs: 모바일 푸시 알림 전달
- TLS API: 요청 상세 조회
- OAuth2 Bearer 또는 기기 서명 기반 앱 인증

주의 사항:

- 푸시 메시지 자체에 전화번호, 사용자 이름, RP 민감정보를 과도하게 넣지 않는다.
- 앱 상세 조회 API는 등록된 기기만 접근할 수 있어야 한다.
- 승인 화면에는 "본인이 방금 요청한 로그인이 맞습니까?"를 명확히 표시한다.

### 6.4 사용자 승인 프로세스

프로세스:

1. 사용자가 `baron-safe` 앱을 연다.
2. 앱이 OS 생체 인증, 앱 PIN, 또는 패스키로 사용자 확인을 수행한다.
3. 사용자가 요청 정보를 확인한다.
4. 사용자가 `승인` 또는 `거절`을 선택한다.
5. 앱은 승인 응답 payload를 생성한다.
6. 앱은 payload에 기기 private key로 서명한다.
7. 앱이 Baron SSO에 승인 응답을 제출한다.

승인 응답 예시:

```json
{
  "authReqId": "ars_01J...",
  "deviceId": "dev_01J...",
  "decision": "approve",
  "nonce": "n_01J...",
  "userPresence": true,
  "userVerification": "biometric",
  "approvedAt": "2026-06-23T15:31:02+09:00",
  "signature": "base64url(jws-signature)"
}
```

생성되는 데이터:

| 데이터 | 생성 주체 | 설명 |
| --- | --- | --- |
| decision | Baron Safe | approve/reject |
| user_presence | Baron Safe | 사용자가 앱을 조작했는지 |
| user_verification | Baron Safe | biometric/pin/passkey |
| signature | Baron Safe | 승인 응답 위변조 방지 |
| approved_at | Baron Safe/Backend | 승인 시각 |

표준 기술:

- JWS 또는 COSE 서명
- OS 생체 인증 API
- 선택 적용: FIDO2/WebAuthn user verification

주의 사항:

- "승인"은 반드시 사용자 확인 이후에만 가능해야 한다.
- 앱 백그라운드에서 자동 승인하면 안 된다.
- 동일 요청에 대한 중복 승인/재전송은 거부해야 한다.

### 6.5 서버 검증 및 로그인 완료 프로세스

프로세스:

1. Baron SSO가 `auth_req_id`의 상태를 조회한다.
2. 요청이 pending인지 확인한다.
3. 만료 여부를 확인한다.
4. 제출된 `device_id`가 해당 사용자에게 등록된 기기인지 확인한다.
5. 저장된 public key로 signature를 검증한다.
6. nonce가 일치하고 재사용되지 않았는지 확인한다.
7. 승인 결과가 approve이면 인증 완료 상태로 전환한다.
8. Kratos subject를 확정한다.
9. Hydra `AcceptLoginRequest`를 호출한다.
10. RP로 redirect 또는 token 교환 흐름을 진행한다.

서버 상태 전이:

| 이전 상태 | 이벤트 | 다음 상태 |
| --- | --- | --- |
| pending | 앱 승인 성공 | approved |
| pending | 앱 거절 | rejected |
| pending | TTL 만료 | expired |
| approved | Hydra accept 성공 | completed |
| any | 재사용/위조 시도 | blocked 또는 failed |

표준 기술:

- OIDC login challenge accept
- OAuth2 Authorization Code + PKCE
- JWS signature verification
- OIDC `amr`, `acr` claim 확장

권장 claim:

| claim | 예시 | 설명 |
| --- | --- | --- |
| amr | `["app_push", "device_key", "biometric"]` | 인증 수단 |
| acr | `baron:safe:aal2` | Baron 내부 인증 강도 |
| auth_time | Unix timestamp | 사용자 승인 시각 |
| sid | session id | 세션 관리 |

주의 사항:

- `amr`/`acr`을 통해 일반 비밀번호 로그인, SMS OTP, Baron Safe 승인을 구분해야 한다.
- 민감 RP는 특정 `acr` 이상만 허용하도록 정책화할 수 있다.
- 승인 완료 후에도 기존 OIDC/OAuth2 토큰 발급은 Hydra 표준 흐름을 유지하는 것이 좋다.

## 7. API 초안

### 7.1 승인 요청 생성

내부 또는 RP backchannel API:

```text
POST /api/v1/auth/baron-safe/login/init
```

요청:

```json
{
  "phoneNumber": "010-1234-5678",
  "login_challenge": "hydra-login-challenge",
  "client_id": "hanmac-erp"
}
```

응답:

```json
{
  "authReqId": "ars_01J...",
  "status": "pending",
  "expiresIn": 120,
  "interval": 2
}
```

### 7.2 요청 기기 Poll

```text
POST /api/v1/auth/baron-safe/login/poll
```

요청:

```json
{
  "authReqId": "ars_01J..."
}
```

응답 예시:

```json
{
  "status": "authorization_pending",
  "interval": 2
}
```

승인 완료 시:

```json
{
  "status": "ok",
  "redirectTo": "https://sso.example.com/oauth2/auth?..."
}
```

### 7.3 앱 요청 상세 조회

```text
GET /api/v1/auth/baron-safe/requests/{authReqId}
```

응답:

```json
{
  "authReqId": "ars_01J...",
  "clientName": "한맥 ERP",
  "clientId": "hanmac-erp",
  "requestDevice": "Chrome on Windows",
  "requestIpAddress": "203.0.113.xxx",
  "requestedAt": "2026-06-23T15:30:00+09:00",
  "expiresAt": "2026-06-23T15:32:00+09:00",
  "nonce": "n_01J..."
}
```

### 7.4 앱 승인/거절 제출

```text
POST /api/v1/auth/baron-safe/requests/{authReqId}/decision
```

요청:

```json
{
  "deviceId": "dev_01J...",
  "decision": "approve",
  "nonce": "n_01J...",
  "userPresence": true,
  "userVerification": "biometric",
  "approvedAt": "2026-06-23T15:31:02+09:00",
  "signature": "base64url-signature"
}
```

응답:

```json
{
  "status": "approved"
}
```

## 8. 보안 요구사항

### 8.1 필수 요구사항

- `baron-safe` 기기는 사전에 사용자 계정에 등록되어야 한다.
- 기기별 private key는 서버에 저장하지 않는다.
- 승인 응답은 기기 private key로 서명해야 한다.
- 승인 요청은 짧은 TTL을 가져야 한다.
- nonce는 요청별 1회용이어야 한다.
- 동일 요청의 중복 승인, 만료 후 승인, 다른 기기의 승인은 거부한다.
- 앱 승인 전 사용자 확인을 수행한다.
- 모든 통신은 TLS를 사용한다.
- 승인/거절/만료/실패를 감사 로그로 남긴다.

### 8.2 권장 요구사항

- 기기 등록 시 기존 표준 로그인 또는 관리자 초대를 요구한다.
- 기기 변경/해제 시 사용자와 관리자에게 알림을 보낸다.
- 고위험 RP는 WebAuthn 또는 추가 PIN을 요구한다.
- 푸시 피로 공격 방지를 위해 단기간 반복 요청을 제한한다.
- 승인 화면에 number matching 또는 request code를 추가한다.
- 위치/IP가 평소와 다르면 경고를 표시한다.
- `baron-safe` 인증으로 생성된 세션은 일반 세션과 구분 표시한다.

## 9. 표준 기술 적용 가능성

| 영역 | 적용 가능한 표준/기술 | 적용 방식 |
| --- | --- | --- |
| Out-of-Band 인증 | OpenID Connect CIBA | 앱 승인 기반 비동기 인증 모델 |
| RP 최종 로그인 | OIDC Authorization Code + PKCE | 기존 Hydra 흐름 유지 |
| RP backchannel 인증 | `private_key_jwt`, mTLS | RP가 승인 요청 생성 시 자신을 인증 |
| 승인 응답 서명 | JWS/JWK 또는 COSE | 등록 기기의 private key로 승인 payload 서명 |
| 기기 내 사용자 확인 | WebAuthn/FIDO2/passkey, OS biometric | 앱 승인 전 사용자 검증 |
| 제한 장치 대안 | OAuth2 Device Authorization Grant | TV/CLI/키오스크형 입력 제한 장치에 응용 가능 |
| 요청 보안 강화 | Pushed Authorization Requests(PAR) | RP 인증 요청 변조/노출 축소 |
| 세션 관리 | OIDC Back-Channel Logout | RP 로그아웃 전파 |
| 토큰 취소 | OAuth2 Token Revocation | refresh token 무효화 |

## 10. 앱 기술 스택 제안

`baron-safe`는 Android와 iOS를 모두 지원해야 하므로, 초기 개발에서는 단일 코드베이스로 양 플랫폼을 동시에 지원하는 크로스플랫폼 프레임워크를 우선 검토하는 것이 현실적이다.

### 10.1 권장안: Flutter 기반 크로스플랫폼 앱

권장 기술 스택:

| 영역 | 권장 기술 | 적용 이유 |
| --- | --- | --- |
| App Framework | Flutter | Android/iOS 단일 코드베이스, 기존 `userfront`와 기술 친화성 |
| Language | Dart | Flutter 기본 언어 |
| Push Notification | Firebase Cloud Messaging + APNs 연동 | Android/iOS 공통 푸시 발송 관리 |
| Secure Storage | Android Keystore, iOS Keychain/Secure Enclave 연동 | 기기 private key 및 민감 토큰 보호 |
| Local Authentication | `local_auth` 계열 생체 인증 연동 | 승인 전 지문/Face ID/기기 PIN 확인 |
| Crypto Signing | JWS/JWK 또는 COSE 서명 라이브러리 | 승인 응답 서명 및 위변조 방지 |
| API 통신 | HTTPS + certificate pinning 검토 | 앱-서버 통신 보호 |
| 상태 관리 | Riverpod 또는 Bloc | 승인 요청/기기 등록/세션 상태 관리 |
| 배포 | Google Play Enterprise, Apple Business Manager/TestFlight | 내부/협력사 대상 앱 배포 관리 |

Flutter를 권장하는 이유:

- Android/iOS 공통 UI와 비즈니스 로직을 하나의 코드베이스로 관리할 수 있다.
- 로그인 승인 앱은 고성능 네이티브 UI보다 안정적인 API 통신, 푸시, 보안 저장소, 생체 인증 연동이 핵심이므로 Flutter와 잘 맞는다.
- Baron SSO의 `userfront`가 이미 Flutter 기반이므로 조직 내 학습 비용과 코드 패턴 재사용 측면에서 유리하다.
- 필요 시 플랫폼별 보안 기능은 Method Channel 또는 플러그인으로 네이티브 연동할 수 있다.

### 10.2 대안: React Native

React Native도 Android/iOS 공통 개발이 가능하다.

장점:

- JavaScript/TypeScript 기반으로 웹 프론트엔드 인력과 협업이 쉽다.
- 푸시, 생체 인증, secure storage 생태계가 충분하다.

단점:

- 현재 Baron SSO의 사용자 프론트가 Flutter 기반이므로 기술 스택이 하나 더 늘어난다.
- 보안 저장소와 네이티브 crypto 연동 시 라이브러리 품질 검증이 필요하다.

### 10.3 대안: 네이티브 앱 분리 개발

Android는 Kotlin, iOS는 Swift로 각각 개발하는 방식이다.

장점:

- Android Keystore, iOS Keychain/Secure Enclave, 생체 인증, 푸시 처리 등 플랫폼 보안 기능을 가장 직접적으로 제어할 수 있다.
- 장기적으로 고보안 앱을 만들기에는 가장 안정적인 선택이다.

단점:

- Android/iOS 개발과 테스트를 별도로 운영해야 한다.
- 초기 개발 속도와 유지보수 비용이 증가한다.
- 기능 동등성 관리가 어렵다.

### 10.4 공통 구현 원칙

프레임워크와 관계없이 다음 원칙은 반드시 지켜야 한다.

- Android와 iOS 모두 기기별 key pair를 앱 최초 등록 시 생성한다.
- private key는 서버로 전송하지 않고 Android Keystore 또는 iOS Keychain/Secure Enclave에 보관한다.
- push token은 알림 전달용으로만 사용하고 인증 수단으로 취급하지 않는다.
- 승인 응답은 `auth_req_id`, `nonce`, `decision`, `device_id`, `approved_at` 등을 포함해 서명한다.
- 앱 승인 전 OS 생체 인증 또는 앱 PIN을 요구한다.
- 앱이 탈옥/루팅, 디버그 빌드, 무결성 훼손 상태일 경우 고위험 RP 승인을 제한한다.
- Android는 Play Integrity API, iOS는 App Attest 또는 DeviceCheck 적용을 검토한다.
- 앱과 서버 API는 TLS를 기본으로 하고, 필요 시 certificate pinning을 적용한다.

### 10.5 배포 및 운영 방안

Baron SSO 사용자가 불특정 다수가 아니라 등록된 내부/외부 사용자라는 점을 고려하면, 앱 배포도 일반 공개 앱보다 관리형 배포가 적합하다.

권장 배포 방식:

| 대상 | Android | iOS |
| --- | --- | --- |
| 내부 임직원 | Managed Google Play 또는 사내 MDM | Apple Business Manager 또는 MDM |
| 협력사/고객사 | 제한 공개 테스트/엔터프라이즈 배포 검토 | Apple Business Manager Custom App 또는 TestFlight |
| 초기 파일럿 | Firebase App Distribution | TestFlight |

운영 고려사항:

- 기기 등록/해제 기능을 관리자 화면과 사용자 마이페이지에 제공한다.
- 분실 기기 즉시 차단 기능이 필요하다.
- 앱 버전 최소 요구사항을 서버에서 강제할 수 있어야 한다.
- 보안 정책 변경 시 구버전 앱의 승인을 제한할 수 있어야 한다.

## 11. 구현 방식 선택지

### 11.1 완전 CIBA 지원 방식

Baron SSO가 CIBA의 backchannel authentication endpoint와 CIBA grant type을 공식 지원한다.

장점:

- 표준 정합성이 가장 높다.
- RP와의 장기적 상호운용성이 좋다.
- Poll/Ping/Push mode를 명확히 정의할 수 있다.

단점:

- Hydra에서 CIBA를 직접 지원하지 않는 경우 구현 범위가 커진다.
- discovery metadata, client registration, token grant 확장이 필요하다.

### 11.2 CIBA 스타일 내부 브로커 방식

Baron Backend가 CIBA와 유사한 승인 브로커 역할을 하고, 최종 로그인 완료는 기존 Hydra `AcceptLoginRequest`로 연결한다.

장점:

- 현재 Baron SSO 구조에 적용하기 쉽다.
- 기존 OIDC Authorization Code + PKCE 흐름을 유지할 수 있다.
- 단계적 도입이 가능하다.

단점:

- 외부 표준 CIBA endpoint로 바로 공개되지는 않는다.
- 내부 API 명세와 보안 검증을 엄격히 관리해야 한다.

권장:

- 초기 도입은 11.2 방식이 현실적이다.
- 이후 RP 요구가 커지면 11.1 방식으로 확장한다.

### 11.3 Device Authorization Grant 응용 방식

키오스크, TV, CLI처럼 입력이 제한된 기기에는 OAuth2 Device Authorization Grant를 응용할 수 있다.

장점:

- 표준 RFC가 명확하다.
- 사용자가 다른 기기에서 승인하는 모델이다.

단점:

- 사용자가 user code를 입력하는 UX가 기본 모델이다.
- 휴대폰 번호 기반 push 승인과는 CIBA보다 덜 직접적이다.

## 12. 도입 단계 제안

### Phase 1: 내부 승인 브로커 MVP

- `baron-safe` 기기 등록 모델 추가
- Android/iOS 공통 앱 MVP 구현
- 승인 요청 생성 API 추가
- 앱 요청 상세 조회 API 추가
- 앱 승인/거절 API 추가
- 요청 기기 poll API 추가
- Hydra `AcceptLoginRequest` 연계
- 감사 로그 추가

### Phase 2: 보안 강화

- 기기별 key pair 및 JWS 서명 검증
- Android Keystore, iOS Keychain/Secure Enclave 연동 강화
- OS 생체 인증 또는 앱 PIN 필수화
- Play Integrity API, App Attest/DeviceCheck 적용 검토
- nonce 재사용 방지
- rate limit 및 push fatigue 방어
- RP별 allowlist와 required ACR 정책
- 관리자 화면에서 기기 등록/해제 관리

### Phase 3: 표준 확장

- CIBA discovery metadata 검토
- backchannel authentication endpoint 공개 여부 검토
- `urn:openid:params:grant-type:ciba` 지원 검토
- Ping/Poll delivery mode 정식화
- PAR/JAR 적용 검토

## 13. 운영 정책 제안

### 13.1 인증 강도 구분

`baron-safe` 승인 로그인은 다음과 같이 별도 인증 강도로 관리한다.

| 인증 방식 | 예시 ACR | 설명 |
| --- | --- | --- |
| 전화번호 단독 | `baron:phone:identifier-only` | 운영 로그인 비권장 |
| SMS OTP | `baron:phone:sms-otp` | 전화번호 소유 확인 |
| Baron Safe 앱 승인 | `baron:safe:app-approval` | 등록 앱 승인 |
| Baron Safe + 생체 인증 | `baron:safe:aal2` | 앱 승인 + 사용자 확인 |
| WebAuthn/passkey | `baron:webauthn:phishing-resistant` | 피싱 저항 인증 |

### 13.2 RP별 접근 정책

- 일반 RP: Baron Safe 앱 승인 허용
- 민감 RP: Baron Safe + 생체 인증 또는 WebAuthn 요구
- 관리자 RP: WebAuthn 또는 추가 MFA 요구
- 외부망 RP: IP/위치 이상 탐지 시 추가 인증 요구

### 13.3 감사 로그 항목

| 항목 | 설명 |
| --- | --- |
| auth_req_id | 승인 요청 ID |
| user_id | 대상 사용자 |
| client_id | 요청 RP |
| device_id | 승인 앱 기기 |
| request_ip | 요청 기기 IP |
| request_user_agent | 요청 기기 User-Agent |
| decision | approve/reject/expired |
| user_verification | biometric/pin/passkey/none |
| signature_valid | 서명 검증 결과 |
| completed_at | 로그인 완료 시각 |

## 14. 주요 위험과 대응

| 위험 | 설명 | 대응 |
| --- | --- | --- |
| 푸시 피로 공격 | 공격자가 반복 승인 요청을 보내 사용자가 실수 승인 | rate limit, number matching, 반복 요청 차단 |
| 휴대폰 분실 | 등록 앱이 설치된 기기 분실 | 원격 기기 해제, 관리자 잠금, 생체 인증 필수 |
| 푸시 토큰 탈취 | 알림 토큰 유출 | push token은 인증 수단으로 사용하지 않음 |
| 앱 위조 | 공격자가 가짜 앱으로 승인 시도 | 기기 private key 서명 검증 |
| 앱 무결성 훼손 | 루팅/탈옥/디버그 환경에서 승인 조작 | Play Integrity, App Attest, 고위험 RP 제한 |
| 요청 변조 | RP 정보 또는 요청 ID 변조 | 서버 저장 요청 기준 검증, nonce, signature |
| 사용자 열람 | 전화번호 입력으로 가입 여부 추론 | 응답 메시지 일반화, rate limit |
| RP 오남용 | 허용되지 않은 RP가 승인 요청 생성 | client authentication, allowlist |

## 15. 팀장 보고용 최종 제안

`baron-safe` 앱 승인 방식은 "전화번호만으로 로그인"이 아니라 "전화번호로 사용자를 식별하고, 등록된 모바일 인증 장치에서 사용자가 승인하는 로그인"으로 정의해야 한다.

이렇게 정의하면 다음 장점이 있다.

- Baron SSO 사용자가 등록된 내부/외부 사용자로 제한되므로 앱 설치와 기기 등록을 보안 절차로 수용시키기 쉽다.
- 전화번호 단독 로그인의 비표준/저보증 문제를 해결한다.
- 사용자는 요청 RP와 요청 기기를 확인하고 승인할 수 있다.
- OIDC CIBA와 유사한 표준 모델로 설명 가능하다.
- 기존 Hydra 기반 OIDC Authorization Code + PKCE 흐름을 유지할 수 있다.
- 감사 로그, RP별 정책, 세션 관리와 자연스럽게 연결된다.

권장 구현 방향은 다음과 같다.

1. 1차로 Baron Backend가 CIBA 스타일 내부 승인 브로커 역할을 수행한다.
2. 앱은 Android/iOS 공통 지원을 위해 Flutter 기반으로 우선 검토한다.
3. `baron-safe` 앱은 기기별 key pair를 생성하고 승인 응답을 서명한다.
4. 앱 승인 전 생체 인증 또는 앱 PIN을 요구한다.
5. Baron SSO는 승인 검증 후 기존 Hydra `AcceptLoginRequest`로 OIDC 흐름을 완료한다.
6. 모든 승인 로그인에는 `amr`, `acr`, `device_id`, `auth_req_id`를 기록한다.
7. 향후 표준 CIBA endpoint 지원 여부를 검토한다.

최종적으로 이 방식은 기존 제안보다 보안성과 설명 가능성이 높다. 단, push 알림 자체를 인증 수단으로 오해해서는 안 되며, 반드시 등록 기기의 서명 검증과 사용자 확인 절차가 포함되어야 한다.