Pages

Pages

Apr 30, 2009

あなたのクレジットカード番号に潜む規則性


びっくりした!クレジットカード番号はランダムに見えて実は一定の規則に従っているということを知った。


Djangoのソースを読んでいたら、オンラインストアなどを作る人のために、ユーザが入力したクレジットカード番号が正しいものかどうかを確認する方法がのっていた。




  1. クレジットカード番号の後ろから数えて*1奇数桁だけを合計する。

  2. クレジットカード番号の後ろから数えて偶数桁を2倍して合計する。2倍して10以上になるときは9を引く。

  3. 1と2の数字を合計する


正しいカード番号ならこの合計が10で割り切れる。



試しに自分の持ってるカードでやってみたけど、確かにこのルールに従った番号がついてる。オンライン決済するようなWebアプリをつくるひとは、あらかじめ番号をチェックしてあからさまな偽カード番号については、カード会社に照会しないようにするといいみたい。


一瞬合コン向けのゲームとかに応用(「もし10で割り切れたら俺たち運命!」とか)できるのではと考えたが、こんな面倒な計算を酒の席でできるはずがないと我に返った。俺まだ常識人!



プログラムでやるとこうなる。


こんな面倒な作業を人間がやるはずはない。チェック作業をするperlやjavaなどの言語向けライブラリがあるので"luhn"とか"mod 10"でググるとよい。Pythonでやるとこうなる。



pythonクックブックにのっていた方法

pythonクックブックという本には「3.15 クレジットカードのチェックサム」という節でこんな方法が掲載されている。



#!/usr/bin/env python
card_number = "123456789" # ここに番号いれて
sum = 0
num_digits = len(card_number)
oddeven = num_digits & 1 # num_digitsが偶数なら0、奇数なら1
for count in range(num_digits):
digit = int(card_number[count])
if not (( count & 1 ) ^ oddeven):
digit = digit*2
if digit > 9:
digit = digit - 9
sum = sum + digit
print "num: %s digit: %s sum: %s" % (count, digit, sum)
print sum
if sum % 10 == 0 :
print "The card number is valid."
else :
print "Error: The card number is invalid."


djangoのcheckdigits.py

Python用のフレームワークDjango*2のutilsディレクトリの中にはこんな関数が用意されている。



LUHN_ODD_LOOKUP = (0, 2, 4, 6, 8, 1, 3, 5, 7, 9) # sum_of_digits(index * 2)
def luhn(candidate):
if not isinstance(candidate, basestring):
candidate = str(candidate)
try:
evens = sum([int(c) for c in candidate[-1::-2]]) #文字列の後ろから
odds = sum([LUHN_ODD_LOOKUP[int(c)] for c in candidate[-2::-2]])
return ((evens + odds) % 10 == 0)
except ValueError: # Raised if an int conversion fails
return False

あとは、



>>import checkdigits
>>checkdigits.luhn(12345678901234)

などとするとチェックできる。


上の例(Pythonクックブック)の方が読みやすいけど、これって数字を頭から足し算してる。大丈夫なのかなぁ。。。


下の例はMystring[-1::-2]という見慣れない書き方が気になったが、これは文字列の一番後ろの文字から-2番目の文字を順に取り出すという操作らしい。


なに言ってるか分からないですよね。すいません。実行例を書いておくので体で理解してください。



>>> d=1234567890
>>> str(d)[-1::-2]
'08642'
>>> str(d)[-2::-2]
'97531'


他にもクレジットカードには沢山の規則性があって、裏を返せば、インターネット上に転がっている無意味に見える数字の羅列の中からクレジットカード番号だけを抜き出す事は簡単だということだ。


参考:


JANは、奇数桁に3、偶数桁に1を掛け、足し方は一括のモジュラス10なので「モジュラス10 ウエイト3-1(一括)」と表現される。


クレジットカード番号は、奇数桁に1、偶数桁に2を掛け、足し方は分割のモジュラス10なので「モジュラス10 ウエイト1-2(分割)」と表現される。但しこの呼び方はあまり使われておらず、LUHN Formulaの名で呼ばれている。


ISBNは、末尾(サム桁)に1、先頭桁に10を掛け、足し方は一括のモジュラス11なので「モジュラス11 ウエイト1~10(一括)」と表現される。


チェックディジット - 通信用語の基礎知識





Haskell だと、こんな感じ?


クレジットカードのチェックディジット - すばらしき functional programming - haskell




クレジットカードと言えば


その昔ドイツのワールドカップの会場で「公式スポンサーであるマスターカードしか使えない」と言われて焦った事を思い出した。


f:id:kkomiyama:20060710040444j:image


クレジットマスター!? 2009/07/07追記


クレジットマスターなるプログラムが出回っているらしい。



16けたのクレジットカード番号のうち複数のけたに、決まった数字を足し引きしていくと、特定の回数で元の番号に戻る。その過程で出てきた番号は、他人が使用しているものに該当する可能性があるという。カード番号の並びの規則性を悪用した方法。こうした計算を瞬時に行う自動ソフトも出回っているとされる。カード業界の関係者などによると、10年ほど前から被害が確認されているが、具体的な防止策は見つかっていない。<http://www.itmedia.co.jp/news/articles/0907/07/news019.html>





*1:前から数えるとアメックスのように奇数桁のカードがうまくいかなくなる


*2:うちで使ってるのは1.0.2