오프라인 환경에서는 인증과 인가를 검증 시점에 서버로 물어볼 수 없다. 서버가 미리 서명해 둔 정보를 디바이스에 심어 두고, 디바이스가 그 서명을 현장에서 직접 검증한다.
지하주차장에 세워둔 차량의 문을 휴대폰으로 여는 상황을 생각해 보자. 차량도 휴대폰도 셀룰러 네트워크에 연결되지 않는다. 하지만 둘은 BLE(Bluetooth Low Energy)를 통해 직접 통신할 수 있다. 눈앞의 휴대폰이 등록된 사용자의 것인지, 그리고 그 사용자에게 문을 열 권한이 있는지를 차량 스스로 판정해야 한다.
온라인 서비스에서 인증과 인가는 서버에 물어보면 된다. 토큰이 유효한지는 발급자가 답하고, 어떤 권한이 있는지는 정책 서버가 답한다. 검증에 필요한 답이 서버에 있기 때문이다.
오프라인 환경에는 그 서버가 없다. 그래서 답을 미리 만들어 서명해 두고, 현장에서는 서명만 확인한다.
이 글은 두 가지를 다룬다. 하나는 모바일과 디바이스가 서버 없이 서로를 인증하는 방법이고, 다른 하나는 인가를 어떻게 오프라인으로 옮기는가이다.
왜 오프라인에서 인증과 인가가 어려운가
오프라인 인증이 어려운 것은 암호 기술 때문이 아니다. 눈앞의 상대가 누구인지 물어볼 서버가 없기 때문이다.
온라인 인증 방식은 대부분 인가 서버를 전제로 한다. OAuth 2.0의 Token Introspection 에서는 리소스 서버가 인가 서버에 토큰의 유효성을 질의한다. 검증 시점에 네트워크 왕복이 한 번 이상 필요하고, 서버에 연결할 수 없으면 인증과 인가는 실패한다.
오프라인 환경에서는 이 전제가 무너진다. 차량이 터널이나 지하주차장에 들어가면 LTE나 5G 신호가 약해지거나 완전히 사라진다. 이때 차량은 서버에 요청을 보낼 수도, 응답을 받을 수도 없다.
따라서 검증 시점에 서버에 의존하는 인증·인가 메커니즘은 오프라인 환경에서 사용하기 어렵다.
모바일과 디바이스는 어떻게 인증하는가
모바일과 디바이스의 오프라인 인증 문제는 디지털 서명(Digital Signature) 으로 푼다. 모바일은 자신의 비밀키(Private Key)로 서명하고, 디바이스는 미리 가지고 있던 공개키(Public Key)로 그 서명을 검증한다. 검증에 필요한 것은 공개키뿐이므로 이 과정에는 네트워크가 필요 없다.
이 글에서는 모바일을 휴대폰으로, 디바이스를 차량으로 놓고 설명한다.
오프라인 인증은 두 가지 조건 위에 선다
첫째, 디바이스 밖으로 나가지 않는 비밀키다. 비밀키가 외부로 유출되면 누구나 디바이스를 대신해 인증할 수 있다. 따라서 비밀키는 HSM(Hardware Security Module)이나 TEE(Trusted Execution Environment)처럼 외부에서 직접 접근할 수 없는 영역에 보관해야 한다.
둘째, 미리 등록해 둔 공개키다. 차량은 네트워크에 연결되지 않은 상태에서도 이 공개키를 기준으로 상대방의 서명을 검증해야 한다.
이처럼 검증자가 사전에 신뢰하도록 등록해 둔 키나 인증서를 신뢰 앵커(Trust Anchor) 라고 한다. 공개키 자체가 신뢰 앵커가 될 수도 있다.
그렇다면 차량은 무엇을 신뢰 앵커로 삼아야 할까?
휴대폰과 차량이 한 번도 만난 적이 없다면, 차량은 눈앞의 휴대폰을 어떻게 믿을 수 있을까? 차량과 휴대폰이 공통으로 신뢰하는 상위 기관, 즉 Root CA(루트 인증기관) 가 있어야 한다. Root CA는 휴대폰의 공개키와 신원을 묶어 서명하고, 차량은 미리 가지고 있는 Root CA 공개키로 이 서명을 검증한다.
이때 사용하는 것이 인증서(Certificate)다. 인증서는 “이 공개키가 이 신원에 속한다"는 내용을 Root CA가 서명한 문서다. X.509는 이러한 인증서를 표현하기 위한 표준 형식이다.
실제 오프라인 환경에서는 Root CA의 공개키 또는 Root CA 인증서가 신뢰 앵커로 사용된다.
Root CA 인증서는 자기 자신의 비밀키로 서명한 자기 서명 인증서(Self-Signed Certificate)다. 따라서 이 인증서의 서명만 검증해서는 그것이 신뢰할 수 있는 Root CA에서 나온 것인지 확인할 수 없다. 자신을 검증해 줄 상위 인증서가 없기 때문이다.
그래서 Root CA 인증서는 다른 인증서처럼 검증하는 대상이 아니라, 인증서 검증을 시작하는 기준점으로 사용된다. 검증자는 이 값을 미리 안전하게 저장해 두고, 이후 전달받은 인증서가 이 Root CA를 시작점으로 하는 유효한 인증서 체인을 갖는지 확인한다.
따라서 차량은 모든 휴대폰의 정보를 미리 가지고 있을 필요가 없다. Root CA 공개키 하나만 미리 가지고 있으면, Root CA가 서명한 휴대폰 인증서를 현장에서 검증할 수 있다. 서버에 접속해 휴대폰의 정보를 다시 확인할 필요도 없다.
대칭키와 비대칭키는 여기서 확장성이 갈린다. 대칭키 방식에서는 차량과 휴대폰이 공유할 비밀키를 미리 나눠 가져야 한다. 상대가 많아질수록 관리해야 할 키도 많아진다. 반면 비대칭키 방식에서는 차량이 휴대폰마다 비밀키를 가지고 있을 필요가 없다. 차량은 Root CA 공개키만 가지고 있고, 각 휴대폰은 자신의 비밀키로 서명한다.
신뢰 앵커는 런타임에 만들어지는 정보가 아니다. 차량이 출고되기 전에 제조·프로비저닝 단계에서 안전하게 저장해야 한다. 펌웨어에 포함하거나 HSM, TEE와 같은 보호된 영역에 저장하는 이유가 여기에 있다.
공격자가 차량의 Root CA 공개키를 임의로 바꿀 수 있다면, 공격자는 자신의 키를 새로운 루트로 등록할 수 있다. 그러면 차량은 공격자가 만든 인증서를 정상적인 인증서로 받아들인다. 신뢰 앵커가 뚫리면 그 위에 쌓은 모든 검증이 무의미해진다.
비밀이 아니라 소유를 증명한다
인증에는 두 가지 방식이 있다. 비밀을 제시하는 방식과, 비밀을 사용할 수 있음을 증명하는 방식이다.
비밀번호나 사전 공유키를 그대로 보내는 방식은 전자다. 채널을 도청당하면 그 비밀은 즉시 공격자의 것이 된다.
소유 증명(Proof of Possession)은 후자다. 비밀 자체를 보내는 대신, 검증자가 매번 새로 만들어 보낸 값에 자신의 비밀키로 서명해 돌려준다. 이렇게 비밀키를 가지고 있음을 보이는 방식을 challenge-response라고 한다.
지하주차장에서 차량과 휴대폰이 처음 만났다고 생각해 보자.
먼저 휴대폰이 자신의 인증서를 차량에 보낸다. 인증서에는 휴대폰의 공개키와 이 공개키가 어떤 신원에 속하는지를 나타내는 정보가 들어 있다.
차량은 미리 가지고 있던 Root CA 공개키를 사용해 인증서의 서명을 검증한다. 이를 통해 이 인증서가 차량이 신뢰하는 CA에서 발급된 것인지 확인한다. 검증이 끝나면 차량은 인증서에 들어 있는 휴대폰의 공개키를 얻을 수 있다.
하지만 여기서 인증이 끝난 것은 아니다.
공개키와 인증서는 누구나 복사할 수 있다. 공격자가 다른 사람의 인증서를 복사해 차량에 보내는 것만으로는, 그 인증서가 가리키는 비밀키를 가지고 있다는 증거가 되지 않는다.
그래서 차량은 새로운 난수(nonce)를 만들어 휴대폰에 보낸다. 휴대폰은 자신의 비밀키로 이 난수에 서명하고, 그 서명을 차량에 돌려준다. 차량은 앞에서 인증서에서 얻은 공개키로 이 서명을 검증한다.
검증에 성공하면 차량은 인증서에 들어 있는 공개키에 대응하는 비밀키를 휴대폰이 실제로 가지고 있다는 것을 확인할 수 있다.
이 두 단계는 서로 다른 것을 확인한다.
- 인증서 검증: 이 공개키를 신뢰해도 되는가?
- 소유 증명: 지금 인증서를 제시한 휴대폰이 그 공개키에 대응하는 비밀키를 실제로 가지고 있는가?
둘 중 하나만으로는 충분하지 않다. 인증서만 확인하면 공격자가 다른 사람의 인증서를 복사해서 제시할 수 있다. 반대로 비밀키로 서명했다는 사실만 확인해서는 그 공개키가 누구의 것인지 알 수 없다. 인증서 검증과 소유 증명을 함께 해야, 신뢰할 수 있는 공개키를 가진 주체가 실제로 그에 대응하는 비밀키를 쥐고 있는지 확인할 수 있다.
차량이 매번 새로운 난수를 사용하는 이유도 여기에 있다. 공격자가 이전에 오간 서명을 캡처하더라도 그 서명은 이전 난수에 대한 서명이므로, 다음번에 차량이 보낸 새로운 난수에 대한 응답으로 그대로 사용할 수 없다. 비밀키 자체도 네트워크를 통해 전송되지 않는다.
이런 구조는 차량만의 특별한 기술이 아니다. 공개키를 미리 등록하고, 상대방이 그 공개키에 대응하는 비밀키를 가지고 있는지 서명으로 확인하는 방식은 여러 시스템에서 사용된다.
- FIDO2/WebAuthn: 인증기가 서버가 제공한 challenge를 포함한 인증 데이터를 자신의 비밀키로 서명하고, 서버는 등록해 둔 공개키로 이를 검증한다.
- TLS 클라이언트 인증(mTLS): 클라이언트가 자신의 인증서와 함께 비밀키를 사용한 서명을 보내고, 서버는 인증서의 공개키를 사용해 클라이언트가 해당 비밀키를 가지고 있는지 확인한다.
- SSH 공개키 인증: 서버에 등록된 공개키에 대응하는 비밀키를 클라이언트가 가지고 있음을 서명으로 증명한다.
세 시스템의 세부 프로토콜은 서로 다르지만 핵심 구조는 같다.
공개키는 미리 등록하고, 비밀키는 디바이스 밖으로 내보내지 않으며, 실제 인증 시에는 새로운 데이터를 비밀키로 서명하게 해서 소유를 증명한다.
비대칭 서명은 부인방지를 제공한다
전자서명은 송신자의 비밀키를 가진 쪽만 만들 수 있고, 검증은 누구나 공개키로 할 수 있다. 이 비대칭성이 부인방지(Non-Repudiation)를 만든다. 비밀키는 오직 본인만 가지고 있으므로, 나중에 자신이 서명하지 않았다고 주장할 수 없다.
반면 대칭키에서는 메시지를 검증할 수 있는 주체가 같은 메시지를 만들 수도 있다. 따라서 두 당사자 사이에 분쟁이 생기면, 그 기록만으로는 어느 쪽이 메시지를 만들었는지 제3자에게 증명하기 어렵다.
오프라인에서는 이 차이가 더 크게 벌어진다.
온라인 시스템에서는 사건이 발생했을 때 서버의 기록을 확인할 수 있다. 예를 들어 서버는 “특정 시각에 특정 계정이 특정 차량에 문 열기 명령을 보냈다"와 같이 기록을 남긴다. 이 기록과 서버의 인증·접근 로그를 함께 확인하면 당시 어떤 요청이 있었는지 사후에 추적할 수 있다.
하지만 오프라인 환경에서는 이런 서버 기록이 남지 않는다.
지하주차장에서 휴대폰과 차량이 BLE로 직접 통신하고, 두 장치 모두 서버에 연결되어 있지 않다고 생각해 보자. 이때 인증과 명령 처리가 모두 두 장치 사이에서 끝난다면, 나중에 분쟁이 발생했을 때 당시 어떤 명령이 오갔는지 확인할 기록을 두 장치가 직접 남겨야 한다.
이 기록을 남기는 수단이 비대칭 서명이다.
휴대폰이 문 열기 명령에 서명하고 차량이 그 서명을 보관하면, 나중에 차량은 해당 공개키를 사용해 그 기록을 다시 검증할 수 있다. 다만 서명만으로 “사람이 직접 문 열기 버튼을 눌렀다"는 사실까지 증명되지는 않는다.
서명이 증명하는 범위는 “해당 비밀키를 가진 주체가 이 데이터에 서명했다"까지다. 그 비밀키를 실제 사용자가 직접 사용했는지, 악성 프로그램이 사용했는지, 사용자의 휴대폰을 다른 사람이 조작했는지는 별도의 문제다.
그래서 비밀키를 어떻게 보호하는지가 서명의 신뢰도를 좌우한다. 비밀키를 일반 애플리케이션 메모리에 두는 대신 Secure Element, HSM, TEE와 같은 보호된 영역에서 외부로 꺼낼 수 없도록 관리하면 비밀키가 탈취될 가능성을 낮출 수 있다. 그만큼 그 서명이 실제 사용자의 디바이스에서 만들어졌다는 판단도 더 믿을 수 있게 된다.
비대칭 서명 기반의 오프라인 인증은 세 가지를 함께 얻는다. 서버 없이 하는 검증, Root CA 공개키 하나로 여러 휴대폰의 인증서를 검증하는 확장성, 그리고 부인방지다.
비대칭키 기반 오프라인 인증은 무엇을 설계해야 하는가

