서명 기반 비자(Visa) 규격의 불명확성
요약
AI 쇼핑 에이전트를 위한 검증 레이어를 구축하는 과정에서 직면한 Visa의 Trusted Agent Protocol(TAP) 규격 불명확성 문제를 다룹니다. 특히 서명 베이스(signature base)를 생성하는 정형화된 표현 방식의 모호함이 구현에 미치는 영향을 분석합니다.
핵심 포인트
- AI 에이전트 결제를 위한 Visa TAP 프로토콜의 3단계 레이어 구조 분석
- RFC 9421 기반의 HTTP 메시지 서명 및 ID 토큰 검증의 명확성 확인
- 서명 베이스 생성을 위한 객체의 정형화된 표현(canonical representation) 규격의 모호성 지적
원래 avalayer.com/writing의 Field Notes 001에 게시되었습니다.
검증(Verification)은 기묘한 사업입니다. 결국 당신이 판매하는 것은 타인의 약속에 대한 확실성입니다. 그래서 우리는 AI 쇼핑 에이전트(AI shopping agents)를 위한 가맹점 측 검증 레이어(verification layer)를 구축할 때 스스로 규칙을 세웠습니다. 모든 프로토콜을 공개 규격(public-spec)의 깊이까지 구현하고, 실제 운영 중인 키 자료(production key material)를 통해 검증하며, 확실하지 않은 부분이 있다면 솔직하게 밝히는 것입니다. 이 에세이는 그 규칙이 흥미로워졌던 한 지점에 관한 이야기입니다.
배경을 설명하자면, 우리의 API는 모든 AI 에이전트로부터 서명된 요청(signed request)을 수락하고, 신뢰할 수 있는지 여부와 유형화된 이유(typed reason)를 포함한 판결을 반환합니다. 솔직히 말씀드리면, 우리는 Visa의 신뢰할 수 있는 에이전트 프로토콜(Trusted Agent Protocol, TAP)을 포함하여 네 가지 프로토콜을 구현했습니다. 그 작업의 대부분은 구현 작업이 마땅히 가야 할 방향으로 진행되었습니다. 규격(spec)이 무언가를 말하면, 그것을 구축하고, 테스트를 통과하며, 암호학(cryptography)은 암호학이 해야 할 일을 수행합니다. 암호학은 이 산업에서 신뢰할 수 있는 절반입니다. 신뢰할 수 없는 나머지 절반은 합의(agreement)입니다. 규격이란 만난 적 없는 사람들 사이의 현실에 대한 합의이며, 대부분의 그러한 합의와 마찬가지로, 누군가 그것을 주의 깊게 읽기 전까지만 유효합니다.
세 개의 레이어, 그중 두 개는 깔끔함
Visa TAP는 세 개의 레이어로 구성된 프로토콜입니다. 외부 레이어(outer layer)는 에이전트의 신원(identity)과 의도(intent)를 특정 가맹점 및 경로에 결합하는 RFC 9421 HTTP 메시지 서명(HTTP message signature)입니다. 중간 레이어(middle layer)는 본문에 포함된 소비자 인식 객체(Consumer Recognition Object)로, mcp.visa.com에 게시된 Visa의 JWKS를 통해 검증할 수 있는 Visa 서명 신원 토큰(identity token)을 포함합니다. 내부 레이어(inner layer)는 마찬가지로 서명된 에이전트 결제 컨테이너(Agentic Payment Container)입니다.
레이어 1과 2는 즐거운 과정이었습니다. RFC 9421은 정의된 서명 베이스 (signature base), 작동 예시, 그리고 수년간의 구현 과정에서 쌓인 경험(implementation scar tissue)을 갖춘 성숙한 규격입니다. ID 토큰 (identity token)은 활성화된 공개 키 세트 (public key set)를 통해 검증됩니다. 우리는 Visa의 운영 환경 JWKS를 가져와 실제 RSA 키를 해석하고 실제 서명을 검증했습니다. 규격이 이 정도로 명확한 기준을 제공할 때 독립적인 검증 (independent validation)이 가능해지며, 독립적인 검증이야말로 이 게임의 핵심입니다.
레이어 3은 우리가 난관에 봉착한 지점입니다.
한 문장, 네 가지 질문
서명된 바디 객체 (signed body objects)에는 서명 베이스 (signature base), 즉 서명되고 검증되는 정확한 바이트 문자열 (byte string)이 필요합니다. 공개 규격은 이를 단 한 문장으로 설명하며, 서명 필드 자체를 제외하고 베이스는 "수신된 순서대로 객체의 모든 필드를 정형화된 표현 (canonical representation)으로 나타낸 것"이라고 명시합니다.
그 한 문장이 한 장(chapter) 분량의 역할을 수행하고 있지만, 실제 구현자가 갖는 질문에는 전혀 답을 해주지 못합니다.
- 렌더링 (Rendering). 각 필드는 가공되지 않은 JSON (raw JSON)인가요? 이름과 값의 쌍인가요? 문자열은 따옴표로 감싸져 있나요, 아니면 그대로인가요?
- 중첩된 값 (Nested values). 압축된 형태 (compact)인가요, 아니면 보기 좋게 출력된 형태 (pretty printed)인가요? 키 (keys)의 순서가 재정렬되나요, 아니면 유지되나요?
- 결합 (Joining). 필드 사이에 줄바꿈 (newlines)이 들어가나요? 마지막에 줄바꿈이 붙나요, 아니면 붙지 않나요?
- 순서 (Ordering). "수신된 순서 (order received)"는 아마도 삽입 순서 (insertion order)를 의미하겠지만, 모든 프로그래밍 언어가 이에 대한 약속을 지키는 것은 아닙니다.
여기에 함정이 있습니다. 그 문장이 틀린 것은 아닙니다. 그것이 문제입니다. 틀렸다면 차라리 눈에 보였을 것입니다. 이 네 가지 질문에 대해 어떤 합리적인 답변을 내놓더라도 작동하는 구현 (implementation)을 만들어낼 수 있습니다. 자신의 답변으로 서명하고, 자신의 답변으로 검증하면 모든 테스트를 통과합니다. 당신의 구현은 정확합니다. 다른 모든 사람의 구현도 마찬가지입니다. 서로 다른 시간대에 예정된 회의에 두 사람이 모두 정시에 도착할 수 있는 것처럼, 모두가 각자에게는 정답인 상태가 됩니다.
서명 베이스 (signature base)는 네트워크 선로(wire)를 통해 절대 전달되지 않습니다. 그것은 서명자(signer)의 메모리와 검증자(verifier)의 메모리 내에서만 잠시 존재하며, 만약 이 두 구성이 서로 다르더라도 그 이유를 알려주는 에러 메시지는 결코 나타나지 않습니다. 대신 여러분이 마주하게 될 것은 암호학이 보여줄 수 있는 감정의 모든 스펙트럼, 즉 "유효하지 않은 서명 (invalid signature)"입니다. 각자 완벽하게 자기 완결적인 제품을 출시한 두 팀 사이에서, 몇 달 뒤에야 이 불일치가 마침내 표면 위로 드러날 때, 그것은 버그처럼 보일 것입니다. 하지만 그것은 버그가 아닙니다. 그것은 아무도 인지하지 못했던 의견 차이일 뿐입니다.
우리는 이 문제를 해결할 유물을 찾아보았습니다. 개발자 문서에는 작동 예시가 없습니다. 샘플 리포지토리(sample repository)는 서명된 객체(signed objects)는 보여주지만, 서명된 바이트(bytes) 자체는 결코 보여주지 않습니다. 테스트 벡터(test vector)도 존재하지 않습니다. 우리가 파악한 바로는, 두 개의 독립적인 TAP 구현체가 서로 일치함을 증명할 수 있는 공개된 객체는 세상에 존재하지 않습니다.
우리가 한 일
다른 사람들에게 유용할 가능성이 높아지는 순서대로 세 가지를 수행했습니다.
첫째, 하나의 해석 방식을 선택하고 그것을 하나의 규격으로 명명했습니다. 우리의 해석은 RFC 9421의 베이스 스타일을 반영합니다: 삽입 순서에 따라 필드당 하나의 이름과 값 라인을 배치하고, 문자열은 가공 없이(bare) 두며, 그 외 모든 것은 줄바꿈으로 연결된 컴팩트 JSON (compact JSON) 형식을 사용합니다. 이 방식은 우리의 서명자와 검증자가 공유하는 단일 함수 내에 존재하므로, 우리의 라운드 트립 (round-trip)은 정확합니다. 만약 Visa가 이와 다른 규범적인 답변을 발표하더라도, 수정 사항은 단 하나의 함수뿐입니다. 여러분의 추측을 격리하십시오. 그리고 각 추측에 주소를 부여하십시오.
둘째, 불확실성을 우회하는 대신 공개 문서에 직접 명시했습니다. 우리의 README에는 해당 구조가 미지정(under-specified) 상태임을 밝히고, 우리의 해석을 담고 있는 함수를 가리키고 있습니다. 확신을 팔면서 몰래 추측하는 대안적인 방식은, 고객이 결국 찾아내게 될 모순의 종류입니다.
셋째, 우리는 Visa의 리포지토리(repository)에 네 가지 질문을 한 번에 해결할 수 있는 단 하나의 결과물, 즉 샘플 객체(sample object), 해당 객체의 정확한 서명 베이스 문자열(signature base string), 그리고 공개된 테스트 키(test key)로 생성된 유효한 서명을 요청하는 공개 이슈(public issue)를 제출했습니다. 만약 우리의 해석이 그들의 의도와 일치한다면, 우리가 직접 테스트 벡터(test vectors)를 기여하겠다고 제안했습니다. 해당 이슈는 github.com/visa/trusted-agent-protocol/issues/23에 올라와 있으며, 만약 여러분이 TAP를 구현하고 있다면 언제든 참여를 환영합니다.
일반적인 교훈
테스트 벡터(Test vectors)는 산문(prose)만큼이나 규범적입니다. 솔직히 말하면 그 이상입니다. 산문은 비용이 발생하기 전까지는 아무도 알아채지 못하는 방식으로 모호할 수 있지만, 바이트 문자열(byte string)은 그럴 수 없기 때문입니다. 산문은 규격(spec)이 약속을 하는 곳입니다. 테스트 벡터는 그 약속을 지키는 곳입니다.
규격에서의 모호함은 대출과 같으며, 그 이자는 두 번째로 구현하는 사람이 지불하게 됩니다. 현재 에이전틱 커머스(agentic commerce) 분야는 이러한 대출을 많이 받고 있습니다. Visa의 TAP, Google의 AP2, IETF의 Web Bot Auth 초안, EMVCo의 자격 증명 스키마(credential schemas) 등이 모두 공개된 상태에서 빠른 속도로 작성되고 있으며, 대부분은 두 개의 독립적인 구현체가 서로 만나기도 전에 작성되고 있습니다. 그 만남이야말로 규격이 실제로 테스트되는 지점인데, 아직 그런 만남은 거의 일어나지 않았습니다. 이번 달에 EMVCo의 초안 스키마 프레임워크(draft schema framework)에 대한 의견을 제출했을 때, 우리의 첫 번째 요청은 Visa에 했던 것과 동일했습니다. 즉, 구현이 갈라진(divergence) 후가 아니라, 버전 1과 함께 작동 예시(worked example)를 배포하라는 것이었습니다.
만약 여러분이 이 분야의 규격을 작성하고 있다면: 하나의 완전한 샘플, 서명되는 정확한 바이트(bytes), 그리고 테스트 키를 사용한 서명을 공개하십시오. 이는 몇 년간의 소리 없는 불호환성을 방지할 수 있는 단 몇 시간의 작업입니다. 만약 여러분이 무언가를 구현하고 있다면: 한 문장이 한 장(chapter) 분량의 역할을 수행하고 있다는 것을 발견했을 때, 단순히 답을 선택하지 마십시오. 추측을 분리하고, 그것을 추측이라고 명명하며, 다음 구현자가 그 부분에서 걸려 넘어질 수 있도록 명시하십시오. 모호함에 대해 크게 목소리를 내는 것은 딱 한 번, 즉 시작 단계에서만 비용이 적게 듭니다. 우리는 지금 시작 단계에 있습니다.
어쨌든 그것이 우리가 스스로에게 지키려고 노력하는 규율입니다. 검증(Verification)은 신뢰를 기반으로 하는 비즈니스이며, 신뢰를 기반으로 하는 비즈니스가 대충 얼버무리는 것은 용납되지 않습니다. 규격(Spec)이 명확한 곳에서는 우리도 명확하게 행동합니다. 규격이 명확하지 않은 곳에서는, 우리는 공개적으로 그렇다고 말하고 질문을 던집니다.
신뢰는 모두가 동의하는 곳에서 쌓이는 것이 아닙니다. 누군가가 자신이 확신할 수 없음을 인정하고, 자신의 작업 과정을 보여줄 때 쌓입니다.
– N.M.
AVA Pay™는 AI 커머스를 위한 가맹점 측 신뢰 게이트웨이(trust gateway)입니다. AI 쇼핑 에이전트가 이미 보유하고 있는 서명(IETF Web Bot Auth, Visa TAP, Google AP2)을 검증하는 단일 API를 제공하며, 가맹점이 검증된 신원(verified identity)에 대해 어떤 혜택을 부여할지 정책을 설정할 수 있게 합니다. 검증기(Verifier), SDK, 그리고 240개의 모든 실제 암호학(real-cryptography) 테스트는 github.com/AVA-PAY/ava-pay에서 오픈 소스로 공개되어 있습니다. 더 많은 에세이는 avalayer.com/writing에서 확인할 수 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기