증상 확인: 시스템이 갑자기 느려지거나 응답 불가 상태가 됨
웹 애플리케이션의 특정 입력 폼(예: 회원가입 이름, 검색창, URL 파라미터)에 데이터를 제출했을 때, 평소와는 다르게 응답이 극도로 느려지거나 서버가 완전히 응답을 중단하는 현상이 발생합니다. 서버 모니터링 도구를 확인하면, 단일 프로세스나 스레드가 CPU 사용률을 100% 가까이 장기간 점유하고 있는 것을 관찰할 수 있습니다. 이는 사용자가 악의적인 정규 표현식 패턴을 입력하여 발생한 서비스 거부 상태의 전형적인 징후입니다.
원인 분석: 정규 표현식 엔진의 최악의 경우 복잡도
문제의 핵심은 “Catastrophic Backtracking”에 있습니다. 정규 표현식 엔진(대부분 NFA 방식)은 패턴 매칭을 위해 가능한 모든 조합을 시도하며 백트래킹합니다. 악의적으로 구성된 패턴과 특정 입력이 결합되면, 백트래킹 경로가 기하급수적으로 폭발하여 단일 평가에 수 초, 수 분, 심지어 영원히 끝나지 않는 연산을 유발합니다. 이로 인해 애플리케이션 스레드가 고갈되어 다른 정상 요청을 처리할 수 없게 됩니다. 취약한 패턴은 주로 중첩된 양화사((a+)+, (a|a?)+), 중복된 선택적 그룹 등을 포함합니다.
해결 방법 1: 입력 길이 제한과 간단한 화이트리스트 필터링
가장 즉각적이고 기본적인 방어선을 구축합니다. ReDoS 공격은 일반적으로 긴 문자열(수십~수천 자)을 필요로 합니다.
- 입력값 길이 제한(Validation): 서버측에서 모든 사용자 입력에 대해 엄격한 길이 제한을 적용하십시오. 클라이언트측 검증만으로는 충분하지 않습니다.
- 예: 사용자 이름은 50자, 검색어는 200자로 제한.
- 화이트리스트 기반 문자 필터링(Sanitization): 입력값이 예상되는 문자 집합만 포함하도록 강제합니다.
- 예: 이름 필드에는
[a-zA-Z가-힣\s.-]만 허용. 정규 표현식 사용 전, 더 간단한 문자열 함수(isalnum()등)로 선필터링 가능.
- 예: 이름 필드에는
이 방법은 많은 저수준 공격을 차단하지만, 정규 표현식 자체의 취약점을 해결하지는 않습니다.
해결 방법 2: 안전한 정규 표현식 패턴 작성 및 엔진 제어
정규 표현식 사용이 불가피하다면, 패턴 자체를 안전하게 설계하고 엔진의 실행 시간을 제한해야 합니다.
패턴 설계 원칙
백트래킹을 최소화하는 패턴을 작성합니다.
- 소유적 양화사(Possessive Quantifier) 사용: 일치한 부분을 되돌리지 않도록 합니다. (Java, PCRE 등)
a++,(a+)+대신a++. - 원자적 그룹(Atomic Group) 사용: 그룹 내부에서 일단 일치하면 백트래킹하지 않습니다.
(?>a+). - 명시적 패턴 작성: 중첩된 불확정성 제거.
^(a+)+$는^a+$로 충분함.
실행 시간 제한 설정
정규 표현식 평가에 타임아웃을 강제합니다. 이는 최후의 안전장치 역할을 합니다.
- Python (regex 모듈):
regex.compile(pattern, timeout=5)와 같이 timeout 인자 사용. - Java (Pattern 클래스): 직접적인 타임아웃은 없으나, 별도 스레드에서 실행하고
Future.get(timeout, TimeUnit.SECONDS)로 인터럽트. - .NET:
Regex(pattern, RegexOptions.None, TimeSpan.FromSeconds(5))생성자 사용. - Node.js:
safe-regex라이브러리로 패턴 검사 또는 실행을 Worker 스레드로 분리 후 타임아웃.
주의사항: 소유적 양화사나 원자적 그룹은 정규 표현식 엔진에 따라 지원 여부가 다릅니다. 프로덕션 코드 적용 전, 개발 환경에서의 호환성과 기존 로직 변경 여부를 반드시 테스트해야 합니다. 타임아웃 설정은 환경(예: 다른 정규 표현식 라이브러리 사용)에 따라 달라질 수 있습니다.
해결 방법 3: 정적 분석 도구 도입과 대체 구현
조직적이고 근본적인 접근법입니다. 취약한 패턴을 사전에 발견하고, 가능하면 정규 표현식을 피합니다.
- 정적 분석 도구(SAST) 통합: CI/CD 파이프라인에 정규 표현식 보안 취약점 검사 도구를 추가합니다.
- 예: SonarQube(with ReDoS 플러그인),
owasp-esapi-java라이브러리의Validator.SafeRegex메서드, 또는 전용 npm 패키지(safe-regex,recheck). - 이 도구들은 패턴을 분석하여 최악의 경우 복잡도를 평가하고 잠재적 ReDoS 취약점을 리포트합니다.
- 예: SonarQube(with ReDoS 플러그인),
- 정규 표현식 대체: 간단한 문자열 매칭이나 파싱으로 해결할 수 있는 작업인지 재검토합니다.
- 예: URL 검증을 위해 복잡한 정규 표현식 대신, 신뢰할 수 있는 파서(
new URL()in JavaScript,urllib.parsein Python)를 사용. - 특정 문자열로 시작하는지 확인:
str.startsWith("prefix")(O) vs/^prefix.*/(X).
- 예: URL 검증을 위해 복잡한 정규 표현식 대신, 신뢰할 수 있는 파서(
주의사항: 지속적인 모니터링과 테스트

한 번 수정했다고 해서 영원히 안전한 것은 아닙니다. 새로운 코드가 추가되거나 라이브러리가 업데이트되면서 취약점이 다시 도입될 수 있습니다.
- 부하 테스트에는 단순한 정상 입력만 포함해서는 안 됩니다. 성능·부하 테스트를 수행할 때는 장문의 일반 문자열과 함께 의심스러운 정규 표현식 입력을 함께 시뮬레이션해, 해당 상황에서 시스템이 어떻게 반응하는지를 관찰해야 합니다. 이는 웨일 브라우저 마우스 제스처 설정: 뒤로 가기 탭 닫기처럼, 실제 사용자 행동 패턴을 가정해 다양한 입력 시나리오를 점검해야만 체감 품질과 안정성을 동시에 확보할 수 있다는 점을 시사합니다.
- 애플리케이션 성능 모니터링(APM): 프로덕션 환경에서 요청 처리 시간을 상시 모니터링합니다. 특정 엔드포인트의 평균 처리 시간이 비정상적으로 증가하는 추세는 잠재적 공격이나 성능 저하의 신호입니다.
- WAF(웹 애플리케이션 방화벽) 규칙: 가능하다면, 알려진 ReDoS 유발 패턴을 차단하는 WAF 규칙을 활성화하십시오. 이는 애플리케이션 로직 수정 전의 추가 보호층이 됩니다.
전문가 팁: 정규 표현식은 강력한 도구이지만, 비용이 높은 연산입니다. “정규 표현식이 해답일 때, 당신은 두 개의 문제를 가진 것”이라는 격언을 명심하십시오. 패턴을 작성한 후, 반드시
regex101.com같은 온라인 테스터를 이용해 “디버거” 모드로 실행해 보십시오, 입력에 대해 엔진이 몇 단계를 거치는지 확인하면, 백트래킹이 과도하게 발생하는 패턴을 시각적으로 식별할 수 있습니다. 또한, 팀 내에 ‘정규 표현식 코드 리뷰 체크리스트’를 만들어, 모든 새로운 정규 표현식이 길이 제한 검사, 타임아웃 설정, 안전한 패턴 원칙 중 하나 이상을 충족하는지 확인하는 문화를 정착시키는 것이 장기적 보안을 보장합니다.