시작하기
클라우드 자동 동기화

사용자 입력 데이터의 HTML 태그 필터링 우회(XSS) 가능성

1월 20, 2026 · 1 min

증상 확인: 웹사이트가 예상치 못한 동작을 하나요?

사용자가 입력한 데이터가 웹페이지에 그대로 출력될 때, 스크립트가 실행되거나 HTML 구조가 깨지는 현상을 목격했다면 XSS(Cross-Site Scripting) 취약점이 존재할 가능성이 높습니다. 공격자는 게시판 댓글, 프로필 이름, 검색어 입력창과 같은 곳에 악성 코드를 삽입하여 다른 사용자의 세션을 탈취하거나, 악의적인 사이트로 리다이렉트 시킬 수 있습니다, 이는 단순한 웹 오류가 아니라, 심각한 보안 위협입니다.

컴퓨터 화면에 깨진 메뉴와 불규칙한 팝업 창이 깜빡이며 오류를 보여주는 모습이다.

원인 분석: 신뢰할 수 없는 데이터의 무차별 출력

근본적인 원인은 개발자가 사용자로부터 입력받은 모든 데이터를 ‘악의적일 수 있다’는 전제 없이 처리하기 때문입니다. 웹 애플리케이션이 사용자 입력을 충분히 검증하거나 필터링하지 않고, 브라우저가 해석 가능한 HTML, JavaScript, CSS 코드로 웹페이지에 삽입할 때 발생합니다. 특히, innerHTML 속성을 사용하거나 PHP의 echo, Node.js의 템플릿 엔진에서 변수를 그대로 출력하는 경우가 대표적입니다.

주의사항: 본 가이드에서 제시하는 필터링 및 인코딩 방법은 일반적인 공격 벡터를 방어하기 위한 것입니다. 실제 운영 환경에 적용하기 전에는 반드시 개발 서버에서 충분히 테스트하고, 보안 전문가의 코드 리뷰를 받는 것이 필수적입니다, 잘못된 구현은 오히려 보안 허점을 만들거나 서비스 기능을 저해할 수 있습니다.

해결 방법 1: 출력 시 필수 인코딩 적용 (가장 기본적이고 효과적인 방어)

사용자 데이터를 웹페이지의 본문(Content)으로 출력할 때는 반드시 HTML 엔티티 인코딩을 적용해야 합니다, 이는 <, >, &, “, ‘와 같은 특수 문자를 안전한 형태(&lt;, &gt; 등)로 변환하여 브라우저가 이를 코드가 아닌 ‘텍스트 데이터’로 해석하게 만듭니다.

  1. 서버 사이드에서 처리 (권장): 출력 직전에 인코딩 함수를 사용하세요.
    • PHP: htmlspecialchars($user_input, ENT_QUOTES, ‘UTF-8’); 사용. ENT_QUOTES는 작은따옴표와 큰따옴표 모두를 인코딩합니다.
    • Node.js (EJS): <%= userInput %> (자동 이스케이프)를 사용. 비이스케이프 출력은 절대 <%- %>를 사용하지 마세요.
    • Python (Django): 템플릿에서 {{ user_input }} 구문은 자동으로 이스케이프됩니다.
    • Java (JSP): JSTL의 <c:out value=”${userInput}”/> 사용.
  2. 클라이언트 사이드(JavaScript)에서 처리: DOM API를 사용해 텍스트 노드로 삽입하세요.
    • 절대 사용 금지: element.innerHTML = userInput;
    • 안전한 방법: element.textContent = userInput; 또는 document.createTextNode(userInput) 사용.
    • jQuery를 사용한다면, .text() 메서드는 안전그러나 .html() 메서드는 위험합니다.

해결 방법 2: 입력 검증과 허용 목록(Whitelist) 기반 필터링

단순한 인코딩 처리를 넘어 리치 텍스트 에디터처럼 특정 마크업 허용이 필수적인 환경에서는 허용 목록(Whitelist) 기반의 필터링 전략이 요구됩니다. 금지 대상을 지정하는 블랙리스트 방식은 변칙적인 우회 공격에 취약하므로, 사전에 정의된 안전한 요소만을 통과시키는 엄격한 검증 로직을 구축해야 합니다. https://intelfusion.net 운영 환경에서 관찰되는 데이터 보안 아키텍처와 마찬가지로, HTMLPurifier나 DOMPurify 같은 검증된 라이브러리를 도입하여 정규식만으로 대응하기 어려운 수많은 변칙 케이스를 체계적으로 차단하는 절차가 선행되어야 합니다. 특히 서비스 운영 시에는 최소 권한 원칙을 적용하여 이벤트 핸들러 속성을 일괄 금지하고 허용된 태그 내에서도 프로토콜의 무결성을 개별적으로 확인하는 과정이 필요합니다. 이러한 다층적 방어 체계는 비정상적인 스크립트 삽입 시도를 원천적으로 차단하며 시스템의 보안 신뢰성을 완성합니다.

