HTML 엔티티는 파서가 잘못 해석할 수 있는 문자를 HTML에서 표현하는 메커니즘입니다. 태그를 시작하는 것으로 잘못 해석되는 꺾쇠 괄호, 다른 엔티티의 시작으로 잘못 해석되는 앰퍼샌드, 인코딩 변환으로 손실될 수 있는 비 ASCII 문자가 대상입니다. 엔티티를 잘못 처리하면 레이아웃 깨짐·문자 깨짐, 최악의 경우 XSS 취약점으로 이어집니다.
HTML 엔티티란
HTML 엔티티는 &로 시작하고 ;로 끝나는 문자열로, 단일 문자를 나타냅니다. 두 가지 형식이 있습니다:
이름 있는 엔티티는 설명적인 키워드를 사용합니다:
< → <
> → >
& → &
" → "
→ (줄 바꿈 없는 공백)
숫자 엔티티는 유니코드 코드 포인트를 10진수 또는 16진수로 사용합니다:
< → < (10진수)
< → < (16진수)
© → ©
© → ©
둘 다 동일한 출력을 생성합니다. 이름 있는 엔티티가 더 읽기 쉽고, 숫자 엔티티는 이름이 없는 문자를 포함한 모든 유니코드 문자에 사용할 수 있습니다.
HTML 엔티티가 중요한 이유
HTML 구조 깨짐 방지
<와 >는 HTML에서 특별한 의미를 갖습니다. 소스 코드 표시 등 리터럴 꺾쇠 괄호를 표시하려면 이스케이프해야 합니다:
<!-- 잘못됨: 브라우저가 불완전한 태그로 파싱 -->
Using <strong> instead of <b> is preferred.
<!-- 올바름 -->
<p>Using <strong> instead of <b> is preferred.</p>
XSS 취약점 방지
사용자가 입력한 콘텐츠를 HTML에 삽입하기 전에 이스케이프하지 않는 것은 가장 일반적인 웹 보안 버그 중 하나입니다. 사용자가 <script>alert(1)</script>를 입력하고 코드가 그것을 그대로 출력하면, 모든 방문자의 브라우저에서 그 스크립트가 실행됩니다.
<!-- 위험: 사용자 입력을 그대로 출력 -->
<p>Hello, <%= username %></p>
<!-- 안전: HTML 인코딩 -->
<p>Hello, <%= htmlEncode(username) %></p>
HTML에 삽입되는 사용자 입력에 대해 항상 다음 5개 문자를 인코딩하세요:
| 문자 | 엔티티 |
|---|---|
& | & |
< | < |
> | > |
" | " |
' | ' |
문서 문자 세트 외부 문자 표시
UTF-8이 보편화되기 전, ISO-8859-1(Latin-1)로 제공된 문서에서는 ©·€·— 등을 직접 표현할 수 없었고 엔티티가 해결책이었습니다. 오늘날 UTF-8 제공이 표준이지만, 입력하기 어렵거나 텍스트 프로세서에서 제거될 수 있는 문자에는 엔티티가 여전히 유용합니다.
HTML 엔티티 빠른 참조
예약 문자
| 문자 | 이름 | 엔티티 | 숫자 참조 |
|---|---|---|---|
< | 소보다 작음 | < | < |
> | 소보다 큼 | > | > |
& | 앰퍼샌드 | & | & |
" | 큰따옴표 | " | " |
' | 작은따옴표 | ' | ' |
타이포그래피
| 문자 | 이름 | 엔티티 | 용도 |
|---|---|---|---|
| 줄 바꿈 없는 공백 | | 단어 간 줄 바꿈 방지 |
— | 엠 대시 | — | 문장 구분, 범위 |
– | 엔 대시 | – | 숫자 범위(2010–2024) |
… | 말줄임표 | … | 텍스트 잘림 |
" | 왼쪽 큰따옴표 | “ | 인용 |
" | 오른쪽 큰따옴표 | ” | 인용 |
' | 아포스트로피 | ’ | 단축형 |
기호
| 문자 | 이름 | 엔티티 |
|---|---|---|
© | 저작권 | © |
® | 등록 상표 | ® |
™ | 상표 | ™ |
€ | 유로 | € |
£ | 파운드 | £ |
¥ | 엔/위안 | ¥ |
° | 도 | ° |
± | 플러스마이너스 | ± |
× | 곱하기 | × |
÷ | 나누기 | ÷ |
→ | 오른쪽 화살표 | → |
수학 기호
| 문자 | 이름 | 엔티티 |
|---|---|---|
≤ | 이하 | ≤ |
≥ | 이상 | ≥ |
≠ | 같지 않음 | ≠ |
∞ | 무한대 | ∞ |
∑ | 합계 | ∑ |
√ | 제곱근 | √ |
코드로 인코딩·디코딩하기
JavaScript
브라우저 DOM이 HTML 엔티티 인코딩을 처리합니다:
// 인코딩(HTML 이스케이프)
function htmlEncode(str) {
const div = document.createElement('div');
div.appendChild(document.createTextNode(str));
return div.innerHTML;
}
htmlEncode('<script>alert(1)</script>');
// "<script>alert(1)</script>"
// 디코딩(HTML 언이스케이프)
function htmlDecode(str) {
const div = document.createElement('div');
div.innerHTML = str;
return div.textContent;
}
htmlDecode('<b>bold</b>');
// "<b>bold</b>"
Node.js(DOM 없음)에서는 라이브러리를 사용합니다:
npm install he
import he from 'he';
he.encode('<script>alert(1)</script>');
// "<script>alert(1)</script>"
he.decode('<b>bold</b>');
// "<b>bold</b>"
Python
Python 표준 라이브러리로 일반적인 경우를 처리할 수 있습니다:
import html
# 인코딩
html.escape('<script>alert(1)</script>')
# '<script>alert(1)</script>'
# 작은따옴표를 포함하여 인코딩
html.escape("it's a test", quote=True)
# 'it's a test'
# 디코딩
html.unescape('<b>Hello & World</b>')
# '<b>Hello & World</b>'
PHP
// HTML 컨텍스트용 인코딩
htmlspecialchars('<script>alert(1)</script>', ENT_QUOTES, 'UTF-8');
// <script>alert(1)</script>
// 적용 가능한 모든 문자 인코딩
htmlentities('© 2024', ENT_QUOTES, 'UTF-8');
// © 2024
// 디코딩
html_entity_decode('<b>bold</b>', ENT_QUOTES, 'UTF-8');
// <b>bold</b>
인코딩해야 할 때와 하지 않아도 될 때
항상 인코딩: 신뢰할 수 없는 입력(사용자 이름·검색 쿼리·폼 값·API 데이터)을 HTML에 삽입할 때.
이중 인코딩하지 말 것. 콘텐츠가 이미 인코딩되어 있다면(데이터베이스에 <로 저장된 경우), 다시 인코딩하면 &lt;가 되어 < 대신 리터럴 <로 표시됩니다.
비 ASCII 텍스트에는 엔티티 대신 UTF-8 사용. UTF-8로 제공하고 저장하면 ©·€·→를 엔티티 없이 HTML에 직접 사용할 수 있습니다. 레거시나 제한된 환경에서만 엔티티가 필요합니다.
는 아껴 사용. 는 HTML 이메일의 간격 해결책이나 줄 바꿈 방지에 자주 사용되지만, 현대 HTML/CSS에서는 white-space: nowrap이나 word-break 속성이 더 유지보수하기 쉽습니다.
빠른 검색 도구
문자의 엔티티를 찾거나 소스 코드에서 발견한 엔티티를 디코딩하려면 전용 인코더/디코더가 가장 빠릅니다. ZeroTool HTML 엔티티 도구 사용해보기 →
HTML 엔티티가 포함된 텍스트를 붙여 넣어 디코딩하거나, 특수 문자를 입력·붙여 넣어 엔티티 표현을 얻을 수 있습니다. 용도:
- CMS 내보내기에서 깨진 HTML 디코딩
- 시각적으로만 알고 있는 기호의 올바른 엔티티 찾기
- 템플릿 이스케이프가 올바르게 작동하는지 확인
정리
HTML 엔티티는 두 가지 중요한 역할을 합니다. HTML 구조를 깨지 않고 예약 문자를 표시하는 것과, 사용자 입력을 이스케이프하여 XSS를 방지하는 것입니다. 현대 UTF-8 문서에서는 이스케이프에 기본적으로 <·>·&·"·'만 필요하며, 나머지 문자 세트는 직접 삽입할 수 있습니다.