HTML 엔티티 인코딩의 작동 원리
HTML 엔티티는 브라우저가 파싱하여 단일 문자로 복원하는 문자 참조입니다. 다섯 가지 예약된 HTML 문자(<, >, &, ", ')는 텍스트가 HTML로 렌더링될 때 항상 인코딩이 필요하며, 나머지는 선택 사항으로 문서 인코딩 방식에 따라 다릅니다.
- 모드와 범위 선택. 인코드 모드는 입력을 문자 단위로 처리합니다. 디코드 모드는 입력에서 엔티티 패턴을 찾습니다. 범위 토글은 다섯 가지 HTML 안전 문자만 인코딩할지, 모든 비 ASCII 코드 포인트도 변환할지를 결정합니다.
- 엔티티 스타일 선택. 이름형 엔티티(
©)는 소스 코드에서 읽기 좋습니다. 10진수 참조(©)와 16진수 참조(©)는 이름 없이도 모든 유니코드 코드 포인트를 표현합니다. 구형 이메일 클라이언트와 XML 파서는 숫자형 형식을 선호합니다. - 입력 순회. 인코딩 시 각 코드 포인트를 읽어 약 200개의 이름형 엔티티 내장 테이블과 대조합니다. 일치하지 않으면 숫자형으로 폴백합니다. 디코딩 시
&name;,&#NNN;,&#xHH;를 한 번에 매칭하는 단일 정규식으로 스캔합니다. - 문자로 매핑. 이름형은 역방향 테이블로 해석합니다. 숫자형은 10진수 또는 16진수로
String.fromCodePoint를 통해 처리합니다. 알 수 없는 이름형 엔티티는 그대로 유지되어 부분 입력도 손실 없이 왕복됩니다. - 실시간 모드. 실시간 모드를 켜면 키 입력마다 150ms 디바운스로 변환이 재실행됩니다. 스니펫을 조정하면서 템플릿에 붙여넣기 전에 즉각적인 피드백을 원할 때 유용합니다.
HTML 엔티티를 인코딩해야 하는 이유
- 사용자 입력이 레이아웃을 깨지 않도록 방지. 사용자가 댓글 창에
<를 입력하면 그 텍스트를 HTML에 그대로 삽입했을 때 페이지 나머지 부분이 깨집니다. 예약 문자를 먼저 인코딩하면 브라우저가 해당 문자를 태그의 시작이 아닌 문자로 렌더링합니다. - 속성값 유효성 유지. HTML 속성 안에 따옴표가 포함된 문자열을 삽입할 때, 내부 따옴표를
"(큰따옴표 속성의 경우) 또는'(작은따옴표 속성의 경우)로 교체해야 합니다. 그렇지 않으면 파서가 속성을 조기에 닫고 나머지 내용이 잘못된 마크업이 됩니다. - 저장된 데이터의 의도치 않은 HTML 무력화. 로그, 버그 리포트, 채팅 내보내기에는 종종 실제 꺾쇠 괄호와 앰퍼샌드가 포함됩니다. 덤프를 문서 페이지에 붙여넣기 전에 엔티티 인코딩하면 해당 내용이 텍스트로 표시되며 렌더러나 링크 자동 감지기가 오작동하지 않습니다.
- 코드 스니펫 안전하게 공유. 블로그 글, 이메일, 슬랙 메시지에
<script>alert(1)</script>같은 예시 태그를 게시할 때 괄호를 인코딩해야 스니펫이 실행되지 않고 표시됩니다. 이 기법은 RSS 피드 본문과 JSON-LD `description` 필드에도 동일하게 적용됩니다.
주요 활용 사례
엔티티 인코딩은 프레임워크가 자동으로 처리해 주더라도, 처리되지 않는 순간을 위해 수동 도구가 유용합니다. 원시 텍스트가 런타임에 HTML로 합성되는 모든 곳에서 활용됩니다.
- 서버 렌더링 템플릿: Jinja2, ERB, Twig, Handlebars는 기본적으로 자동 이스케이프하지만 raw 블록과 `safe` 마커가 이를 비활성화합니다 — 이 코덱으로 이스케이프 결과를 확인할 수 있습니다.
- 이메일 및 뉴스레터 제작: 많은 ESP 템플릿 엔진은 병합 필드를 자동 이스케이프하지 않으므로, 사용자 제공 이름의 스마트 따옴표와 저작권 기호를 사전에 인코딩해야 합니다.
- 문서 및 코드 샘플: Markdown 블로그나 정적 사이트 스니펫에 예시 HTML 태그를 붙여넣을 때 괄호를 인코딩해야 렌더러가 텍스트로 처리합니다.
실제 예시
모드를 인코드, 스타일을 이름형, 범위를 최소로 설정하고 <script>alert('hi')</script>를 붙여넣으면 출력이 <script>alert('hi')</script>가 됩니다. 스타일을 숫자형 16진수로 바꾸면 동일 입력이 <script>alert('hi')</script>가 됩니다. 모드를 디코드로 전환하고 인코딩된 문자열을 다시 붙여넣으면 원래 태그가 그대로 복원됩니다.
FAQ
HTML 엔티티란 무엇인가요?
HTML 엔티티는 브라우저가 페이지를 파싱할 때 단일 문자로 대체하는 문자 참조입니다. 이름형(&는 &), 10진수 숫자형(&), 16진수 숫자형(&)의 세 가지 형태가 있습니다. 다섯 가지 예약된 HTML 문자(<, >, &, ", ')는 텍스트가 HTML에 삽입될 때 항상 인코딩이 필요합니다. 나머지 약 2,225개의 이름형 엔티티는 기호, 악센트, 그리스 문자를 다루지만 문서 인코딩이 UTF-8이면 선택 사항입니다.
이름형과 숫자형 엔티티 중 어느 것을 사용해야 하나요?
소스 코드를 명확하게 읽고 싶을 때는 이름형 엔티티를 사용하세요(템플릿에서 ©를 보면 바로 이해됩니다). 소비자가 구형이거나 엄격한 경우 — XML 파서, 레거시 이메일 클라이언트, 일부 피드 리더는 HTML5 이름형 엔티티의 일부만 인식하고 숫자형은 모두 인식합니다. 16진수는 스펙 문서의 유니코드 코드 포인트 표기와 일대일로 대응되기 때문에 보안 중심 컨텍스트에서 선호됩니다.
& 같은 16진수 엔티티도 디코딩되나요?
네. 디코더는 세 가지 엔티티 형태를 한 번에 매칭하는 단일 정규식을 사용합니다: &name;, &#NNN;, &#xHH;. 숫자형은 10진수 또는 16진수로 String.fromCodePoint를 통해 해석됩니다. 이름형과 숫자형이 혼합된 입력도 올바르게 디코딩되며, 알 수 없는 이름은 리터럴 텍스트로 유지되어 부분 입력도 손실 없이 왕복됩니다.
신뢰할 수 없는 입력에 안전하게 사용할 수 있나요?
코덱 자체는 브라우저 전용으로 입력을 어디에도 전송하지 않습니다. 출력을 안전하게 삽입할 수 있는지 여부는 컨텍스트에 따라 다릅니다. 엔티티 인코딩은 HTML 본문 및 속성값 컨텍스트를 처리하며, OWASP 규칙 #1 케이스를 커버합니다. JavaScript 컨텍스트(인라인 이벤트 핸들러, `<script>` 블록), CSS 컨텍스트, URL 컨텍스트는 각각의 인코딩 규칙이 필요하며 엔티티 인코딩만으로는 충분하지 않습니다. 서버 측 심층 방어를 위해 DOMPurify나 프레임워크의 자동 이스케이프 기능과 함께 사용하세요.
브라우저 측 엔티티 인코딩은 사용자 입력과 렌더링된 HTML 사이의 경계에 위치합니다. 변환을 로컬에서 수행하면 원본 텍스트를 외부 도구로 전송하지 않고도 프레임워크가 생성했을 결과를 검증할 수 있습니다.