機械読取領域のチェックディジットがすべて合っているパスポートは、信頼できるように感じられます。計算は合い、バリデーターは5回 true を返し、オンボーディングのフローは先へ進みます。しかし、その true が何を意味するのかは正確に押さえておく価値があります。見た目よりもずっと小さな約束だからです。

この記事は、KYCやオンボーディングのフローを作る開発者向けの入門です。よく使われるスクリーニングのチェックを、MRZのチェックディジットで見抜けるもの、見抜けないもの、そしてそれぞれの穴をどの別のチェックが埋めるかに整理します。以下の領域はすべて、ICAO自身の見本である「Utopia」のAnna Maria Eriksson、またはこの記事のために作ったその変形です。実在の書類は登場しません。

これはパスポート・身分証OCR API、doc.cheapのブログです。以下の内容にdoc.cheapは必要ありません。

チェックディジットは何のためにあるか

MRZは、パスポートの写真ページの下部やIDカードの裏面にある、大文字、数字、フィラー < からなるブロックです。ICAO Doc 9303はこれにチェックディジットを与えています。旅券番号、生年月日、有効期限にそれぞれ1つ、パスポートの任意の個人番号に1つ、そして下の行の大部分にかかる複合チェックディジットです。

各チェックディジットは重み付きの和です。すべての文字を数値にし(0–9 はそのまま、A = 10 から Z = 35 まで、< = 0)、繰り返す重み 7、3、1 を掛け、その和を10で割った余りがチェックディジットになります。MRZチェックディジットの仕組みでは、貼り付けて使えるバリデーターとともに手順を説明しています。

チェックディジットは読み取りの誤りを見つけるために設計されました。不正を検出するためのものでは最初からなく、以下の内容はすべてそこから導かれます。

チェックディジットが見抜けること

1桁の誤り。 7、3、1はいずれも10と公約数を持たないので、フィールドのどの1桁を別の数字に変えても、10で割った余りは必ず変わります。3 を 8 と読んでも、5 を 6 と読んでも、フィールドのチェックディジットは合わなくなり、複合チェックディジットも合わなくなります。

隣り合う2文字の入れ替わりの大半。 隣り合う2文字が入れ替わると、和は2つの値の差に重みの差(4、2、6のいずれか)を掛けた分だけ変わります。それが10の倍数になるのは、2つの値の差が5の倍数のときだけです。そのため 98 を 89 と入力すれば検出されますが、16 を 61 と入力した場合や、05 を 50 と入力した場合はすり抜けます。

汚れ、反射、手入力。 ここがチェックディジットの本領です。1文字にかかる折り目、ラミネートの反射、領域を手で打ち直す人。不正なMRZデータの大半はこうした原因で生まれ、チェックディジットの不一致は、フィールドが誤って読まれたことを安く知らせるシグナルです。正しい対応は、却下ではなく撮り直しです。

計算では見えないところ

正直な誤りであっても、チェックディジットには穴があります。スクリーニングのフローはそれを知っておくべきです。

値が10、20、30だけ違う文字に誤読された英字。 見本の旅券番号 L898902C3 を例にとります。チェックディジットは 6 です。C(値12)を 2(値2)に置き換えると、和は 10 × 3 = 30 だけ減って316から286になり、チェックディジットは 6 のままです。同じ文字を同じ重みで含む複合チェックディジットも、やはり合格します。B と 1、C と 2 のような組は、何の兆候もなく入れ替わりえます。

どのチェックディジットも守らないフィールド。 氏名、発行国、国籍、性別はどのフィールドのチェックディジットの外にもあり、複合チェックディジットも国籍と性別を含みません。氏名の誤読は気づかれず、印字されたページと比べて初めてわかります。

まったく見抜けないこと

この節の内容はすべて、仕組み上MRZのチェックディジットを通過します。

領域の内部が整合した偽造書類。 アルゴリズムは公開されていて、20行のコードで書けます。偽造書類を作る人はチェックディジットを正しく計算します。チェックディジットの誤りは、どの読み取り装置もただで見つける唯一のミスだからです。合格した領域が示すのは、領域が正しく読まれたということだけです。書類が本物かどうかについては何も語りません。

実在の人物から写したデータ。 他人の実名、生年月日、旅券番号から作った領域は、データが本物なのでチェックディジットも正しくなります。カメラの前にいるのがその人かどうかは別の問題です。書類の顔写真との顔照合、ライブネスチェック、利用できる場合は発行機関の紛失・盗難リストとの照合で確かめます。

有効期限切れの書類。 有効期限 120415 はチェックディジットを通過しますが、それは2012年4月15日です。有効期限はチェックサムではなく日付のルールなので、今日の日付と比べてください。YYMMDDには世紀がないので、文脈から決める必要があります。方法はYYMMDD日付形式で説明しています。このサイトのMRZチェックディジット計算ツールは、過去の有効期限をチェックディジットの横に期限切れとして表示するので、2つの答えを並べて確認できます。

差し替えられた写真。 MRZには画像も画像のハッシュも含まれません。データページの写真を差し替えても、領域には何の影響もありません。

複製または改ざんされたチップ。 チップ付きのパスポートでは、データグループに発行国が署名しており、その署名の検証(パッシブ認証、ICAO Doc 9303 Part 11)によって、データが発行者から来たことがわかります。それにはNFCでの読み取りと発行者の証明書が必要です。ページの写真は、どれほど鮮明でもこれに答えられません。MRZが提供するのは、チップを開くためのアクセスキーだけです。

見落とされがちなチェック:領域とページの照合

書類はほとんどのことを2回書いています。1回はMRZに、もう1回は視覚読取領域(VIZ)、つまり人が読む印字されたページにです。この2つは1つの発行者が同時に作ったものなので、本物で傷のない書類なら一致します。

だからこそ、不一致はチェックディジットの不合格よりも興味深いのです。チェックディジットの不合格は、たいてい写真の質が悪いことを意味します。チェックディジットは合格しているのに、印字された姓、生年月日、旅券番号が違うことを言っているなら、どちらかが誤読されたか、印刷後に変えられたかです。いずれにしても、人が確認すべき書類です。

この照合は意図して行う必要があります。両方の領域を読み、印字された値を正規化し(日付は同じ形式に、氏名は素の大文字だけに)、フィールドごとに比較します。翻字も考慮してください。印字された Müller は、発行者によって領域では MUELLER にも MULLER にもなります。MRZフォーマットのページでは、各レイアウトがどのフィールドを持つか、つまりどのフィールドを比較できるかを示しています。

実用に耐えるスクリーニングの順序

  1. 形。 行数と長さでTD1、TD2、TD3が決まります。形が違えば読み取りの失敗です。
  2. チェックディジット。 不合格なら撮り直しで、却下ではありません。
  3. 領域とページ。 チェックディジットが合格していて不一致なら、人の確認に回します。
  4. 日付。 有効期限は今日と、生年月日は自社の年齢ルールと比べます。
  5. 本人性。 書類の顔写真に対する顔照合とライブネス。
  6. 真正性。 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の比較で公開されている料金を並べて確認できます。

**最後に質問です。**これらの穴のうち、あなたのオンボーディングのフローが実際に出会ったのはどれですか。下のコメント欄で教えてください。