HTML 엔티티 인코딩 도구
HTML 엔티티 문자를 온라인으로 변환하며, 인코딩 및 디코딩을 지원하고 XSS 공격을 효과적으로 방지합니다
변환 방식 선택
HTML 엔티티 인코딩이란?
HTML 엔티티 인코딩은 특수 문자를 HTML 엔티티 참조로 변환하는 메커니즘입니다. HTML에서 일부 문자는 특수한 의미를 가지고 있습니다(예: <, >, &). 이러한 문자 자체를 페이지에 표시하려면 엔티티 인코딩을 사용해야 합니다. 엔티티 인코딩에는 두 가지 형태가 있습니다: 명명된 엔티티(예: <)와 숫자 엔티티(예: <). 명명된 엔티티는 읽기 쉽고, 숫자 엔티티는 모든 Unicode 문자를 표현할 수 있습니다.
사용 방법
사용 방법
- 왼쪽 입력 상자에 변환할 텍스트를 입력하거나 붙여넣습니다
- 해당 변환 버튼을 클릭하여 인코딩 또는 디코딩 방법을 선택합니다
- 결과가 오른쪽에 자동으로 표시됩니다
- '복사' 버튼을 클릭하여 결과를 클립보드에 복사합니다
변환 방법
키보드 단축키
- Ctrl + EHTML 엔티티 인코딩
- Ctrl + DHTML 엔티티 디코딩
인코딩 팁
- HTML 소스에 사용자에게 보이는 텍스트를 삽입하기 전에 인코딩하세요. 특히 꺾쇠 괄호, 따옴표 또는 앰퍼샌드가 포함될 수 있는 경우에 중요합니다.
- HTML 엔티티 인코딩은 마크업이 해석되는 것을 방지하는 데 도움이 되지만, XSS 방어의 일부일 뿐이며 컨텍스트별 출력 이스케이프를 대체하지는 않습니다.
활용 사례
기술 원리
HTML은 WHATWG HTML Living Standard가 정의하는 두 가지 문자 참조를 사용합니다. 명명된 문자 참조는 &로 시작하고 ;로 끝나며, WHATWG가 관리하는 entities.json 테이블(현재 사양 기준 약 2,231개 이름, 끝에 세미콜론이 없는 레거시 별칭 포함)에서 가져옵니다. 숫자 문자 참조는 십진수(<) 또는 십육진수(<) 형태의 유니코드 코드 포인트를 사용하며, 대체 영역 U+D800-U+DFFF을 제외한 U+0000부터 U+10FFFF까지 모든 문자를 인코딩할 수 있습니다. HTML 구문 안전을 위해 반드시 이스케이프해야 하는 다섯 문자는 &(&), <(<), >(>), "("), '(')입니다. '는 XML과 HTML5에 포함되지만 HTML 4.01에서는 유효하지 않으므로, OWASP는 레거시 파서를 거쳐야 하는 이중 따옴표 속성에 숫자 형태 '를 권장합니다. 이 도구의 인코딩은 단일 패스 치환입니다. 순서가 중요한데, &를 먼저 이스케이프해야 하며, 그렇지 않으면 <와 >에 삽입된 엔티티 접두사가 &lt;로 재이스케이프됩니다. 디코딩은 브라우저의 HTML 파서를 활용합니다. 입력을 분리된 요소의 innerHTML에 할당하고 textContent를 읽어옴으로써, HTML 사양의 공식 토크나이저 상태 머신(13.2.5.72 문자 참조 상태부터 13.2.5.80까지)에 위임합니다. 이 머신은 끝 세미콜론이 없는 잘못된 입력을 포함하여 명명된, 십진수, 십육진수 형태를 모두 올바르게 해석합니다. 전체 인코딩 모드의 숫자 인코딩은 String.prototype.codePointAt를 사용하여 코드 포인트 단위로 문자열을 순회하므로, UTF-16 대체 쌍을 차지하는 아스트랄 문자(예: 이모지 U+1F600)가 😀 하나로 변환됩니다. XSS 방지는 HTML 엔티티 인코딩만으로는 부족하며, 컨텍스트별 이스케이프가 필요합니다. OWASP XSS 방어 치트 시트는 HTML 본문, HTML 속성(따옴표/비따옴표), JavaScript 데이터(<script> 내부), CSS, URL 등 다섯 가지 컨텍스트를 정의합니다. HTML 엔티티 이스케이프는 컨텍스트 1과 2만 커버합니다. JavaScript 컨텍스트는 JSON.stringify를 통한 \xHH 또는 \uHHHH 이스케이프를, URL 컨텍스트는 encodeURIComponent(RFC 3986 퍼센트 인코딩)를 사용해야 하며, 인라인 이벤트 핸들러는 HTML과 JavaScript 파서를 모두 거치므로 규칙이 합산됩니다. script-src 'self'와 unsafe-inline이 제거된 Content-Security-Policy 헤더는 이스케이프 실수를 잡는 현대적 방어 계층이며, innerHTML, document.write, setAttribute('on*', ...) 등의 DOM 싱크는 기본적으로 이스케이프하는 textContent 또는 프레임워크 관리 바인딩(React의 JSX, Vue의 머스태치)으로 대체해야 합니다.
- 명명된 참조: WHATWG entities.json에 약 2,231개 항목; 반드시 이스케이프해야 하는 다섯 이름은 & < > " '('는 HTML5/XML 전용, HTML 4.01에서는 비유효)
- 숫자 참조: 십진수 &#DDDDD;와 십육진수 &#xHHHH;는 U+0000부터 U+10FFFF까지 커버; 대체 영역 U+D800-U+DFFF과 U+0000 NULL은 HTML 사양상 비유효
- 이스케이프 순서: &를 먼저 치환해야 하며, 그렇지 않으면 후속 이스케이프의 & 접두사가 이중 인코딩됨; 인코딩은 5개 항목 조회 테이블로 O(n)
- DOMParser를 통한 디코딩: 분리된 요소의 innerHTML에 할당하면 HTML 사양 토크나이저(문자 참조 상태, 13.2.5.72-80절)가 호출되어 끝 세미콜론이 없는 레거시 엔티티도 처리
- 아스트랄 문자 처리: String.prototype.codePointAt와 for...of 순회를 사용하여 이모지 및 CJK 확장 B 문자(U+10000 이상)가 단일 &#NNNNN;으로 변환되도록 함
- 컨텍스트별 이스케이프(OWASP XSS 방어 치트 시트 규칙 #0): HTML 본문, HTML 속성, JavaScript, CSS, URL 각각 다른 이스케이프 필요; HTML 엔티티만으로는 JS 또는 URL 싱크에서 XSS를 막을 수 없음
- 심층 방어: Content-Security-Policy script-src 'self'(RFC 스타일), DOMPurify 화이트리스트 살균, 바닐라 DOM 코드에서 innerHTML 대신 textContent/innerText 사용
예시
기본 요소 인코딩
입력: <script>alert(1)</script>
출력: <script>alert(1)</script>
용도: 사용자가 입력한 내용을 렌더링할 때 브라우저가 실제 태그로 해석하지 않도록 방지속성 값 인코딩
입력: <div title="Hello & world">
출력: <div title="Hello & world">
참고: 속성 내부의 따옴표와 앰퍼샌드를 엔티티로 인코딩하여 값이 따옴표 밖으로 빠져나가지 못하게 함페이지 내 URL 표시
입력: search?q=hello&lang=en
출력: search?q=hello&lang=en
용도: URL을 HTML에 삽입하기 전 페이지에서 &를 인코딩해야 하며, 그렇지 않으면 파서가 뒷부분을 잘못된 엔티티로 처리할 수 있음비-ASCII 문자 (전체 인코딩)
입력: 中文 같은 CJK 문자
출력: 완전한 UTF-8 숫자 형태 中文 (페이지가 지원하면 명명된 엔티티 사용)
용도: 레거시 HTML에 임의의 유니코드를 안전하게 임베드; 최신 페이지는 보통 UTF-8을 그대로 사용자주 묻는 질문
HTML 인코딩은 어떤 문자를 변환하나요?
다섯 개의 SGML 예약 문자입니다: & → &, < → <, > → >, " → ", ' → '(또는 '). 추가로, UTF-8을 처리하지 못하는 구형 시스템을 위해 ASCII 외 문자를 숫자 엔티티(&#xNN;)로 변환하는 옵션도 있습니다.
HTML 인코딩이 필요한 상황은 언제인가요?
사용자 입력 텍스트를 HTML에 삽입할 때마다 필요합니다. 인코딩을 누락하는 것이 XSS 취약점의 근본 원인입니다. HTML 본문, 속성 값, JavaScript 컨텍스트, CSS 컨텍스트, URL 컨텍스트 각각에 맞게 인코딩하세요. 컨텍스트마다 규칙이 조금씩 다릅니다.
'와 '의 차이는 무엇인가요?
둘 다 작은따옴표를 출력합니다. '는 HTML5에서 추가됐지만 HTML4와 일부 구형 이메일 클라이언트에서는 유효하지 않습니다. 출력이 오래된 시스템에서 읽힐 수 있다면 '를 사용하세요. 본 도구는 호환성을 최대로 하기 위해 기본적으로 '를 출력합니다.
출력 결과에 여전히 &가 남아 있는 이유가 무엇인가요?
입력에 이미 & 같은 HTML 엔티티가 들어 있었다면 인코딩 결과로 &amp;가 나오는 게 정상입니다. 입력 속의 앰퍼샌드를 엔티티가 아니라 문자 그대로의 &로 보았기 때문입니다. 원본이 이미 엔티티 인코딩되어 있다면 먼저 디코딩하세요.
이모지도 변환되나요?
이모지는 유효한 유니코드이며 최신 HTML은 일반 문자처럼 처리하므로, 시스템이 ASCII만 허용하지 않는 한 별도의 인코딩이 필요 없습니다. ASCII 외 문자에 대한 숫자 엔티티 변환을 켜면 &#xNNNN; 형식으로 바꿀 수 있습니다.
HTML 인코딩과 URL 인코딩은 같은 건가요?
아니요. URL 인코딩(퍼센트 인코딩)은 URL에서 사용할 수 없는 문자를 %NN 시퀀스로 바꿉니다. HTML 인코딩은 HTML에서 사용하기 위해 명명된 엔티티나 숫자 엔티티로 바꿉니다. 컨텍스트에 맞는 인코딩을 사용하세요. 둘을 섞으면 이중 인코딩 버그가 생깁니다.
변환은 로컬에서 이루어지나요?
네. 인코딩과 디코딩 모두 브라우저 안에서 처리되며 붙여 넣은 텍스트는 업로드되지 않습니다.