하이퍼텍스트 마크업 언어(HTML)는 1991년부터 사용되었지만, 1997년 12월의 HTML 4.0은 문자를 합리적으로 완전하게 처리한 최초의 표준화된 버전이다. HTML 문서에 7비트 ASCII 범위를 벗어나는 특수 문자가 포함될 때 고려할 두 가지 목표는 정보의 인티그리티와 범용 브라우저 표시이다.
문서의 문자 인코딩 지정
문서에서 사용되는 문자 인코딩을 지정하는 두 가지 일반적인 방법이 있다.
첫째, 웹 서버는 하이퍼텍스트 전송 프로토콜(HTTP)의 `Content-Type` 헤더에 문자 인코딩 또는 "charset"을 포함할 수 있으며, 일반적으로 다음과 같이 표시된다.[1]
Content-Type: text/html; charset=utf-8
이 방법은 HTTP 서버가 콘텐츠 협상에 따라 문서의 인코딩을 변경할 수 있는 편리한 방법을 제공한다. 특정 HTTP 서버 소프트웨어는 이를 수행할 수 있으며, 예를 들어 Apache는 mod_charset_lite모듈을 통해 가능하다.[2]
XHTML 문서는 세 번째 옵션으로 XML 선언을 통해 문자 인코딩을 표현할 수 있으며, 다음과 같다.[4]
<?xml version="1.0" encoding="utf-8"?>
이 두 번째 접근 방식에서는 선언이 파싱되기 전까지 문자 인코딩을 알 수 없기 때문에, 선언 자체까지 문서에 사용된 문자 인코딩을 아는 데 문제가 있다. 문자 인코딩이 ASCII 확장인 경우 선언 자체까지의 내용은 순수 ASCII여야 하며 올바르게 작동한다. UTF-16BE 및 UTF-16LE와 같이 ASCII 확장이 아닌(즉, ASCII의 상위 집합이 아닌) 문자 인코딩의 경우, 웹 브라우저와 같은 HTML 프로세서는 휴리스틱을 사용하여 일부 경우에 선언을 파싱할 수 있어야 한다.
인코딩 감지 알고리즘
HTML5부터 권장되는 문자 집합은 UTF-8이다.[3] 문서의 문자 인코딩을 결정하기 위해 여러 입력 소스를 기반으로 하는 "인코딩 스니핑 알고리즘"이 사양에 정의되어 있다:
특정 바이트 값 시퀀스 또는 범위를 찾기 위한 문서 바이트 분석,[5] 및 기타 잠정적인 감지 메커니즘.
인쇄 가능한 ASCII 범위(32~126) 밖의 문자는 보통 잘못 표시된다. 이는 영어 사용자를 위한 몇 가지 문제를 야기하지만, 다른 언어는 정기적으로—어떤 경우에는 항상—그 범위를 벗어나는 문자를 필요로 한다. 중국어, 일본어, 한국어(한중일 문자) 언어 환경에서는 여러 가지 다른 멀티바이트 인코딩이 사용되고 있어 자동 감지도 자주 사용된다. 마지막으로, 브라우저는 보통 사용자가 잘못된 문자 집합 레이블을 수동으로 재정의할 수 있도록 허용한다.
다국어 웹사이트와 비서구권 언어 웹사이트에서 모든 언어에 동일한 인코딩을 사용할 수 있도록 UTF-8을 사용하는 것이 점점 더 일반화되고 있다. 모든 언어에 사용할 수 있는 UTF-16 또는 UTF-32는 바이트 지향 ASCII 상위 집합 인코딩을 가정하는 프로그래밍 언어에서 처리하기 어렵고, HTML 문서의 경우와 같이 ASCII 문자의 빈도가 높은 텍스트에는 효율성이 떨어지기 때문에 널리 사용되지 않는다.
페이지가 성공적으로 표시되는 것이 반드시 인코딩이 올바르게 지정되었음을 나타내는 것은 아니다. 페이지 작성자와 독자 모두 특정 플랫폼별 문자 인코딩을 가정하고 서버가 식별 정보를 보내지 않으면, 독자는 작성자가 의도한 대로 페이지를 볼 수 있지만, 다른 플랫폼이나 다른 모국어를 사용하는 다른 독자는 의도한 대로 페이지를 볼 수 없다.
허용되는 인코딩
최근 HTML 표준(현재 WHATWG HTML Living Standard, 그리고 이전에 경쟁했던 W3C HTML 5.0 및 5.1)에서 참조되는 WHATWG Encoding Standard는 브라우저가 지원해야 하는 인코딩 목록을 지정한다. HTML 표준은 다른 인코딩의 지원을 금지한다.[6][7][8] Encoding Standard는 또한 새로운 형식, 새로운 프로토콜(기존 형식이 사용되는 경우에도), 새로운 문서 작성자는 UTF-8만을 사용해야 한다고 규정한다.[9]
UTF-8 외에 다음 인코딩은 Encoding Standard를 참조하여 HTML 표준 자체에 명시적으로 나열되어 있다.[8]
↑호환성을 위해 0xA3A0이 이데오그래픽 스페이스 (U+3000)의 중복 인코딩으로 지정되며, 따라서 U+E5E5 (개인 사용 문자)를 제외한다.[10][11] 또한 0x80이 유로 기호 (U+20AC; Windows-936 참조)의 대체 인코딩으로 허용된다.[12] 그 외에는 2005년 표준의 매핑을 따른다.[11]
↑홍콩 보조 문자 집합 변형,[13] 비록 HKSCS 확장(선행 바이트가 0xA1 미만인 확장)의 대부분은 인코더에 포함되지 않고 디코더에만 포함된다.[14]
↑사양은 Shift JIS에 사용된 것과 동일한 인덱스를 사용하며(도달 가능한 범위 내에서), 즉 NEC 확장을 포함한다. 반각 가나는 인코더에 의해 전각으로 변환되지만,[16] 디코더에 의해 이스케이프 시퀀스(ESC 0x28 0x49)를 사용하여 허용된다.[17]Shift Out 및 Shift In (0x0E 및 0x0F)은 공격을 방지하기 위해 완전히 제외된다.[17][18]
↑배포된 콘텐츠와의 호환성을 위해 일반 UTF-16 레이블에도 지정되어 있지만,[21]바이트 순서 표식 (BOM)이 존재할 경우 어떤 레이블보다 우선순위를 갖는다.[22] 디코딩 전용으로 지정됨; UTF-16으로 인코딩된 문서의 양식 제출은 UTF-8로 인코딩되어야 한다.[20]
↑0x00에서 0x7F까지는 U+0000에서 U+007F로, 0x80에서 0xFF까지는 U+F780에서 U+F7FF (사설 사용 영역 범위)로 매핑되어, 코드 포인트의 하위 8비트가 항상 원래 바이트와 일치하도록 한다.[23]
다음 추가 인코딩은 Encoding Standard에 나열되어 있으며, 따라서 해당 인코딩에 대한 지원도 필요하다.[9]
또한 이 표준은 "교체(replacement)" 디코더를 정의하는데, 이는 특정 인코딩으로 레이블이 지정된 모든 콘텐츠를 교체 문자(�)로 매핑하여 전혀 처리하지 않는다. 이는 악의적인 콘텐츠를 숨기기 위해 클라이언트와 서버 간에 지원되는 인코딩의 차이를 악용할 수 있는 공격(예: 사이트 간 스크립팅)을 방지하기 위함이다.[29]ISO-2022-JP 및 UTF-16에도 동일한 보안 문제가 적용되며, 이들도 ASCII 바이트 시퀀스가 다르게 해석될 수 있지만, 이들은 배포된 콘텐츠에서 비교적 더 자주 사용되기 때문에 이러한 접근 방식은 이들에게는 실현 가능하다고 여겨지지 않았다.[30] 다음 인코딩은 이러한 처리를 받는다.[31]
원시 문자 인코딩 외에도 문자는 숫자 문자 참조(십진법 또는 십육진법) 또는 문자 엔티티 참조와 같은 문자 참조로도 인코딩될 수 있다. 문자 엔티티 참조는 때때로 명명된 엔티티 또는 HTML의 HTML 엔티티라고도 불린다. HTML의 문자 참조 사용은 SGML에서 유래한다.
여기서 nnnn은 십진법 형식의 코드 포인트이고, hhhh는 십육진법 형식의 코드 포인트이다. XML 문서에서는 x는 소문자여야 한다. nnnn 또는 hhhh는 몇 자리든 될 수 있으며 선행 0을 포함할 수 있다. hhhh는 대소문자가 혼합될 수 있지만, 대문자가 일반적인 스타일이다.
HTML 문서를 수신하는 웹 브라우저 또는 이메일 클라이언트, 또는 HTML 문서를 작성하는 문서 편집기가 모든 HTML 문자를 렌더링할 수 있는 것은 아니다. 대부분의 최신 소프트웨어는 사용자의 언어에 대한 대부분 또는 모든 문자를 표시할 수 있으며, 렌더링할 수 없는 문자에 대해서는 상자 또는 기타 명확한 표시를 그린다.
0에서 127까지의 코드, 즉 원래의 7비트 ASCII 표준 세트는 대부분의 문자를 문자 참조 없이 사용할 수 있다. 160에서 255까지의 코드는 모두 문자 엔티티 이름을 사용하여 생성할 수 있다. 더 높은 번호의 코드 중 일부만이 엔티티 이름을 사용하여 생성될 수 있지만, 모든 코드는 십진수 문자 참조로 생성할 수 있다.
문자 엔티티 참조는 &name; 형식도 가질 수 있으며, 여기서 name은 대소문자를 구분하는 영숫자 문자열이다. 예를 들어, "λ"는 HTML 문서에서 λ로도 인코딩될 수 있다. <, >, " 및 & 문자 엔티티 참조는 HTML 및 SGML에서 미리 정의되어 있다. 이는 <, >, " 및 &이 이미 마크업을 구분하는 데 사용되기 때문이다. 이는 HTML5 이전에는 XML의 ' (') 엔티티를 포함하지 않았다. 모든 명명된 HTML 문자 엔티티 참조와 도입된 버전 목록은 XML 및 HTML 문자 엔티티 참조 목록을 참조하라.
HTML 문자 참조를 불필요하게 사용하면 HTML 가독성이 크게 떨어질 수 있다. 웹 페이지의 문자 인코딩이 적절하게 선택되면, HTML 문자 참조는 일반적으로 위에서 언급한 마크업 구분 문자 및 몇 가지 특수 문자(또는 UTF-8과 같은 기본 유니코드 인코딩이 사용되는 경우 전혀 필요하지 않음)에만 필요하다. 잘못된 HTML 엔티티 이스케이프는 또한 사이트 간 스크립팅과 같은 주입 공격에 대한 보안 취약점을 열 수 있다. HTML 속성이 인용되지 않은 상태로 남아 있으면, 가장 중요한 공백(예: 공백 및 탭)과 같은 특정 문자는 엔티티를 사용하여 이스케이프되어야 한다. HTML과 관련된 다른 언어는 문자를 이스케이프하는 자체 방법이 있다.
XML 문자 참조
다양한 문자 엔티티 참조가 있는 기존 HTML과 달리, XML에는 미리 정의된 문자 엔티티 참조가 5개뿐이다. 이는 특정 맥락에서 마크업에 민감한 문자를 이스케이프하는 데 사용된다.[32]
다른 모든 문자 엔티티 참조는 사용되기 전에 정의되어야 한다. 예를 들어, XML 문서에서 é(é, 유니코드 U+00E9인 아쿠트 악센트가 있는 라틴 소문자 E를 나타냄)를 사용하면 엔티티가 이미 정의되지 않은 경우 오류가 발생한다. XML은 또한 십육진수 숫자 참조의 x가 소문자여야 한다. 예를 들어 ਛ 대신 ਛ여야 한다. XML 애플리케이션인 XHTML은 XML의 미리 정의된 엔티티와 함께 HTML 엔티티 세트를 지원한다.
↑Fielding, R.; Reschke, J. (June 2014), 〈Content-Type〉, Fielding, R; Reschke, J, 《Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content》, IETF, doi:10.17487/RFC7231, S2CID14399078, 2014년 7월 30일에 확인함