본문 바로가기

디미페이

🤫오프라인이지만 온라인이어야 해요 - 로컬 생성 결제 토큰

 

디미페이는 네이버페이와 카카오페이처럼 사용자 휴대폰에서 제시되는 QR 코드로 오프라인 결제를 제공해요. 그런데 디미페이를 포함한 이런 대중적인 오프라인 결제 서비스를 사용하기 위해 공통적으로 필요한 게 있어요. 바로 "인터넷"이에요. 오프라인 결제를 하는데, 온라인이어야 한다니, 뭔가 모순적이지 않나요?

 

사실 요즘 밖에서 인터넷을 사용하지 못하는 사람은 많이 없다고 생각해요. 그래서 크게 중요하게 생각하지 않을 수도 있는데, 저희가 인터넷 환경에 신경쓰는 이유는 디미페이가 학생들을 위한 결제 서비스이기 때문이에요. 학생들은 상대적으로 모바일 데이터가 부족한 경우가 많아요.

 

인터넷이 안돼서 친구가 대신 결제해 주고 나중에 송금해 준다는 걸 저희 팀원에게 들었을 때 꾀 충격적이었어요. 모든 학생이 차별 없이 사용할 수 있는 서비스를 만드는 것이 저희의 최종 목적인데, 아주 큰 걸 놓치고 있었다는 걸 깨달았죠.

 

다른 방법은 없었나요?

저희들끼리 오프라인 결제를 만들어보자는 이야기가 가볍게 오가긴 했지만, 실제로 만들기 전에 다른 대안이 있는지 확인해봤어요.

 

근본적인 원인을 "인터넷 접근이 불가능한 경우가 존재한다"라고 정의하면, 아래와 같은 방법을 생각해 볼 수 있어요.

  1. 매점 와이파이 개방
  2. 더치페이/외상 기능 추가
  3. 인터넷 없이 결제할 수 있는 환경 구축

 

매점 와이파이 개방

가장 확실하고 쉬운 방법으로 와이파이 개방을 선택하면 편할 것 같아요. 하지만 많으면 한 번에 약 20명 이상의 학생들이 매점에 모이고, 매점 앞 주위에 있는 학생들까지 고려하면 작은 공유기만 설치된 공간에선 오히려 네트워크 속도가 느려지고 키오스크마저 영향을 받을 수도 있어요. 그리고 매점 인터넷 개방을 목적으로 네트워크 시설을 늘릴 수도 없어요. 아쉽지만 역시 직관적인 방법은 좋은 해결책이 아니었어요.

 

더치페이

그럼 학생들이 대안으로 사용하던 더치페이는 어떨까요? 만들면 정말 재밌겠어요. 하지만 저희는 은행이 아니기 때문에 직접적으로 송금을 할 순 없어요. 하지만 완전히 방법이 없는 건 아닌데, 부분 취소를 이용하면 어느 정도 흉내 낼 수 있어요.

 

한 학생이 매점에서 결제 → 학생이 다른 학생들의 이메일을 입력 → 결제 기록을 보고 누가 뭘 샀는지 일일이 확인

→ 더치페이 요청 → 요청받은 학생이 결제 진행 → 최초 결제 학생에게 부분 취소 → (반복)

 

차라리 송금을 하는 게 더 빠를 것 같아요. 🫤

 

인터넷 없이 결제

 결국 가장 어려워 보이지만 제일 확실하고 기존 결제 플로우에 변경이 없는 방법인 인터넷 없는 결제 환경을 만드는 게 최선의 선택이었어요. 

 

어디서 들어본 것 같은데요?

사실 인터넷 없이 결제를 지원하는 간편 결제 서비스는 이미 존재하고있어요. 대표적으로 Apple Pay와 Google Pay가 있고, 삼성페이도 해외에선 인터넷 연결 없이 결제를 지원해요.

When you are using Samsung Pay to make a purchase, no internet connection is needed. However, some networks will limit you to 10 transactions during a period without internet access, after which Samsung Pay will require an active internet connection. We recommend connecting to the internet at least once per day to ensure Samsung Pay stays up-to-date.

