SOFTMOA TECHNOLOGY
Node.js 정규식 검사 때문에 서버가 멈출 때: ReDoS 점검과 입력 검증 수정
소프트모아가 정리한 기술 기록입니다.
Contents
사용자 입력을 정규식으로 검사하는 순간 API 응답이 멎는다면, 긴 문자열 자체보다 실패할 때 여러 경로를 되짚는 정규식이 문제일 수 있습니다. ReDoS를 점검할 때는 요청이 들어오는 경로와 패턴을 먼저 찾고, 입력 크기를 제한한 뒤, 겹치는 반복을 없앤 검증식으로 바꾸세요. 입력 길이 제한만으로 위험한 패턴이 안전해지는 것은 아닙니다.
어떤 요청에서 정규식이 실행되는지 찾기
라우트 매개변수, 검색 조건, 파일 이름, 계정 식별자처럼 외부에서 받은 값을 검사하는 코드를 살펴보세요. 특히 (a+)+처럼 반복 안에 반복이 있거나, 서로 같은 글자를 받아들일 수 있는 선택지가 반복되는 패턴을 확인합니다. 정상 입력만 빠르게 통과했다고 안심하면 안 됩니다. 일부 패턴은 긴 입력의 끝에서 일치가 실패할 때 되돌아가는 경로가 급증합니다. Node.js 공식 문서도 이런 경우 이벤트 루프가 막혀 다른 요청까지 기다리게 될 수 있다고 설명합니다. 운영 서버에 의도적으로 긴 실패 입력을 보내 시험하지는 마세요.
진단 순서는 요청 본문·쿼리·경로 중 어느 필드가 검증식에 들어가는지, 그 필드의 최대 길이와 허용 문자 규칙이 무엇인지, 실패 요청 직전 어떤 검증이 실행됐는지를 확인하는 것입니다. 이벤트 루프 지연은 증상일 뿐 정규식이 원인이라는 증거는 아닙니다. 요청 원문이나 개인정보를 통째로 로그에 남기지 말고, 필드 이름과 길이, 검증 실패 유형만 기록하도록 범위를 좁히세요.
슬러그는 복잡한 패턴보다 작은 허용 규칙으로
다음 예시는 슬러그를 소문자 ASCII 영문자, 숫자, 하이픈으로만 받고 길이를 1~64개의 JavaScript 문자열 코드 단위로 제한합니다. 먼저 타입과 길이를 확인하므로 너무 긴 입력은 정규식 검사 전에 거부됩니다. 검증식에는 중첩 반복이나 겹치는 선택지를 넣지 않았습니다. 이 규칙은 이메일 주소나 사람 이름에 재사용할 규칙이 아니라, 이 슬러그 필드의 예시입니다.
import assert from 'node:assert/strict';
function validSlug(value) {
if (typeof value !== 'string' || value.length < 1 || value.length > 64) {
return false;
}
return /^[a-z0-9-]+$/.test(value);
}
assert.equal(validSlug('order-2026'), true);
assert.equal(validSlug('a'.repeat(65)), false);
assert.equal(validSlug('order!'), false);
assert.equal(validSlug('주문-2026'), false);
assert.equal(validSlug(null), false);
console.log('slug checks passed');
위 코드를 slug-check.mjs로 저장하고 node --check slug-check.mjs, 이어서 node slug-check.mjs를 실행하세요. 문법 검사에 오류가 없고 테스트가 모두 통과하면 slug checks passed가 출력됩니다. 이 테스트는 허용·길이 초과·문자 불일치·타입 오류를 확인할 뿐, 서비스 전체의 부하 내성이나 모든 정규식의 안전성을 증명하지 않습니다. 하이픈의 첫 글자 허용 여부나 중복 하이픈처럼 업무상 필요한 의미 검사는 별도 조건으로 정하세요.
길이 제한을 적용할 위치도 정해야 합니다
함수 안의 value.length 검사는 이미 파싱된 문자열을 다룹니다. 요청 본문 자체가 큰 경우에는 서버·프록시의 요청 크기 제한과 파서의 제한도 따로 설정해야 합니다. 반대로 프록시 제한만 걸어두면 짧지만 위험한 패턴은 그대로 남습니다. 문자열 정규식과 요청 크기 제한을 서로 다른 방어층으로 취급하세요. 입력값이 배열이나 객체로 바뀔 수 있는 API라면 타입 검사를 먼저 두고, 숫자로 암묵 변환해 원래 문제를 숨기지 않는 편이 확인하기 쉽습니다.
기존 패턴을 고칠 때는 통과해야 할 값과 거부해야 할 값을 테스트에 함께 적으세요. 예컨대 영문 대문자가 원래 허용됐다면 위 예시로 교체하는 순간 기존 요청의 동작이 달라집니다. 허용 범위를 합의한 뒤 교체하고, 실패 응답이 어떤 필드에서 비롯됐는지는 알려주되 입력 전체를 응답이나 로그에 되풀이하지 않는 것이 좋습니다. 복잡한 패턴을 정적 도구로 검사할 수는 있지만 도구에서 경고가 없다는 사실만으로 안전하다고 결론 내리지 마세요.
검증 대상이 단순 문자열이 아니라면
구분자 몇 개를 확인하는 수준이면 정규식 대신 문자열 분리와 각 부분의 길이·허용값 검사가 읽기 쉬울 수 있습니다. 다국어 이름이나 자유 서술문에 ASCII 슬러그 허용 목록을 적용하면 정상 입력도 거부합니다. 필드의 목적에 맞는 검증을 설계하고, 보안상 필요한 출력 인코딩·쿼리 매개변수화·권한 확인을 입력 검증 하나로 대신하지 마세요. OWASP는 입력의 문법과 업무 의미를 구분해 확인하고, 외부 입력을 가능한 이른 시점에 검증하라고 권합니다.
근거: Node.js 이벤트 루프와 ReDoS 안내, OWASP 입력 검증 가이드. 소프트모아의 다른 개발 자료는 softmoa.com에서 볼 수 있습니다.
소프트모아는 해당 시스템을 구축합니다. 문의하기