기계 판독 영역의 검증 숫자가 모두 통과한 여권은 믿을 만해 보입니다. 계산이 맞고, 검증기가 true를 다섯 번 돌려주고, 온보딩 흐름은 다음 단계로 넘어갑니다. 하지만 그 true가 무엇을 뜻하는지는 정확히 짚어 둘 필요가 있습니다. 보이는 것보다 훨씬 작은 약속이기 때문입니다.
이 입문서는 KYC와 온보딩 흐름을 만드는 개발자를 위한 글입니다. 흔히 쓰는 스크리닝 검사를 MRZ 검증 숫자가 잡아내는 것, 잡아내지 못하는 것, 그리고 각각의 빈틈을 어떤 다른 검사가 메우는지로 나눕니다. 아래의 영역은 모두 ICAO 자체의 견본인 "Utopia"의 Anna Maria Eriksson이거나, 이 글을 위해 만든 그 변형입니다. 실제 문서는 등장하지 않습니다.
이곳은 여권 및 신분증 OCR API doc.cheap의 블로그입니다. 아래 내용에는 doc.cheap이 필요하지 않습니다.
검증 숫자는 무엇을 위한 것인가
MRZ는 여권 사진 페이지 아래쪽이나 신분증 뒷면에 있는, 대문자와 숫자와 필러 <로 이루어진 블록입니다. ICAO Doc 9303은 여기에 검증 숫자를 둡니다. 문서 번호, 생년월일, 만료일에 하나씩, 여권의 선택적 개인 번호에 하나, 그리고 아래 행의 대부분을 덮는 복합 검증 숫자가 있습니다.
각 검증 숫자는 가중합입니다. 모든 문자를 숫자로 바꾸고(0–9는 그대로, A = 10부터 Z = 35까지, < = 0), 반복되는 가중치 7, 3, 1을 곱한 뒤, 합을 10으로 나눈 나머지가 검증 숫자가 됩니다. MRZ 검증 숫자의 원리에서 붙여 넣어 쓸 수 있는 검증기와 함께 과정을 설명합니다.
검증 숫자는 읽기 오류를 잡도록 설계되었습니다. 처음부터 사기를 탐지하려는 것이 아니었고, 아래 내용은 모두 여기서 나옵니다.
검증 숫자가 잡아내는 것
숫자 하나의 오류. 7, 3, 1은 모두 10과 공약수가 없으므로, 필드의 어느 한 자리를 다른 숫자로 바꾸면 합을 10으로 나눈 나머지가 반드시 달라집니다. 3을 8로, 5를 6으로 읽으면 필드 검증 숫자가 맞지 않게 되고, 복합 검증 숫자도 마찬가지입니다.
이웃한 두 문자가 자리를 바꾼 경우 대부분. 이웃한 두 문자가 자리를 바꾸면, 합은 두 값의 차이에 가중치의 차이(4, 2 또는 6)를 곱한 만큼 바뀝니다. 그것이 10의 배수가 되는 것은 두 값의 차이가 5의 배수일 때뿐입니다. 그래서 98을 89로 입력하면 잡히지만, 16을 61로, 05를 50으로 입력하면 그냥 지나갑니다.
훼손, 반사, 재입력. 검증 숫자가 제값을 하는 곳이 여기입니다. 한 글자를 가로지르는 접힌 자국, 라미네이트의 반사, 영역을 손으로 다시 입력하는 사람. 잘못된 MRZ 데이터의 대부분은 이런 원인에서 생기며, 검증 숫자 실패는 필드가 잘못 읽혔다는 값싼 신호입니다. 올바른 대응은 거절이 아니라 다시 촬영하는 것입니다.
계산이 보지 못하는 곳
정직한 오류에서도 검증 숫자에는 빈틈이 있고, 스크리닝 흐름은 이를 알고 있어야 합니다.
값이 10, 20, 30만큼 차이 나는 문자로 잘못 읽힌 글자. 견본 문서 번호 L898902C3을 보겠습니다. 검증 숫자는 6입니다. C(값 12)를 2(값 2)로 바꾸면 합이 10 × 3 = 30만큼 줄어 316에서 286이 되고, 검증 숫자는 여전히 6입니다. 같은 문자를 같은 가중치로 덮는 복합 검증 숫자도 그대로 통과합니다. B와 1, C와 2 같은 쌍은 아무 신호 없이 서로 바뀔 수 있습니다.
어떤 검증 숫자도 지키지 않는 필드. 이름, 발급 국가, 국적, 성별은 모든 필드 검증 숫자 바깥에 있고, 복합 검증 숫자도 국적과 성별은 건너뜁니다. 이름을 잘못 읽어도 아무 신호가 없으며, 인쇄된 페이지와 비교해야만 드러납니다.
아예 잡아낼 수 없는 것
이 절의 모든 경우는 구조상 MRZ 검증 숫자를 통과합니다.
영역 내부가 일관된 위조 문서. 알고리즘은 공개되어 있고 코드 스무 줄이면 됩니다. 위조 문서를 만드는 사람은 검증 숫자를 정확히 계산합니다. 틀린 검증 숫자는 모든 판독기가 공짜로 잡아내는 유일한 실수이기 때문입니다. 통과한 영역은 영역이 올바르게 읽혔다는 뜻일 뿐, 문서가 진본인지에 대해서는 아무것도 말해 주지 않습니다.
실제 인물에게서 베낀 데이터. 다른 사람의 실명, 생년월일, 문서 번호로 만든 영역은 데이터가 진짜이므로 검증 숫자도 유효합니다. 카메라 앞의 사람이 그 사람인지는 다른 문제입니다. 문서 사진과의 얼굴 대조, 라이브니스 검사, 접근할 수 있다면 발급 기관의 분실·도난 목록 조회로 확인합니다.
만료된 문서. 만료일 120415는 검증 숫자를 통과하지만, 그날은 2012년 4월 15일입니다. 만료는 체크섬이 아니라 날짜에 관한 규칙이므로, 오늘 날짜와 비교하세요. YYMMDD에는 세기가 없으니 문맥으로 정해야 합니다. 방법은 YYMMDD 날짜 형식에서 다룹니다. 이 사이트의 MRZ 검증 숫자 계산기는 지난 만료일을 검증 숫자 옆에 만료됨으로 표시하므로, 두 답을 나란히 볼 수 있습니다.
바꿔 붙인 사진. MRZ에는 사진도, 사진의 해시도 없습니다. 데이터 페이지의 사진을 바꿔도 영역은 그대로입니다.
복제되거나 변조된 칩. 칩이 있는 여권에서는 데이터 그룹에 발급 국가가 서명하며, 그 서명을 검증해야(수동 인증, ICAO Doc 9303 Part 11) 데이터가 발급 기관에서 왔다는 것을 알 수 있습니다. 여기에는 NFC 판독과 발급 기관의 인증서가 필요합니다. 페이지 사진은 아무리 선명해도 이 질문에 답할 수 없습니다. MRZ는 칩을 여는 데 쓰는 접근 키만 제공합니다.
흔히 건너뛰는 검사: 영역과 페이지 대조
문서는 대부분의 내용을 두 번 적습니다. 한 번은 MRZ에, 한 번은 사람이 읽는 인쇄 페이지인 육안 판독 영역(VIZ)에 적습니다. 둘은 한 발급 기관이 함께 만든 것이므로, 진본이고 손상되지 않은 문서라면 서로 일치합니다.
그래서 불일치는 검증 숫자 실패보다 더 눈여겨볼 만합니다. 검증 숫자 실패는 대개 사진이 나쁘다는 뜻입니다. 검증 숫자는 통과했는데 인쇄된 성, 생년월일, 문서 번호가 다른 값을 말한다면, 한쪽이 잘못 읽혔거나 인쇄 후에 바뀐 것입니다. 어느 쪽이든 사람이 직접 봐야 할 문서입니다.
이 대조는 일부러 해야 합니다. 두 영역을 모두 읽고, 인쇄된 값을 정규화한 다음(날짜는 같은 형식으로, 이름은 순수한 대문자로), 필드별로 비교합니다. 음역도 감안하세요. 인쇄된 Müller는 발급 기관에 따라 영역에서 MUELLER일 수도, MULLER일 수도 있습니다. MRZ 형식 페이지에서 각 레이아웃이 어떤 필드를 담는지, 즉 어떤 필드를 비교할 수 있는지 볼 수 있습니다.
믿고 쓸 수 있는 스크리닝 순서
- 형태. 행 수와 길이로 TD1, TD2, TD3이 정해집니다. 형태가 틀리면 잘못 읽은 것입니다.
- 검증 숫자. 실패하면 다시 촬영하고, 거절하지 않습니다.
- 영역과 페이지. 검증 숫자가 통과했는데 불일치하면 사람에게 넘깁니다.
- 날짜. 만료일은 오늘과, 생년월일은 자사의 연령 규칙과 비교합니다.
- 신원. 문서 사진과의 얼굴 대조와 라이브니스 검사.
- 진위. NFC로 칩을 검증하거나, 그 일을 위해 만든 서비스로 물리적 보안 요소를 확인합니다.
1단계부터 4단계까지는 비용이 적고 어떤 이미지에서든 실행됩니다. 5단계와 6단계는 별도의 제품이며, MRZ 계산을 아무리 더해도 대신할 수 없습니다.
doc.cheap의 역할
doc.cheap 여권 OCR API는 1단계부터 4단계를 다루고, 나머지에 대해서는 정직하게 보고합니다. 응답에는 mrz.status가 있으며 값은 passed, failed, absent 중 하나입니다. failed일 때 mrz.reason이 무엇이 맞지 않았는지 알려 줍니다. 검증 숫자(Check digit failed for: document number)이거나 인쇄 페이지와의 불일치(MRZ does not match the visual zone for: surname)입니다. 기본적으로 두 영역을 모두 읽고 비교하기 때문입니다. 영역 자체는 읽은 그대로 mrz.lines와 mrz.text에 돌아오므로, 직접 작성한 코드로 검증 숫자를 다시 계산할 수 있습니다. 4단계는 document.expiry_date, document.is_expired, document.days_remaining이 답합니다.
이것은 인식 서비스이지 검증 서비스가 아닙니다. authenticity 블록은 통과를 암시하는 대신 not_checked를 돌려주며, 사진과 칩 검사는 그 일을 위해 만든 도구에 맡깁니다. 코드 없이 영역을 시험해 보려면 MRZ 검증 숫자 계산기에 붙여 넣으세요. 브라우저에서 실행되며, 계산한 각 검증 숫자를 인쇄된 것 옆에 보여 줍니다. 호스팅 서비스를 고르는 중이라면 여권 OCR API 비교에서 공개된 가격을 나란히 볼 수 있습니다.
마지막으로 질문 하나: 이 빈틈들 가운데 여러분의 온보딩 흐름이 실제로 마주친 것은 무엇인가요? 아래 댓글로 알려 주세요.