삼성 페이를 사용하여 결제할 때는 인터넷 연결이 필요하지 않습니다. 그러나 일부 네트워크에서는 인터넷에 연결되지 않은 기간 동안 10회의 거래로 제한되며, 그 이후에 삼성 페이를 사용하려면 인터넷 연결이 필요합니다. 삼성 페이를 최신 상태로 유지하려면 하루에 한 번 이상 인터넷에 연결할 것을 권장합니다.
(Commonly asked questions about Samsung Pay)

 

 

그럼 QR 코드를 이용한 결제 서비스들은 어떨까요? 아쉽게도 QR 코드를 사용하는 국내 간편결제 서비스는 모두 인터넷 연결을 필요로 해요. 대신 해외 서비스인 Alipay는 유일하게 인터넷 연결이 없이 결제 토큰을 발급할 수 있어요. (국내 앱 중 해외 결제로 Alipay를 사용하는 경우, 인터넷이 연결되어있지 않을 때 첫 토큰 발급은 불가능하지만 갱신은 가능해요.)

 

어쩌다 보니 국내 최초로 인터넷 없이 QR 결제 토큰을 만들게 되었네요.😳

 

Local Generated Pay Token (로컬 생성 결제 토큰)

 저는 인터넷 없이 사용자 기기에서 발급할 수 있는 결제 토큰을 "로컬 생성 결제 토큰"이라고 부르기로 했어요. 지금부턴 짧게 "로컬 토큰"이라고 할게요. 로컬 토큰은 결제 토큰을 인터넷 없이 만든다는 점뿐만 아니라 클라이언트 애플리케이션의 오프라인 모드 지원, 그리고 빠르고 일관된 토큰 생성 시간을 보장할 수 있어요. 이는 인터넷이 전혀 없는 상황뿐만 아니라 느린 인터넷 환경보다 더 좋은 결제 경험을 제공할 수 있어요.

 

전체 사양은 local-generated-payment-token리파지토리에서 보실 수 있어요.

 

온라인 인증

로컬 토큰의 원리를 알아보기 전에 인터넷 인증 기반의 토큰 생명 주기(lifecycle)가 어떻게 되는지 볼게요.

 
  flowchart LR
    PA[결제 핀 인증] --> SA{{결제 서버 인증}} --> SP
    LA[로컬 인증] --> SP
    SP[결제 수단 선택] --> IT{{토큰 발급}}
    -- 1분 후 --> EP[토큰 만료]

 

사용자는 사용할 결제 수단을 선택하고, 결제 비밀번호를 입력하거나 로컬 인증(생체 인증 등)을 시도해요. 인증에 성공하면 클라이언트 앱은 결제 서버로부터 1회용 결제 토큰을 발급받아요. 이 토큰이 QR 코드에 담기는 값이에요. 마지막으로 토큰의 유효기간이 지나거나 토큰이 결제에 사용되면 토큰은 만료돼요.

 

온라인 인증 방식을 사용하면 언제 어디서 토큰을 만들었는지 같은 정보로 사용자 행동에 대한 감사가 가능해 보안에서 이점이 있어요. 그리고 결제 수단과 결제에 대한 정보를 길이가 짧은 토큰에 매핑할 수 있어 토큰을 바코드 형태로 제공할 수 있다는 장점이 있어요. 이러면 QR 코드 리더기가 없는 매장에서도 사용할 수 있고 입력 속도가 느린 리더기라도 빠른 결제가 가능해요.

바코드 리더기는 붙여 넣기처럼 한 번에 입력되는 게 아니라 키보드처럼 한 글자씩 빠르게 입력해요.

카카오페이 토큰 (281006026784316707863518 )

 

하지만 네이버페이나 KB페이처럼 EMV CPM-QR 규격을 따르거나 자체 규격을 사용하는 일부 서비스는 온라인 인증 방식을 사용하더라도 토큰의 길이가 바코드로 나타낼 정도록 작지 않아 항상 적용되는 장점은 아니에요.

 

서버의 역할

