ID驗證系列|信用卡卡號驗證

趁著演講者在講些五四三的時候,來補我的不務正業系列,這次來看看信用卡卡號驗證。

信用卡 信用卡(圖片來源: shutterstock

編號規則

信用卡的編碼規則,相較之下稍微稍微複雜點。根據 ISO/IEC 7812 標準,信用卡一般在 13~19 碼,但 Mastercard 旗下似乎有 12 碼簽帳金融卡(Debit Card)。而在臺灣比較常見的長度是 16 碼,因此下面在說明多以 16 碼來說明,但不管幾碼編碼規則其實都是相同的。


長達 16 碼的信用卡卡號,其實是由 3 部分所組成的,以一張卡號為 4311-4656-0640-6131 的 Visa 信用卡為例:

發卡機構代碼 個人帳戶號碼 檢核碼
4 3 1 1 4 6 5 6 0 6 4 0 6 1 3 1


  • 發卡機構代碼(Issuer Identification Numbers,IIN)
    IIN 有時被稱為銀行識別號碼(Bank Identification Number,BIN),這是用來辨別卡片的主要資訊,由 行業標識碼(Major Industry Identifier,MII)為首所組成的 6 碼數字。

    因此可以從左起第 1 碼數字能看出發卡組織的端倪。一般來說,5 開頭是萬事達卡、4 是 Visa為、3 是美國運通與 JCB、62 是中國銀聯。不過這些編碼似乎會因為商業聯盟與組織營運,如果要查確切的對應,可能得去查查美國國家標準協會(American National Standards Institute,ANSI) 的 IIN 資料庫。

  • 帳戶號碼(Primary Account Number, PAN)
    中間位數由發卡單位自定義,一般由 6~12 碼數字所組成。其意義並沒有硬性規定,可能會包含分行之類的訊息,但也有可能只是流水號。

  • 檢核碼(Checking Number)
    顧名思義就是用檢查這組信用卡的卡號真偽的一個數字,由 Luhn 演算法計算所得出。


在找資料的時候發現,有些文章的檢查規則是照著 Luhn 演算法的生成規則一步步計算的,但我想檢查不是生成,有些動作可以適度的化簡:

  1. 設定權重
    由右到左為每個數字賦予一個權重,其中奇數位的權重是 1、偶數位的權重是 2:

    idx $n_{15}$ $n_{14}$ $n_{13}$ $n_{12}$ $n_{11}$ $n_{10}$ $n_9$ $n_8$ $n_7$ $n_6$ $n_5$ $n_4$ $n_3$ $n_2$ $n_1$ $n_0$
    卡號 4 3 1 1 4 6 5 6 0 6 4 0 6 1 3 1
    權重 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1
  2. 乘積計算
    將卡號每碼與其對應的權重一一相乘,若乘積大於 10 則取兩位數之和。

    idx $m_{15}$ $m_{14}$ $m_{13}$ $m_{12}$ $m_{11}$ $m_{10}$ $m_9$ $m_8$ $m_7$ $m_6$ $m_5$ $m_4$ $m_3$ $m_2$ $m_1$ $m_0$
    乘積 8 3 2 1 8 6 10 6 0 6 8 0 12 1 6 1
    取和 8 3 2 1 8 6 1 6 0 6 8 0 3 1 6 1
  3. 10的倍數
    將取和完成的數值進行加總,若總和為 10 的倍數,則為有效卡號:

    \[(m_{0}+m_{1}+m_{2}+m_{3}+m_{4}+m_{5}+m_{6}+m_{7}+m_{8}+m_{9}+m_{10}+m_{11}+m_{12}+m_{13}+m_{14}+m_{15})\%10 = 0\]

    將上面的例子套回計算式後:

    \[\begin{aligned} &(1+6+1+3+0+8+6+0+6+1+6+8+1+2+3+8)\%10 \\ &= 60\%10\\ &= 0 \end{aligned}\]

    餘數為 0,表為有效卡號。

程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function verifyId(id) {
    id =  id.replace(/-/g,"").trim();
    let len = id.length;

    if(len<12 || len >19){
        return false;
    }

    let revId = id.split("").reverse();
     let checkSum = revId.reduce(function(prev, curr, idx){
         curr  = parseInt(curr);
         let w = (idx+1) % 2 == 0 ? 2: 1;
         let res =  curr * w 
         if(res>=10){
             res = parseInt(res/10) + res%10 ;
         }
         return prev + res;
     }, 0);
    return checkSum % 10 == 0
}

console.log(verifyId("4311-4656-0640-6131"));

這組程式碼能加 log 的地方也只有長度檢查的部分,所以就不再寫一版有 log 的了。是說原本想寫 Clojure,不過 Clojure 還不是很熟練,邊寫還要邊查語法,有點太花時間了,改天再來補 Clojure 的程式碼好了。

參考資料

  1. 協同撰寫。發卡行識別碼。檢自 維基百科 (2021-02-04)。
  2. 協同撰寫。ISO/IEC 7812。檢自 維基百科 (2021-02-04)。
  3. Claire (2019-01-10)。卡號與安全機制篇。檢自 愛承諾金融網 (2021-02-04)。
  4. 協同撰寫。Luhn算法。檢自 維基百科 (2021-02-04)。
  5. Roger Jang 。10-4 常用資料規則。檢自 JavaScript 程式設計與應用:用於網頁用戶端 (2021-02-04)。
  6. 支付圈 (2017-05-02)。銀行卡號編碼規則。檢自 每日頭條 (2021-02-04)。
  7. 溫子豪 (2016-08-22)。解開信用卡卡號秘密 檢查碼輕鬆算防偽卡。檢自 卡優新聞網 (2021-02-04)。

更新紀錄

最後更新日期:2021-03-07
  • 2021-03-07 發布
  • 2021-02-04 完稿
  • 2021-02-04 起稿