If you use Amazon or Flipkart e-commerce websites, you might have noticed that they do not store payment information in plain text. Instead, they mask the cc numbers and display only the last four digits.
Many data protection regulations, such as the Payment Card Industry Data Security Standard (PCI DSS), necessitate businesses to mask or truncate credit card numbers when displaying or storing them. Therefore, you as a “developer” should create a mechanism that does not store credit card information naked; instead, it will store it as **** **** **** 9215 or **** **** **** ****.
Here is the figure that describes masked and unmasked credit card numbers:
Here are three ways you can use to mask your credit card number in Python:
- Using a secure way with a regex approach that includes input validation
- Using only the regex method
- Using string slicing
Method 1: Secure method using regex with input validation
We will create a custom function that removes any non-digit characters, validates the credit card number length, masks all the numbers except the last four digits, and reformats the masked numbers in the original order.
import re def mask_credit_card_secure(card_number): # Removing any non-digit characters cleaned_number = re.sub(r'\D', '', card_number) # Validating the card number (simple check for length) if not 13 <= len(cleaned_number) <= 19: raise ValueError("Invalid credit card number length") # Masking all numbers except last 4 digits masked = '*' * (len(cleaned_number) - 4) + cleaned_number[-4:] # Reformatting the masked number to match original format mask_char_count = 0 result = '' for char in card_number: if char.isdigit(): result += masked[mask_char_count] mask_char_count += 1 else: result += char return result # Example numbers card_numbers = [ "1244567790193456", "1244-5677-9019-3456", "1244 5677 9019 3456", "12445677901934567890" # Invalid length for testing secure method ] print("Secure method using regex with input validation: ") for card in card_numbers: try: print(f"Original: {card}") print(f"Masked: {mask_credit_card_secure(card)}\n") except Exception as e: print(f"Error: {str(e)}\n")
You can see that it will handle any valid user input that contains spaces or dashes and return the desired output.
Here, we handled various input types, including numbers without spaces, with spaces, with hyphens(-), and invalid cc numbers.
The only disadvantage of this approach is that it requires deep knowledge of regular expressions and might become slower due to performing so many operations. However, if security is your priority, I highly recommend using this method.
OutputSecure method using regex with input validation: Original: 1244567790193456 Masked: ************3456 Original: 1244-5677-9019-3456 Masked: ****-****-****-3456 Original: 1244 5677 9019 3456 Masked: **** **** **** 3456 Original: 12445677901934567890 Error: Invalid credit card number length
Method 2: Simple Regular expression
We already saw the regular expression approach above, but it mixed with other operations. In this approach, we just deal with credit card numbers that might include spaces or dashes.
import re # Finding numbers and replacing each number with "*" using regex def mask_credit_card(card_number): return re.sub(r'\d(?=\d{4})', '*', card_number) # Example numbers card_numbers = ["1244567790193456"] print("Simple Regular Expression method: ") for card in card_numbers: try: print(f"Original: {card}") print(f"Masked: {mask_credit_card(card)}\n") except Exception as e: print(f"Error: {str(e)}\n")Output
Simple Regular expression method: Original: 1244567790193456 Masked: ************3456
In this method, we simply find all the cc numbers using a regular expression pattern and replace those numbers with “*” except the last four digits.
You still require extensive knowledge of “Regular Expressions,” which is a tricky business. Furthermore, this method does not work with spaces or dashes. Use the first approach for that.
If you want to create a code that handles spaces as well as dashes, check the code below:
import re def mask_credit_card(card_number): # At the start, remove any non-digit characters digits_only = re.sub(r'\D', '', card_number) # In addition, mask all but except last 4 digits masked_digits = '*' * (len(digits_only) - 4) + digits_only[-4:] # At last, replace the digits in the original string, # keeping the formatting masked_number = '' digit_index = 0 for char in card_number: if char.isdigit(): masked_number += masked_digits[digit_index] digit_index += 1 else: masked_number += char return masked_number # Example credit cards card_numbers = [ "1244-5677-9019-3456", "1234567890123456", "1234 5678 9012 3456" ] print("Using simple regex method:") # Main driver code for card in card_numbers: print(f"Original: {card}") print(f"Masked: {mask_credit_card(card)}\n")Output
Using simple regex method: Original: 1244-5677-9019-3456 Masked: ****-****-****-3456 Original: 1234567890123456 Masked: ************3456 Original: 1234 5678 9012 3456 Masked: **** **** **** 3456
Method 3: String slicing method
In this method, we will calculate the number of digits to be masked. In addition, we will create a string of asterisks for the masked part. Furthermore, we will extract the last four digits of the card number and finally join the asterisks and the last four digits.
def mask_credit_card(card_number): return "*" * (len(card_number) - 4) + card_number[-4:] # Example credit cards card_numbers = ["1234567890123456"] print("Using string slicing:") # Main driver code for card in card_numbers: print(f"Original: {card}") print(f"Masked: {mask_credit_card(card)}\n")Output
Using string slicing: Original: 1234567890123456 Masked: ************3456
This approach is effortless to understand and works with any length of cc numbers. However, it is very basic and does not provide security. Furthermore, it does not handle non-digit characters. That means you have to have valid input to work with this method.
Concluding thoughts
Masking is the process of hiding sensitive user information from the public and instead displaying a symbol like an asterisk (*) instead.
As mentioned earlier, if you are working with a payment information system, I highly recommend using the first approach, which includes data validation, security, handling non-digit characters, and masking credit card numbers.