토큰을 생명주기를 통해 우리는 서버가 핀 인증, 토큰 생성, 그리고 토큰 만료를 담당한다는 걸 알 수 있어요. 만약 이 부분을 서버로부터 분리하면 인터넷 없는 결제 토큰을 만 들 수 있을 것 같아요.

 

토큰 디자인

위 지식을 바탕으로 제가 처음 로컬 토큰을 설계할 때 생각한 방법을 나타내보았어요.

 

결제를 위해 필요한 최소한의 정보는 사용자 식별자와 결제수단 식별자예요. 결제 수단 식별자는 전역으로 고유한 값을 가진다면 사용자 ID도 사용할 필요가 없지만, 나중에 일부 페이로드 암호화할 경우를 위해 사용자 ID도 함께 사용했어요. 암호 키를 가져오려면 사용자 ID가 필요하거든요.

토큰 디자인 1

 

하지만 이 두 값을 그대로 사용하면 누구나 다른 사람의 결제 수단을 도용할 수 있어요. 사용자 ID와 결제수단이 자신의 것인지 증명할 수 있는 장치가 필요해요.

토큰 디자인 2

 

그런데 이 보안토큰이 정적이라면 아무 의미가 없을 거예요. 보안 토큰은 지속적으로 바뀌는 동적 토큰 이어야 해요. 보안 토큰이 바뀌면 이전 토큰은 저절로 만료돼요.

토큰 디자인 3

 

마지막으로 이 토큰을 상품 바코드나 다른 바코드와 다르다는 걸 알려주는 토큰 식별자를 추가했어요. 토큰 식별자는 토큰 자체를 식별하기도 하지만 토큰 사양의 버전 등 필요한 정보를 함께 담을 수 있어요.

토큰 디자인 4

 

지금 부터 설명하는 내용의 많은 부분은 새로운 0.4.버전에서 크게 업데이트 되었어요. 하지만 모두 0.4 버전의 기반이 되는 기술이라 만약 끝까지 다 읽으셨다면 0.4 릴리즈 노트도 꼭 확인해 주세요.🤗

동적 보안 토큰(동적 오프라인 인증)

가중 중요한 부분인 보안 토큰부터 다뤄볼게요. 동적 오프라인 인증의 대표적인 접근 방법은 시각을 이용하는 거예요. 시각은 계속 변하는 값이고, 서버와 클라이언트가 별도의 통신 없이 동일한 값을 알 수 있기 때문이에요. Google Authenticator 같은 OTP 서비스나 역에 있는 OTP 사물함을 사용해 보신 적 있으신가요? 모두 같은 원리를 사용하여 일회용 비밀번호를 만들어요.

또 다른 동적 인증 방법은 아래에서 다뤄요.

Google Authenticator

 

이 비밀번호를 TOTP(Time-based one-time password)라고해요. TOTP는 특정 시간 간격마다 새로운 비밀번호를 생성할 수 있어요. 원리는 기준 시각(주로 2FA가 등록된 시각)과 시크릿 키를 서버와 사용자 기기에 저장하고, 현재 시각을 기준으로 "카운터"를 계산한 뒤, HOTP(HMAC-based one-time password)라는 알고리즘으로 6자리 숫자를 산출해요.

 

카운터는 특정 시간마다 비밀번호가 업데이트되도록 해주어요. 즉, 서버가 담당하던 "토큰 자동 만료"를 구현하게 되죠. 카운터를 계산하려면 Unix 시간의 기준 시각(\(T_{0}\))과 업데이트 주기인 카운터 간격(\(T_{x}\))이 필요해요. 카운터 간격은 보통 30초나 1분으로 설정해요. 준비된 값을 아래 수식에 대입하면 카운터 값을 구할 수 있어요.

 

$$C=\left\lfloor {\frac {T-T_{0}}{T_{X}}}\right\rfloor$$

 