이 구조에는 여섯 가지 설계 판단이 들어 있다.
| 설계 | 답해야 하는 질문 |
|---|---|
| 장기 신원키와 세션 키 분리 | 누구인지 증명하는 키와 통신을 보호하는 키를 왜 나누는가? |
| 세션마다 새 임시 키 | 장기 신원키가 나중에 유출되어도 과거 통신을 보호할 수 있는가? |
| 신원과 세션 바인딩 | 지금 만든 세션이 정말 이 상대와 만든 것인가? |
| 장기 신원키 서명 | 나중에 누가 이 명령을 만들었는지 검증할 수 있는가? |
| 재전송(Replay) 방어 | 예전에 유효했던 명령을 다시 실행할 수 없는가? |
| 수신자 바인딩 | 다른 차량에서 이 명령을 재사용할 수 없는가? |
장기 신원키와 세션 키를 분리한다
장기 신원키와 세션 키는 서로 다른 목적으로 쓴다.
장기 신원키는 “나는 누구인가"를 증명하는 데 쓴다. 반면 세션 키는 “이번 통신을 어떻게 보호할 것인가"를 담당한다.
두 역할을 키 하나로 처리하면 그 키가 유출되었을 때 신원 인증과 과거 통신의 보안이 함께 영향을 받는다. 따라서 장기 신원키는 신원 확인과 서명에 쓰고, 실제 데이터를 암호화하는 세션 키는 별도로 만든다.
세션 키는 매 세션마다 새로 만든다
세션 키는 장기간 재사용하지 않고, 매번 새로운 임시 키쌍을 이용해 만든다.
예를 들어 휴대폰과 차량이 각각 이번 통신에서만 쓸 임시 키쌍을 만든다. 두 임시 키로 ECDH(Elliptic Curve Diffie-Hellman) 공유 비밀을 얻고, 여기에 KDF(Key Derivation Function)를 적용해 세션 키를 유도한다. 통신이 끝나면 임시 키를 폐기한다.
이렇게 하면 장기 신원키가 나중에 유출되더라도, 이미 끝난 과거 세션의 트래픽을 복호화하기 어렵다. 이를 순방향 비밀성(Forward Secrecy) 이라고 한다.
TLS 1.3이 임시 키 교환을 기본으로 쓰는 것도 같은 이유다.
인증할 때는 상대방의 신원과 이번 세션을 함께 묶는다
상호 인증에서는 상대방의 서명이 유효한지만 확인하는 것으로는 부족하다. 누구의 서명인지, 그리고 어떤 세션을 위한 서명인지 함께 확인해야 한다.
따라서 서명에는 다음 정보가 함께 들어가야 한다.
- 휴대폰의 신원
- 차량의 신원
- 휴대폰의 이번 세션용 임시 공개키
- 차량의 이번 세션용 임시 공개키
- 이번 인증을 위한 nonce
왜 이것이 필요한지는 공격 상황을 보면 알 수 있다.
공격자가 임시 공개키를 자신의 것으로 바꿔치기할 수 있다고 해보자. 인증서 자체도, CA 서명도 유효하다. 하지만 공격자의 임시 공개키가 실제 상대방의 신원과 묶여 있지 않다면, 공격자는 양쪽과 각각 별도의 세션을 만들 수 있다.
따라서 인증서가 유효한지 확인하는 것만으로는 부족하다. 인증서에 들어 있는 신원과 이번 세션의 임시 공개키가 서로 묶여 있는지 확인해야 한다.
이처럼 하나의 세션이나 메시지가 다른 주체의 신원과 잘못 연결되는 문제를 신원 오결합(Identity Misbinding) 이라고 한다. TLS 1.3의 CertificateVerify도 임시 공개키 하나만 서명하지 않는다. 핸드셰이크 과정에서 교환된 내용을 포함하는 transcript에 서명한다. 이를 통해 인증서와 키 교환 과정이 서로 다른 세션에서 가져온 값으로 뒤섞이는 것을 막는다.
세션 키를 만들었다는 사실만으로는 상대방의 신원을 확인할 수 없다. 상대방의 신원과 이번 세션의 임시 키를 함께 검증해야 한다.
암호화와 서명은 서로 다른 목적을 가진다
세션 키로 메시지를 암호화하면 통신 내용은 보호할 수 있다. 하지만 세션 키를 가진 양쪽 모두 메시지를 만들 수 있다. 암호화된 메시지만으로는 어느 쪽이 그것을 만들었는지 제3자가 판단하기 어렵다.
세션 키에서 만든 MAC(Message Authentication Code)도 마찬가지다. MAC을 검증할 수 있는 쪽은 같은 키를 사용해 새로운 MAC을 만들 수도 있기 때문이다.
따라서 어느 주체가 그 명령을 만들었는지 제3자가 확인할 증거가 필요하다면, 장기 신원키로 메시지에 따로 서명해야 한다.
재전송을 막기 위해 메시지에 신선도를 넣는다
서명이 유효하다고 해서 같은 메시지를 계속 실행해도 되는 것은 아니다.
공격자가 과거에 캡처한 “문 열기” 메시지를 다시 차량에 보내는 상황을 생각해 보자. 서명이 유효하면 차량은 그 명령을 그대로 실행한다.
따라서 명령에는 이번 요청임을 나타내는 정보가 필요하다.
예를 들어 다음과 같은 값을 사용할 수 있다.
nonceseq(sequence number)commandIdexpiresAt(만료 시각)
차량은 이미 처리한 commandId나 seq를 기록해 같은 요청이 다시 실행되지 않도록 해야 한다.
서명은 메시지가 변조되지 않았다는 것과 누가 서명했는지만 확인해 준다. 그 메시지가 지금 처음 온 것인지는 알려주지 않는다.
수신자도 서명 대상에 포함한다
마지막으로 이 명령이 누구를 대상으로 하는지도 서명에 포함해야 한다.
예를 들어 휴대폰이 다음 메시지에 서명했다고 하자.
Sign(SK_P, {
command: "unlock"
})
이 서명에는 “누구의 차량을 열 것인가"가 들어 있지 않다.
같은 사용자의 공개키가 여러 차량이나 디바이스에 등록되어 있다면, 공격자가 한 차량에서 얻은 이 서명된 명령을 다른 차량으로 가져갈 수 있다. 서명 자체는 여전히 유효하기 때문에, 수신자는 이 명령이 원래 자신을 대상으로 만들어진 것인지 판단하기 어렵다.
따라서 다음처럼 수신자를 명시하는 것이 좋다.
Sign(SK_P, {
receiverId,
command,
commandId,
seq,
expiresAt
})
이렇게 하면 서명은 “휴대폰이 문 열기 명령에 서명했다"는 것뿐만 아니라 “휴대폰이 특정 차량을 대상으로 문 열기 명령에 서명했다"는 것까지 묶는다.
오프라인 차량 제어에서 서명해야 할 것은 명령 하나가 아니다.
누가 보내는지, 누구에게 보내는지, 어떤 세션에서 보내는지, 언제 보내는지를 함께 묶어 서명해야 한다.
실제 시스템은 어떻게 구현했는가
테슬라는 사전 등록된 공개키로 명령을 검증한다
테슬라의 차량 명령 프로토콜 은 지금까지 설명한 구조와 세부는 다르지만, 같은 문제를 같은 방식으로 푼다. 차량은 사전에 등록된 공개키를 신뢰하고, 명령에는 서명과 함께 nonce, counter, epoch 같은 값이 포함된다. 차량은 이 정보를 이용해 서버에 다시 물어보지 않고도 명령의 출처와 유효성을 검증할 수 있다. 서버에 연결할 수 없는 환경에서도 차량 제어가 가능해야 한다는 요구가, 이런 오프라인 검증 구조로 이어진다.
CCC 디지털 키는 이 구조를 표준으로 확장했다
CCC(Car Connectivity Consortium)의 디지털 키(Digital Key) 는 앞에서 설명한 구조를 차량용 디지털 키 표준으로 확장한 대표적인 사례다. 휴대폰은 Secure Element에 디지털 키를 안전하게 보관하고, 차량과는 NFC(Near Field Communication)·BLE·UWB(Ultra-Wideband)를 이용해 통신한다. 차량과 휴대폰은 상호 인증을 하고, 인증이 끝난 뒤 차량 접근이나 시동과 같은 동작을 허용한다. CCC는 차량과 휴대폰 사이의 신뢰를 공개키 기반 구조로 세우도록 정의한다.
특히 디지털 키는 인터넷에 연결할 수 없는 상황에서도 오너 페어링(Owner Pairing)과 차량 사용이 가능하도록 설계되어 있다. 지하주차장처럼 서버와 통신할 수 없는 환경에서도 이미 프로비저닝된 디지털 키를 이용해 차량을 사용할 수 있어야 하기 때문이다. 다만 키 공유나 재프로비저닝처럼 새 자격 증명을 발급해야 하는 작업에는 서버 연결이 필요하다.
디지털 키는 여기서 한 단계 더 나아간다. “유효한 디지털 키를 가진 기기인가?“만 확인하는 것으로는 충분하지 않다. 그 키를 가진 휴대폰이 실제로 차량 가까이에 있는지도 확인해야 한다. Digital Key Release 3에서는 BLE를 이용해 인증 및 세션을 수립한 뒤, UWB를 이용한 Secure Ranging을 통해 휴대폰과 차량 사이의 거리를 측정한다. 이를 통해 공격자가 두 장치 사이의 통신을 중계해 멀리 떨어진 곳에서 차량을 제어하려는 Relay Attack을 막을 수 있다.
비대칭 서명만으로는 오너 페어링을 풀 수 없다
디지털 키 시스템에는 오너 페어링이라는 과정이 있다. 차량과 소유자의 디바이스 사이에 최초로 신뢰 관계를 설정하는 단계다. 오너 페어링은 휴대폰이 정품 디지털 키 기능을 갖춘 기기인지 확인하는 과정이 아니다. 특정 휴대폰을 해당 차량의 Owner Device로 등록하고, 이후 디지털 키를 관리하거나 다른 사용자에게 키를 공유할 수 있는 권한의 출발점을 설정하는 과정이다.
여기서 문제가 하나 생긴다.
비대칭키 기반의 오프라인 인증만으로는 오너 페어링이 풀어야 할 문제를 모두 해결할 수 없다. 예를 들어 차량이 Device OEM CA 인증서를 이용해 휴대폰의 인증서 체인을 검증한다고 해보자. 이를 통해 차량은 다음과 같은 사실을 확인할 수 있다.
“눈앞의 휴대폰이 신뢰할 수 있는 제조사가 발급한 자격 증명을 가지고 있으며, 디지털 키 기능을 수행할 수 있는 정당한 기기인가?”
하지만 이것만으로는 다음 질문에 답할 수 없다.
“이 휴대폰이 지금 이 차량의 Owner로 등록될 권한이 있는가?”
즉, 기기의 정당성과 특정 차량에 대한 소유자 등록 권한은 서로 다른 문제다.
CCC 디지털 키는 이러한 초기 신뢰 설정 문제를 해결하기 위해 SPAKE2+와 같은 Password-Authenticated Key Exchange(PAKE) 방식을 사용한다. 차량과 휴대폰은 사전에 공유한 비밀이나 페어링 과정에서 받은 인증 정보로 서로를 인증하고, 비밀번호 자체를 네트워크에 노출하지 않은 상태에서 안전하게 공유 비밀을 만든다.
EMV의 DDA는 같은 소유 증명을 쓴다
EMV 칩카드 결제도 비슷한 원리를 오래전부터 사용해 온 대표적인 사례다. 카드와 단말은 공개키 기반 인증 구조를 사용하며, 단말은 카드가 제공한 인증서와 서명을 검증한다. DDA(Dynamic Data Authentication)에서는 단말이 제공하는 예측 불가능한 값을 포함해 카드가 동적 데이터를 만들고 자신의 비밀키로 서명한다. 단말은 카드의 공개키를 이용해 이를 검증함으로써 카드가 해당 비밀키를 실제로 가지고 있는지를 확인한다.
따라서 DDA는 앞에서 설명한 challenge-response 방식의 소유 증명과 같은 핵심 원리를 보여주는 사례다. 다만 EMV의 실제 인증 절차에는 인증서 체인과 동적 인증 데이터 등 여러 요소가 함께 들어간다. “난수를 받고 서명한다"만으로는 EMV 전체를 설명하지 못한다.
V2X는 메시지마다 서명을 로컬에서 검증한다
V2X(Vehicle-to-Everything)에서는 또 다른 형태로 같은 원리를 볼 수 있다. 차량과 도로 인프라 등의 장치는 PKI(Public Key Infrastructure)를 통해 발급받은 인증서를 이용해 V2X 메시지에 서명하고, 다른 장치는 그 서명을 로컬에서 검증한다. 미국의 SCMS(Security Credential Management System)는 이러한 V2X 환경에서 인증서를 발급하고 관리하기 위한 공개키 기반 구조다. 실제 SCMS 요구사항에서도 OBU(On-Board Unit)와 RSU(Roadside Unit) 등의 종단 장치가 IEEE 1609.2 인증서를 이용해 V2X 메시지에 서명하도록 정의하고 있다.
V2X에서는 특히 메시지가 여러 차량과 인프라에 브로드캐스트되기 때문에, 매 메시지를 중앙 서버에 보내 확인하는 방식은 적합하지 않다. 수신 차량이 메시지를 받은 자리에서 서명을 검증하고 신뢰 여부를 판단할 수 있어야 한다. SCMS는 이 검증에 필요한 인증서와 신뢰 체계를 제공한다.
인가는 어떻게 오프라인으로 옮기는가
인증이 “너는 누구인가"라면 인가는 “너는 무엇을 할 수 있는가"다. 인증에 성공한 휴대폰이라도 소유자의 키인지 임시로 공유받은 키인지에 따라 허용되는 명령이 달라야 한다. 디바이스 안에서 동작하는 애플리케이션마다 접근할 수 있는 데이터도 달라야 한다.
문제는 오프라인에서 인가가 겪는 제약이 인증과 정확히 같다는 점이다. 판정 시점에 정책 서버에 물어볼 수 없다. 따라서 해법의 형태도 같다.
정책 결정을 런타임에서 빌드 시점으로 앞당긴다
접근 제어는 두 부분으로 나뉜다. 허용할지 말지를 결정하는 정책 결정 지점(PDP, Policy Decision Point)과, 그 결정을 실제로 집행하는 정책 시행 지점(PEP, Policy Enforcement Point)이다. 온라인 시스템에서 PDP는 원격 서버에 있고 요청이 올 때마다 호출된다. PEP는 서버가 내려준 답을 실행할 뿐이다.
오프라인 인가는 이 결정을 요청 시점이 아니라 빌드·프로비저닝 시점에 미리 내려두고, 그 결과에 서명해서 배포하는 것이다.
인증에서 상대의 공개키를 미리 배포해 두었던 것과 똑같이, 인가에서는 권한 판정 결과를 미리 만들어 배포한다. PDP는 사전에 한 번 실행되고, 런타임의 PEP는 서버를 호출하는 대신 서명만 검증한다.
권한 토큰은 사전에 서명해 배포한다
차량 밖의 예를 하나 보자. 하나의 디바이스 안에서 로컬 저장소를 여러 클라이언트가 공유하고, 클라이언트마다 읽고 쓸 수 있는 스키마가 다른 상황을 가정한다. 중개 역할을 하는 로컬 서비스는 권한 판정을 위해 원격 정책 서버를 호출할 수 없다.
- 발급 서버는 “어떤 클라이언트가 어떤 리소스에 어떤 동작을 할 수 있는가"를 정책으로 정의한다.
- 런타임이 아닌 사전 단계에서 각 클라이언트별 권한 목록을 만들고 비밀키로 서명해 권한 토큰을 발급한다.
- 토큰은 클라이언트 배포물에 함께 포함되어 나간다.
- 로컬 서비스는 발급 서버의 공개키를 HSM이나 TEE 같은 안전 저장 영역에 보관한다.
- 런타임에 클라이언트가 요청과 함께 토큰을 제시하면, 로컬 서비스는 서명을 검증하고 토큰에 적힌 권한 범위 안에서만 요청을 허용한다.
토큰에는 최소한 주체 식별자, 허용된 리소스와 동작의 목록, 유효 기간, 발급자, 정책 버전이 들어간다. 서명 덕분에 토큰은 위조할 수 없고, 클라이언트가 자기 권한을 스스로 주장할 여지가 사라진다.
오프라인 판정은 잠정적 결정이다
오프라인에서 내린 인가 판정은 최종 판정이 아니다.
디바이스가 네트워크에 복귀하면 서버가 다시 판정할 수 있게 된다. 로컬에서 허용된 요청이라도 서버에서 한 번 더 정책을 검증하는 이중 검증이 심층 방어(Defense in Depth)의 기본이다. 오프라인 인가는 “서버를 대신하는 결정"이 아니라 “서버가 없는 동안의 잠정적 결정"으로 설계해야 한다.
로컬에서 먼저 동작하고 연결이 복구되면 서버와 맞춰가는 이 사고방식은 IoT 메시지 전달을 위한 MQTT와 ZERO PAYLOAD 에서 다룬 Offline-First와 같은 구조다. 차이가 있다면 동기화되는 대상이 데이터가 아니라 권한 판정이라는 점이다.
맺음말
오프라인 인증과 인가는 서버를 없애는 기술이 아니다. 서버가 내려야 할 판정을 미리 끝내 서명해 두고, 현장에서는 그 서명만 검증하는 설계다. 인가에서는 서명된 권한 토큰이 미리 내려둔 판정이고, 인증에서는 신뢰 앵커가 미리 심어둔 판정 기준이다.
그래서 오프라인 설계의 무게중심은 검증 시점이 아니라 그 앞에 있다. 어떤 키를 언제 어디에 심을 것인지, 어떤 권한을 어느 시점에 서명해 둘 것인지가 런타임의 안전성을 결정한다.
오프라인 설계의 핵심은 검증을 없애는 것이 아니라, 검증에 필요한 답을 검증 시점보다 앞에 배치하는 것이다.
References
- RFC 8705, OAuth 2.0 Mutual-TLS Client Authentication and Certificate-Bound Access Tokens
- SPAKE2+, an Augmented Password-Authenticated Key Exchange (PAKE) Protocol
- RFC 2986, PKCS #10: Certification Request Syntax Specification
- IEC/IEEE 60802 Security Slice
- SCMS Manager provider Requirements
- Tesla, Vehicle Command SDK Protocol
- Car Connectivity Consortium, Digital Key
- IEEE 802.1AR, Secure Device Identity
