Should I use the CreditCardAttribute to validate credit card numbers?

Jeremy Cook picture Jeremy Cook · Apr 27, 2015 · Viewed 8.2k times · Source

Should I use Microsoft's CreditCardAttribute to validate credit card numbers like so?

[Required, CreditCard]
public string CreditCardNumber { get; set; }

Or should I let the payment gateway handle it, or do something else? I ask this after discovering some customers have been unable to submit payment with their credit card information. Fortunately, I was able to work with one of these customers, and found that their Visa card was processed without a problem after removing the CreditCardAttribute.

In part, this question is rhetorical, but I would like to benefit from other developer's thoughts and experiences, and make other developers aware of the risks of using the CreditCardAttribute by asking the question.

Answer

Jevgeni Geurtsen picture Jevgeni Geurtsen · Apr 27, 2015

I think the best way to find this out is to simply test it:

using System;
using System.Linq;
using System.Text;
using System.IO;

namespace SO
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] cards = new string[] {
                //http://www.paypalobjects.com/en_US/vhelp/paypalmanager_help/credit_card_numbers.htm
                "378282246310005",  // American Express
                "4012888888881881", // Visa
                "6011111111111117", // Discover
                "4222222222222", // Visa
                "76009244561", // Dankort (PBS)
                "5019717010103742", // Dakort (PBS) 
                "6331101999990016", // Switch/Solo (Paymentech)
                "30569309025904", // Diners Club 
                //http://www.getcreditcardnumbers.com/
                "5147004213414803", // Mastercard
                "6011491706918120", // Discover
                "379616680189541", // American Express
                "4916111026621797", // Visa
            };

            foreach (string card in cards)
            {
                Console.WriteLine(IsValid(card));
            }

            Console.ReadLine();
        }

        public static bool IsValid(object value)
        {
            if (value == null)
            {
                return true;
            }

            string ccValue = value as string;
            if (ccValue == null)
            {
                return false;
            }
            ccValue = ccValue.Replace("-", "");
            ccValue = ccValue.Replace(" ", "");

            int checksum = 0;
            bool evenDigit = false;

            // http://www.beachnet.com/~hstiles/cardtype.html
            foreach (char digit in ccValue.Reverse())
            {
                if (digit < '0' || digit > '9')
                {
                    return false;
                }

                int digitValue = (digit - '0') * (evenDigit ? 2 : 1);
                evenDigit = !evenDigit;

                while (digitValue > 0)
                {
                    checksum += digitValue % 10;
                    digitValue /= 10;
                }
            }

            return (checksum % 10) == 0;
        }
    }
}

The IsValid method is from the original C# CreditCardAttribute class. 1 out of the 12 numbers failed:

        True
        True
        True
        True
        False //"76009244561", // Dankort (PBS)
        True
        True
        True
        True
        True
        True
        True

So, should you use it? No, obviously it doesn't detect all numbers. Although you can take their code and improve it!