카운터를 구하면 다음으로 HOTP를 적용해요. HOTP는 두 가지 동작을 수행하는데, 카운터와 시크릿 키로  HMAC값을 구하고, 이 값을 다시 6-10 자리로 줄여요. 여기서 HMAC은 해쉬함수를 이용한 메시지 인증 코드(MAC)로, 공유된 시크릿 키로 메시지의 무결성을 확인하는 알고리즘이에요. 다시 말해 퍼블릭에 공개되는 일반 텍스트와 시크릿 키로 해시를 만들어 중간에 누가 메시지를 변경하지 못하도록 해주어요. JWT를 사용해보적이 있다면 HS256이라는 알고리즘을 한 번쯤 들어봤을 거예요. 이게 바로 SHA-256 알고리즘을 사용하는 HMAC이에요.

 

다시 HOPT로 돌아올게요. HOTP는 HMAC 값을 짧게 줄인다고 했었어요. 구해진 HMAC 값을 자르는 이유는 보통 TOTP나 HOTP값을 사람이 직접 입력을 하기 때문이에요. HMAC은 사용하는 해쉬 알고리즘에 따라 길이가 달라지지만 사람이 일일이 입력하기엔 매우 긴 값이기 때문에 짧은 자리로 자르는 것이죠. 해시함수로 SHA-256을 사용하면 77자리예요. 더 긴 함수인 SHA-512를 사용했다면 154자리가 돼요.🤓 결괏값을 줄일 땐 단순히 앞자리를 이용하는 게 아니라 특정 방법을 사용하는데, 이 부분은 오늘 살펴보지 않을게요.

 

TOTP가 구해지는 과정을 정리해 볼게요.

  • TOTP: 현재 시각과 카운터로 HOTP값을 구한다.
  • HOPT:  HMAC 값을 구하고 이를 6~10 자리로 줄인다.
  • HMAC: 메시지(카운터)를 시크릿 키를 주어진 해시 알고리즘에 적용한다.

 

그런데 저희는 QR 코드를 사용해요. 이 비밀번호를 직접 입력하지 않는다는 거죠. 그러면 굳이 6~10자리로 잘라야 할 필요가 있을까요? 그럼 HOTP를 사용할 필요가 있을까요? 그래서 저는 저는 TOTP가 사용하는 카운터 계산법과 전체 HMAC 값을 사용하기로 했어요. 

 

로컬 인증

결제 QR 코드를 만들기 전, 우리는 생체 인증이나 결제 핀을 입력하는 과정을 거쳐요. iOS의 페이스 ID나 지문 인식처럼 휴대폰에서 사용하는 인증방법을 로컬 인증(local authentication)이라고 해요. 로컬 인증에 성공하면 미리 기기에 저장된 키를 가져올 수 있는데, 저희는 이 키를 바이오키(bio key)라고 불러요. 이 키가 바로 HMAC의 시크릿 키로 사용돼요 -> 이 설계는 논리적으로 오류가 있어요. 0.4 릴리즈 노트를 꼭 확인 해주세요.

 

일반적으로 로컬 인증이 실패한다면 대안(fallback)으로 결제 핀 인증을 시도해요. 하지만 결제  핀 인증은 온라인 인증이에요. 핀 정보를 가지고 있는 주체는 오직 서버뿐이거든요. 사실 아직까지 이 부분이 고민이에요. 로컬 토큰 전용 코드를 별개로 사용할지, 핀 정보를 기기에 저장할지, 아니면 핀 인증을 포기할지. 지금 저희는 결제 핀 인증을 사용하지 않기로 했는데, 혹시 좋은 방법이 있다면 한번 같이 이야기해보아요. 🤗

 

 Time-step Window

카운터는 토큰을 일정시간마다 새롭게 만들어주는 역할을 가진다고 했어요. 하지만 이 방법에는 한 가지 문제점이 있어요.

얼마남지 않은 유효시간

 

OTP 서비스를 사용해 본 분들은 쉽게 공감할 수 있을 거예요. OTP 앱을 켜면 유효기간이 항상 일정하지 않았을 거예요. 유효기간이 많이 남을 때도 있지만, 위 그림처럼 유효기간이 얼마 남지 않아 새로운 토큰이 만들어질 때까지 기다린 적이 있지 않나요?

 

