← 모두의 툴

정규식 생성기의 '신용카드' 패턴은 사실 아무 13자리 숫자에나 매칭된다

가이드 · 2026.08.25 최종 확인

정규식 생성기의 "신용카드" 프리셋을 쓰면 카드번호처럼 생긴 문자열을 걸러낼 수 있을 것 같지만, 실제로는 자릿수와 구분자 모양만 확인할 뿐입니다. 진짜 유효한 카드번호인지 판단하려면 룬(Luhn) 알고리즘이라는 체크섬 검증이 필요한데, 이 알고리즘은 애초에 정규식의 표현 범위 밖에 있습니다. 왜 정규식이 이걸 못 하는지, 그리고 실제 프리셋이 무엇을 걸러내고 무엇을 통과시키는지 코드 레벨에서 확인합니다.

1. 룬 알고리즘이란 무엇인가

룬 알고리즘은 1954년 IBM의 한스 피터 룬이 고안한 체크섬 검증 방식으로, 신용카드번호·IMEI·사업자등록번호 등 다양한 식별번호의 마지막 자리를 "검증 숫자"로 사용합니다. 계산 방식은 오른쪽 끝에서부터 홀수 번째 자리는 그대로, 짝수 번째 자리는 2를 곱한 뒤(결과가 9를 넘으면 각 자리를 더해서 한 자리로 만듦) 모든 자리를 합산했을 때 그 총합이 10의 배수가 되어야 유효한 번호로 인정하는 방식입니다. 단순한 오타나 숫자 하나가 바뀐 위조 번호를 상당수 걸러낼 수 있어 실무에서 1차 검증 수단으로 널리 쓰입니다.

2. 정규식이 이 계산을 표현할 수 없는 이유

정규식은 문자열이 특정 "패턴"과 일치하는지를 판단하는 언어입니다. 유한 오토마톤 기반이라 문자의 순서·반복·존재 여부는 검사할 수 있지만, 자리마다 다른 가중치(1배 또는 2배)를 곱하고 그 결과를 전부 더해서 특정 값과 비교하는 산술 연산은 정규식 문법 안에 존재하지 않습니다. 이건 특정 정규식 엔진의 기능 부족이 아니라, 정규 언어(regular language)라는 이론적 범주 자체가 산술 합산 같은 "누적 상태"를 표현하지 못한다는 계산 이론의 근본적인 한계입니다. 결국 정규식으로 신용카드번호를 검사한다는 것은 애초부터 "형식만 보겠다"는 의미이고, 유효성 검증은 별도의 코드(반복문 + 산술 연산)로 처리해야 합니다.

3. modoohub 정규식 생성기의 실제 "신용카드" 프리셋

코드를 직접 확인한 결과 신용카드 프리셋의 정규식은 \b(?:\d[ \-]?){13,16}\b입니다. 풀어서 설명하면 "숫자 한 자리 뒤에 공백이나 하이픈이 있어도 되고 없어도 됨"을 13~16번 반복하는 패턴입니다. 즉 확인하는 것은 딱 두 가지뿐입니다: ① 숫자가 13~16자리인가, ② 숫자 사이 구분자가 공백이나 하이픈뿐인가. 룬 체크섬은 물론이고 카드사별 시작 번호(비자는 4, 마스터카드는 51~55 등 BIN 규칙) 검사도 전혀 없습니다.

예시: 카드와 전혀 무관한 임의의 13자리 숫자 "0212345678901"(전화번호나 주문번호로 만든 숫자)을 이 정규식으로 테스트하면 매칭됩니다. 반대로 진짜 비자카드 테스트번호 "4111 1111 1111 1111"(16자리, 룬 체크섬 통과)도 매칭되지만, 룬 체크섬을 일부러 깨뜨린 "4111 1111 1111 1112" 같은 무효 번호도 똑같이 매칭됩니다. 정규식 단계에서는 이 둘을 구분할 방법이 없습니다.

4. 그럼 형식 검사는 언제 의미가 있나

이미 문맥상 "이 필드는 카드번호가 맞다"는 것이 확실한 경우(예: 결제 폼의 카드번호 입력칸)라면, 사용자가 숫자를 다 채웠는지·자릿수가 맞는지 정도의 1차 형식 검사로는 여전히 유용합니다. 문제는 자유 텍스트에서 카드번호를 "탐지"하려는 목적으로 쓸 때입니다. 로그 파일이나 채팅 내용에서 이 정규식으로 카드번호를 찾아내려 하면, 카드와 무관한 13~16자리 숫자(주문번호, 전화번호, 일련번호 등)까지 대량으로 오탐(false positive)됩니다.

5. 실제로 유효성까지 검증하려면

룬 체크섬은 반복문으로 몇 줄이면 구현됩니다: 뒤에서부터 자리를 순회하며 짝수 인덱스는 2배 후 9 초과 시 각 자리를 더하고, 전체 합이 10으로 나누어떨어지는지 확인하면 됩니다. 정규식으로는 "형식이 그럴듯한가"까지만, 실제 "유효한 번호인가"는 이런 별도 산술 로직이 필요합니다. 정규식 생성기에서 만든 패턴은 어디까지나 1차 필터로만 쓰고, 결제·검증이 실제로 걸린 곳에서는 룬 체크섬을 포함한 전용 검증 로직이나 라이브러리를 반드시 함께 사용해야 합니다.

자주 묻는 질문

Q. "신용카드" 프리셋이 실제 카드 번호만 정확히 찾아내나요?

아니요. 이 패턴(\b(?:\d[ \-]?){13,16}\b)은 13~16자리 숫자가 공백이나 하이픈으로 구분되어 있는지만 확인하며, 룬 체크섬 검증이나 카드사별 BIN(첫 자리) 검사를 전혀 하지 않습니다. 카드와 무관한 13자리 숫자도 이 패턴에 매칭됩니다.

Q. 정규식만으로 룬 체크섬 검증이 정말 불가능한가요?

네, 표준 정규식(정규 언어) 범위 안에서는 불가능합니다. 자리마다 다른 가중치를 곱해서 누적 합산하는 연산은 정규 언어가 표현할 수 있는 "패턴 매칭"의 범주를 벗어나는 산술 연산이기 때문입니다. 이를 검증하려면 반복문과 산술 연산이 있는 일반 프로그래밍 코드가 필요합니다.

Q. 이런 형식 검사 정규식은 언제 사용하면 안전한가요?

이미 "이 필드가 카드번호일 가능성이 있다"는 문맥이 확실한 경우(결제 폼의 카드번호 입력칸 등)에 형식만 빠르게 검사할 때는 유용합니다. 자유 텍스트에서 카드번호를 탐지하려는 목적으로 쓰면 오탐이 많이 발생해 부적합합니다.

Q. JWT 패턴도 비슷한 한계가 있나요?

네. JWT 프리셋도 점(.)으로 구분된 세 구간이 각각 2자 이상이면 매칭되도록 되어 있어, "12.34.56" 같은 버전 번호나 임의의 점 구분 문자열에도 매칭됩니다. 실제 JWT는 각 구간이 Base64URL로 인코딩된 JSON이지만 그 세부 구조까지는 검사하지 않습니다. 정확한 JWT 구조 검증은 JWT 검사기로 디코딩까지 확인하는 것이 안전합니다.