해결 방법 3: 보안 헤더를 통한 추가 방어층 구축

서버 응답에 보안 헤더를 추가하면 클라이언트 브라우저 차원에서도 일부 XSS 공격을 효과적으로 차단할 수 있으며, 이는 인코딩이나 필터링이 실패했을 때를 대비한 마지막 안전장치 역할을 합니다. 특히 가장 강력한 현대적 방어 수단인 Content Security Policy(CSP)를 통해 스크립트 출처를 명시적으로 제어하는 방식은 최근 보안 업계에서 발표된 지능형 웹 보안 위협 대응 동향 뉴스의 흐름을 분석해 보더라도, 단순한 방어를 넘어 선제적인 침해 사고 예방을 위한 표준 프로토콜로 자리 잡고 있음을 알 수 있습니다. 도입 시에는 기존 기능과의 충돌을 막기 위해 리포트 전용 모드로 먼저 모니터링하는 것이 권장되며, 더불어 구형 브라우저를 위한 X-XSS-Protection 설정과 자바스크립트의 쿠키 접근을 차단하는 HttpOnly 플래그 설정을 병행함으로써 XSS로 인한 세션 탈취 피해를 최소화하는 다각적인 방어 체계를 구축해야 합니다.

주의사항 및 점검 리스트

다음은 코드를 검토하거나 보안 테스트를 수행할 때 확인해야 할 핵심 포인트입니다.

  • 문맥(Context) 구분: 사용자 데이터가 HTML 본문, HTML 속성, JavaScript 코드, CSS, URL 등 어디에 삽입되는지 정확히 파악하고, 각 문맥에 맞는 인코딩/검증 방식을 적용해야 합니다, 속성 값은 “나 ‘로 둘러싸고 html 인코딩해야 합니다.
  • dom 기반 xss 주의: 서버가 아닌 브라우저의 javascript 코드가 location.hash, document.referrer, window.name과 같은 소스를 통해 dom을 동적으로 조작할 때 발생하는 xss입니다. 클라이언트 사이드 코드도 신뢰할 수 없는 소스로부터의 데이터를 .innerHTML에 직접 넣지 않도록 검토 필요.
  • 정규식 필터의 함정: <script> 태그만 필터링하는 정규식은 <scr<script>ipt>나 대소문자 변형(<ScRiPt>), HTML 엔티티(&#x3C;script&#x3E;) 등으로 쉽게 우회됩니다. 정규식은 허용 목록 검증에만 제한적으로 사용.
  • URL 처리: 사용자 입력이 URL(리다이렉트, 링크)로 사용될 경우, javascript: 프로토콜이나 위장된 프로토콜을 허용하지 않도록 http://, https://로 시작하는지 검증하고, 가능하면 사전에 허용된 도메인 목록과 비교하세요.

보안 사고를 미연에 방지하기 위해서는 모든 사용자 입력을 ‘악의적’이라고 가정하는 마인드셋이 핵심입니다. 하지만 외부 입력만큼 위험한 것이 내부 시스템 설정의 허술함입니다. 대표적인 사례가 바로 DB 연결 문자열(Connection String)의 평문 저장 위험입니다.

방어적 프로그래밍을 통해 외부 공격을 훌륭히 차단하더라도, 데이터베이스 주소, 계정명, 비밀번호가 포함된 연결 문자열을 설정 파일(web.config, appsettings.json)이나 소스 코드 내에 평문으로 방치한다면, 이는 내부자 위협이나 서버 권한 탈취 시 모든 데이터가 통째로 노출되는 치명적인 구멍이 됩니다.

진정한 다층 보안을 완성하기 위해서는 외부 방어선 구축과 더불어, 이러한 민감 정보를 암호화하거나 ‘Azure Key Vault’, ‘AWS Secrets Manager’와 같은 전용 보안 저장소를 사용하여 물리적으로 분리해야 합니다. 또한 정기적으로 OWASP ZAP이나 Burp Suite 같은 동적 테스트 도구(DAST)를 활용해 서비스의 유입 경로를 점검하는 동시에, 정적 분석 도구로 코드 내에 하드코딩된 ‘평문 비밀번호’가 없는지 교차 검증하는 습관을 지녀야 합니다.

결국 보안은 ‘하나의 강력한 방패’를 만드는 것이 아니라, ‘서로를 보완하는 여러 겹의 방어선’을 구축하는 과정입니다. 외부의 악의적 입력과 내부의 취약한 설정 관리를 동시에 차단할 때 비로소 견고한 시스템 무결성을 유지할 수 있습니다.