그런데  어느 사이트는 분명 유효 시간이 지나고 번호를 입력했는데도 인증이 성공되기도 해요. 어떻게 한 걸까요? 바로 이전 간격의 코드도 인정해 주도록 설계했기 때문이에요. 이를 Time-step Window라고 해요.

 

그렇지만 QR 코드를 사용하니까 이런 일이 발생 안 하지 않을까요? 아무리 토큰이 길더라도 사람이 입력하는 것보단 바코드 리더기가 더 빨리 입력할 거니까요. 그러나 사용자 기기의 시간이 정확하지 않거나, 네트워크 지연 등의 이유로 충분히 가능성 있는 시나리오예요. 결제에 실패하면 새로운 QR을 다시 찍으면 되긴 하지만, 사용자가 이런 경험을 하는 건 원하지 않아요.

 

30s30sToken generatedToken receivedinvalid token!

 

결제에 실패한다고 항상 time-step window를 고려하지 않아도 괜찮아요. 가능성이 있을 때만 시도하는 게 좋아요. 예를 들어 현재 시각이 새로운 간격으로 넘어온 지 5초밖에 되지 않았을 때만 시도하도록 구현할 수 있어요.

자세한 Time-step window에 대한 내용은 RFC 6238 section 5.2에서 확인하실 수 있어요.

 

이제 완벽한 자동 만료는 구현했어요.💪

 

결제 후 만료 - Nonce

토큰의 자동 만료는 구현했었어요. 결제 후 만료는 어떻게 구현할까요? 여러 구현 방법이 있겠지만, 저는 Nonce를 이용하기로 했어요. Nonce는 암호문이 한 번만 사용되는 것을 보장하기 위해 사용되는 무작위 숫자예요. 일반적으로 클라이언트가 서버로부터 nonce 값을 받지만, 저희는 클라이언트가 생성하는 nonce를 사용해요(cnonce라고 구분하기도 합니다).

 

서버는 토큰을 이용해서 성공적으로 결제를 완료하면 카운터 간격동안만 nonce값을 기억해요. 새로운 카운터가 사용되면 HMAC 인증이 실패하니까요.

 

nonce는 카운터의 또 다른 문제점을 해결하기도 해요. 카운터의 또다른 단점은 카운터 간격이 지나기 전까지 새로운 토큰을 만들 수 없다는 것인데, nonce가 함께 사용되면 토큰을 언제든지 새로 발급할 수 있어요. 

 

이제 결제 후 토큰 만료까지 성공적으로 구현했어요!

지금은 nonce값은 16바이트 무작위 수를 사용해요. nonce를 시간과 연관시켜 생성할 수 있다면 유효성 검사를 더 빠르게 진행할 수 있을 것 같아요.

 

Deep Dive 🌊

동적 암호화가 로컬 토큰의 가장 중요한 개념이라 먼저 자세히 소개해드렸어요. 로컬 토큰의 전체 모습을 조금 더 깊게 둘러볼게요.

 

로컬 토큰은 JSON 같은 포맷없이 평문 텍스트로 구성되고, 세 가지 논리적 단위로 나눌 수 있어요.

  • Metadata (메타데이터)
    • Payload Format Indicator (페이로드 포멧 지시자)
    • Application Name Identifier (애플리케이션 식별자)
    • Version (버전)
  • Common Payload (Public Payload) (일반/공개 페이로드)
    • Auth Type (인증 유형)
    • User Identifier (사용자 식별자)
  • Private Paylod (Encrypted payload) (프라이빗 페이로드/암호화 페이로드)
    • Device Identifier (기기 식별자)
    • Payment Method Identifier (결제 수단 식별자)
    • HMAC
    • Nonce

로컬 토큰

Metadata

메타데이터 페이로드는 토큰 정보를 저장하기 위해 사용돼요. 페이로드 포맷 지시자는 EMV CPM-QR에서 영감을 얻었는데, 이 토큰이 로컬 토큰임을 나타내는 2바이트 정보이고 고정값 `0x4c 0x50`를 사용해요.

 

