概略
クレジットカード番号と判別したデータを見つけた際に、DLPやWAFなどのセキュリティ製品がアラートを発報したり、ECサイトなどで入力したクレジットカード番号が誤った番号であると警告を受けたりすることがあります。こうした仕組みはどのようにして、その数列がクレジットカード番号であること を判別しているのでしょうか。
クレジットカード番号の構成と判別方法についてまとめてみました。
本稿に記載した内容は、個人的な見解を示したものであり、筆者の所属する企業・団体の公式見解ではありません。
クレジットカード番号の構成要素
クレジットカード番号からはカードを発行した企業や団体が判別できるようにいくつかの構成要素が含まれています。例えば 3566 0020 2036 0505
という番号の場合、それぞれの数字の意味は次の表のようになります。
区分 | 例示の値 | 説明 |
---|---|---|
MII | 3 | 発行機関の種類 |
IIN (BIN) | 3566 | 発行機関(銀行等)の識別番号 |
Account No. | 00202036050 | 利用者に固有な番号 |
Check Digit | 5 | 番号チェック用の整合性番号 |
カードの発行会社などを判別する桁が続いたあとに、利用者を識別するための番号が続きます。最後の1桁は、カード番号の入力間違いなどを検出するためのチェックデジットとなっており、クレジットカードでは Luhnアルゴリズムという方式を使って、誤り検出が行われます。
チェックデジットに使われている Luhnアルゴリズムは、IBMの Hans Peter Luhn氏が開発した番号検証方式で、mod10アルゴリズムとも呼ばれます。このチェックデジットを元に計算することで、実際にクレジットカードを使って与信や決済処理を行う前に、番号がルールに則っているかを確認して、ユーザーにエラー出力することもできます。
余談ですが日本のマイナンバーも誤り検出のためのチェックデジットが用意されており省令1で定められています。
Luhnアルゴリズムの計算
仮のクレジットカード番号 3566 0020 2036 0505
を使って、Luhnアルゴリズムの計算方法を説明します。
計算は次のステップで行います。
- カード番号を右から順番に番号に番号をつけて偶数番目の数字を2倍する
- 前項のすべての結果を合計する
- 合計値が10の倍数であるか否かを確認する
ステップ1: 右から順番に番号に番号をつけて偶数番目の数字を2倍する
見やすくするために空白を設けていましたが、計算のときには省きますので、上記の番号は 3566002020360505
になります。
まず、右から順に数えて偶数番目の数字を2倍します。ただし、2倍して9より大きくなったら、その数字の各桁の合計にします。つまり 2倍して 10 になった場合は 1 + 0 = 1 となり、2倍して 12 になった場合は 1 + 2 = 3 とします。
これに倣って、先程の番号を計算してみると、次のようになります。
桁位置(右から) | 元の数字 | 操作内容 | 結果 |
---|---|---|---|
1 (最右) | 5 | そのまま | 5 |
2 | 0 | 0 × 2 | 0 |
3 | 5 | そのまま | 5 |
4 | 0 | 0 × 2 | 0 |
5 | 6 | そのまま | 6 |
6 | 3 | 3 × 2 = 6 | 6 |
7 | 0 | そのまま | 0 |
8 | 2 | 2 × 2 = 4 | 4 |
9 | 0 | そのまま | 0 |
10 | 2 | 2 × 2 = 4 | 4 |
11 | 0 | そのまま | 0 |
12 | 0 | 0 × 2 | 0 |
13 | 6 | そのまま | 6 |
14 | 6 | 6 × 2 = 12 → 1+2 | 3 |
15 | 5 | そのまま | 5 |
16 (最左) | 3 | 3 × 2 = 6 | 6 |
ステップ2: すべての結果を合計する
先ほどの結果をすべて足し合わせると、50になります。
5 + 0 + 5 + 0 + 6 + 6 + 0 + 4 + 0 + 4 + 0 + 0 + 6 + 3 + 5 + 6 = 50
ステップ3: 合計が10の倍数であるかを確認する
正しいクレジットカード番号は ステップ2の計算結果が 10の倍数 になります。先ほどの計算結果は 50ですので3566 0020 2036 0505
は正しい番号であることが確認できました。
テスト用のクレジットカード暗号
クレジットカード番号は秘匿すべき情報のひとつです。そのため、例示やテストのための専用の番号が発行されています。それらは実際の決済には使えないため、安心して例示ができます。
オンライン決済サービスstripeのドキュメントなどでテスト用クレジットカード番号の一覧を確認することができます。
Luhnアルゴリズムの実装
ここまで説明した内容をBash関数にしてみます。この関数はステップ1~3の流れに従ったチェックを行って正しい番号であれば真を、そうでなければ偽を返します。
luhn_check() {
local num="$1"
local sum=0
local even=0
local i digit temp
for (( i=${#num}-1; i>=0; i-- )); do
digit=${num:i:1}
if (( even )); then
temp=$((digit * 2))
(( temp > 9 )) && temp=$((temp - 9))
sum=$((sum + temp))
else
sum=$((sum + digit))
fi
even=$((1 - even))
done
(( sum % 10 == 0 )) && return 0 || return 1
}
動作テスト
動作テストをしてみます。まずは正しい番号を入力してみます。すると真が返ります。
$ luhn_check 3056930009020004 ; echo $?
0
$ luhn_check 4242424242424242 ; echo $?
0
番号の誤りテスト用の番号を入力すると、偽が返ります。
$ luhn_check 4242424242424241 ; echo $?
1
どうやら、正しく判別できているようです。
発行者識別番号(IIN)
クレジットカードなどの決済用カードの番号は、ISO/IEC7812-1で規定された8桁2の発行者識別番号を確認することで、どの団体が発行したものかがわかります。これは IIN(Issuer Identification Number)または BIN(Bank Identification Number)と呼ばれます。IINはAmerican Bankers Association(ABA)が管理しており、クレジットカードの場合は、いわゆる国際ブランドの判別ができます。
国際ブランド | IIN(BIN) | 桁数 |
---|---|---|
American Express | 先頭が 34 または 37 から始まる | 15 |
Diners Club Inernational | 先頭が 36 から始まる | 14 |
Visa | 先頭が 4から始まる | 13、16、19 |
MasterCard | 先頭が 51~55 または 2221~2720 から始まる | 16 |
JBC | 先頭が 3528~3589 から始まる | 16 |
これらの割り当て範囲は、今後追加されることもありますので、注意が必要です。2017年にはMasterCardがBIN割り当て範囲を追加しています。
割り当てられている IINは bincodes.comなどで確認することができます。
国際ブランド判別の実装
IINを使って、主要な国際ブランドを判別するBash関数を実装してみます。
カード番号の先頭 1桁、2桁、4桁のローカル変数を用意してCASE文で分けていますが、単純にIF文で実装しても問題ありません。せっかくですので、番号の桁数もチェックしています。条件に合致する場合は国際ブランド名を出力します。
get_brand() {
local num="$1"
local len=${#num}
local prefix1=${num:0:1}
local prefix2=${num:0:2}
local prefix4=${num:0:4}
case 1 in
$(( (prefix2 == 34 || prefix2 == 37) && len == 15 )) ) echo "American Express" ;;
$(( prefix2 == 36 && len == 14 )) ) echo "Diners Club" ;;
$(( prefix1 == 4 && (len == 13 || len == 16 || len == 19) )) ) echo "Visa" ;;
$(( prefix2 >= 51 && prefix2 <= 55 && len == 16 )) ) echo "MasterCard" ;;
$(( prefix4 >= 2221 && prefix4 <= 2720 && len == 16 )) ) echo "MasterCard" ;;
$(( prefix4 >= 3528 && prefix4 <= 3589 && len == 16 )) ) echo "JCB" ;;
*) return 1 ;;
esac
}
動作テスト
テスト用クレジットカード番号を使って動作テストをしてみます。
$ get_brand 378282246310005
American Express
$ get_brand 36227206271667
Diners Club
$ get_brand 4000056655665556
Visa
$ get_brand 2223003122003222
MasterCard
$ get_brand 3566002020360505
JCB
今回設定した国際ブランドは判別できているようです。
国際ブランドの判別について
本稿で挙げた国際ブランドの IINは一部を示したものであり、上記のコードを使ってすべてのクレジットカードブランドを判別できるものではありません。例えば Discover Cardの判別は含まれていませんし、米国で発行されたDiners ClubのIINも先ほど示したものとは異なります。
実際にクレジットカード番号の判別を行う場合には正確な識別条件を改めて確認したうえで、十分なテストを行うべきです。
最後に
クレジットカード番号は、MIIやIINなどの識別子と利用者固有番号、そしてLuhnアルゴリズムによるチェックデジットで構成されており、誤入力を検出する仕組みを備えています。この仕組みを活用することで、決済や与信の処理を行わずにクレジットカード番号のチェックのみ行えます。これは不適切なカード情報の漏洩やユーザーの入力ミスの発見に役立ちます。
また、こうした誤り検出の考え方は、クレジットカードだけでなく何等かの識別子(例えば伝票番号など)を独自に実装するときにも参考になるでしょう。
脚注
-
平成二十六年総務省令第八十五号 行政手続における特定の個人を識別するための番号の利用等に関する法律に規定する個人番号、個人番号カード、特定個人情報の提供等に関する命令 ↩
-
昔は 6桁でしたが 2022年4月以降は 8桁の IINが義務付けられています。VISA: 8桁のBINへの移行準備 ↩