애플리케이션 식별자는 토큰을 발급한 애플리케이션을 구분하는 정보예요.

 

버전은 코드가 어떤 버전의 사양을 따르는지를 나타내요. 1바이트 정보이며, 버전의 첫 4비트는 major 버전, 다음 4비트는 minor 버전을 표시해요. major 버전은 코어 스펙이 변경될 때, minor 버전은 작은 수정 등의 변경이 발생했을 때 바뀌는 규칙을 가지고 있어요.

1) 0001 0000 (0x10) → 1.0v
2) 0011 0101 (0x35) → 3.5v

 

Common

일반 페이로드는 퍼블릭 페이로드예요. 즉 암호화 없이 평문 값을 그대로 노출해도 괜찮을 정보가 포함돼요.

 

Private Payload - 페이로드 암호화

프라이빗 페이로드는 암호화되어 전달되어야 하는 민감한 정보를 저장할 때 사용해요. 여기엔 사용자 기기 식별자와 결제 수단 식별자, 그리고 앞서 살펴본 HMAC 값과 Nonce값이 포함돼요.

 

"HMAC과 Nonce값만 있으면 되지 않나요? 꼭 암호화를 해야 하나요?"

 

물론 HMAC으로 HMAC 파라미터(secret key, counter)를 알 순 없어요. 그렇지만 기기 식별자(Device Identifier)와 결제 수단 식별자(Payment Method Identifier) 같은 개인정보를 페이로드에 그대로 노출하고 싶진 않아요. 그리고 raw HMAC 값을 알면 거의 불가능하지만 brute-force 공격이 가능해요. 

 

암호화에는 크게 두 가지 종류가 있어요. 패스워드 암호로도 불리는 대칭키(symmetric) 암호, 그리고 퍼블릭 키 암호화로 불리는 비대칭(asymmetric) 키 암호화가 있어요. 대칭키 암호화는 비교적 속도가 빠르고 큰 데이터를 암호화하는데 적합해요. 하지만 키가 두 주체에게 저장되기 때문에 키 유출에 더 신경 써야 해요. 퍼블릭 키 암호화는 수학적으로 연관된 두 키를 사용하고, 암호화에 사용되지 않은 다른 키로만 복호화를 할 수 있어요. 하지만 대칭키 암호화에 비해 더 많은 시간이 걸리고 암호화 결과가 커요.

 

만약 여러분이 저라면 어떤 암호화 방식을 선택할 건가요? 먼저 각각의 키 교환 시나리오부터 한번 생각해 보아요.

 

1. 대칭 키 암호화: 사전에 키 교환 후 암호화에 사용

2. 비대칭 키 암호화: 앱에 퍼블릭키를 내장하거나 사용자 별 암호키를 사용.

 

둘 모두 괜찮을 것 같아요. TLS덕분에 키를 전송하는 것도 크게 걱정되지 않아요. 결과적으로 저는 더 빠르고 암호화 결과 비교적 작은 대칭키 암호를 선택했어요. 비대칭 키 암호화 결과는 QR 코드에 담기 너무 부담스럽기 때문이에요. 비대칭 키 암호화 중 하나인 RSA-2048는 2048 bits의 암호문을 산출해요. 다음 글에서 설명할 더 자세히 설명할 내용이지만, 꾀나 큰 편에 속해요.

 

AES

대칭키 암호화 알고리즘 종류는 정말 많아요. 결과적으로 저는 AES-GCM 또는 AES-CBC 알고리즘을 사용할 수 있도록 결정했어요. 제가 토큰을 설계할 때 많이 참고한 EMV는 Triple DES를 사용하지만 AES 알고리즘도 사용한대요.

Symmetric or ‘secret key’ algorithms require that the secret key used for the encryption process also be used in the decryption process. Therefore, the security of the encryption process depends entirely on protection of this secret key.
The EMV application supports the use of the Data Encryption Standard (DES) in its two-key Triple DES form. This is a symmetric algorithm which is widely used in the financial services industry today. DES belongs to the family of encryption algorithms called “block” ciphers because they process data in blocks As an option, the more recent AES algorithm is also supported. The MAC length is retained at 8 bytes for backwards compatibility.

... EMV 애플리케이션은 두 개의 키로 구성된 Triple-DES 형식의 데이터 암호화 표준(DES) 사용을 지원합니다. 이는 오늘날 금융 서비스 업계에서 널리 사용되는 대칭 알고리즘입니다. DES는 데이터를 블록 단위로 처리하기 때문에 “블록” 암호라고 하는 암호화 알고리즘 계열에 속합니다. 옵션으로 최신 AES 알고리즘도 지원됩니다. 이전 버전과의 호환성을 위해 MAC 길이는 8바이트로 유지됩니다. 
(EMV® Issuer and Application Security Guidelines - 5.3.1 Symmetric Algorithms)

 


대안

마지막으로 로컬 토큰을 구현하는 다른 대안을 비교해 볼게요.

 

시각을 이용하는 방법이 일반적인 동적 오프라인 인증 방법이라고 소개했어요. 또 다른 동적 오프라인 인증 방법에는 뭐가 있을까요? 첫 번째 방법은 토큰 자체가 뚫릴 수 없어 사실 시각보다 훨씬 강력한 방법이에요. 바로 미리 공유된 키/토큰을 사용하는 거예요. 은행 보안 카드와 2FA 복구 코드와 비슷한 개념이에요.

plex의 복구 코드 (support.plex.tv/articles/two-factor-authentication)

 

토큰을 완전한 난수(true random number)로 만들 수 있다는 장점이 있지만, 주기적으로 인터넷에 연결하여 새로운 토큰을 받아와야 한다는 단점이 있어요. 최악의 경우로 결제를 못하는 상황이 생길 수도 있어요. 하지만 토큰은 바코드로 나타낼 수 있을 정도로 짧아진다는 장점이 있어요.

 

또 다른 방법은 챌린지-응답(challenge-response)이에요. 이 방법은 MPM과 CPM이 통합된 방법이에요. 매장이 챌린지 코드가 담긴 QR을 제시하고, 사용자가 이를 바탕으로 토큰을 만드는 거예요. 결제 과정이 조금 더 추가되지만 토큰 수명관리가 쉬워지고 보안성을 높일 수 있는 방법이에요. 하지만 매장에서 동적 QR코드를 제시할 수 있는 스크린이 있어야 하고 결제 과정이 더 길어진다는 단점이 있어요. 그렇지만 이 방법 역시 짧은 토큰을 만들 수 있다는 장점이 있어요.

 

마지막 방법은 조금 주제를 벗어나긴 하지만, 그래도 인터넷 없이 결제를 할 수 있기 때문에 소개할게요. 지금 저희가 사용 중인 페이스사인 같은 생체 인증을 사용할 수도 있어요. QR 결제는 아니더라도 인터넷 없이 결제를 할 수 있죠.

 

후기

어떻게 QR 코드에 담을 수 있을 정도로 짧지만 빠르고 안전한 결제 토큰을 만들지 고민하는 건 정말 흥미로운 주제였어요. 많은 레퍼런스를 찾을 수도 없어서 조금 어려웠지만, 이런 사양은 누구나 마음만 먹으면 충분히 만들 수 있다고 생각해요. 제가 특별한 알고리즘을 개발한 게 아니고, 이미 있는 알고리즘을 적절히 조립한 것뿐이니까요. 이때까지 다른 서비스들이 굳이 만들지 않았던 이유는 우리나라에서 인터넷 접근이 어려운 지역은 거의 없고, 더 많은 사람들이 유용하게 쓸 수 있는 서비스를 개발하는 것이 자연스럽고 당연하기 때문이라고 생각해요.

 

로컬 토큰의 전체 사양은 local-generate-payment-token 레포지토리에서 확인하실 수 있어요. 토큰에 대한 궁금한 점은 자유롭게 이야기해 주세요. 그리고 보안 문제가 있다면 k@dimipay.io.로 알려주시면 정말 감사하겠습니다. 🙇‍♂️ 

 

읽어주셔서 고맙습니다:)

 

같이 보기