어떤 문자가 문제를 일으키는 건 분명하다고 생각하지만, 데이터 구조나 프로토콜 설계자가 모든 종류의 문자(심지어 적절히 이스케이프된 것조차)를 임의로 허용하지 않으려는 경향을 가지는 게 최악의 시나리오라는 느낌임. 예를 들어, 사용자명 유효성 검사는 다른 레이어에서 처리해야 한다고 봄. 사용자명을 60자 미만, 이모지나 zalgo 문자 금지, 널 바이트 금지 등으로 체크하고 API에서 적절한 에러를 반환하는 작업임. JSON 파싱 단계에서 사전 유효성 검증 대신 이런 문제로 실패하길 원치 않음. 물론 사용자명에는 특정 문자 클래스가 분명히 부적절함. 하지만 탭 문자 등이 실제로 사용되는 텍스트 파일을 전송한다면 내 언어의 utf8 "string" 타입에서 처리 가능한 것은 인코딩 가능하길 기대함. 특히 널 바이트의 용례가 많으며, 실제로 JSON에서 종종 보임. 하지만 제한된 "정상" 유니코드 집합만 써야 한다면 표준이 존재하는 것이 각자 미니 표준 만드는 것보다는 낫다고 생각함. 결론적으로 아이디어 자체는 좋아 보이나, 블로그 글에서 든 논리는 잘 납득이 안됨
2025년 기준, 로우 레벨 와이어 프로토콜에서 쓸 문자열 표현 방식은 아래 중 하나만 실질적으로 옹호 가능하다는 생각임
"Unicode Scalars"(잘 구성된 UTF-16, 파이썬 문자열 타입)
"잠재적으로 잘못된 UTF-16"(WTF-8, 자바스크립트 문자열 타입)
"잠재적으로 잘못된 UTF-8"(바이트 배열, Go 문자열 타입)
위 방식 중 하나에 "U+0000 없음" 옵션 추가(버퍼 오버플로우 취약점 이전에 설계된 언어/라이브러리 연동 시)
진지하게 말하면, 프레인 텍스트 파일에서 C0(줄바꿈과, 마지못해 HT 제외) 및 C1 문자를 사용하지 않았으면 함. ANSI 컬러 마크업 같은 걸 저장하고 싶어하는 건 이해하지만, 이런 경우 실제로는 플레인 텍스트가 아니라 일종의 텍스트 마크업 포맷임. 마크다운과 유사하지만, C0 범위의 인코딩을 쓴다는 점만 다름. 데이터가 'cat' 명령어 등으로 예쁘게 보인다는 이유만으로 플레인 텍스트라고 말할 수는 없음. 프레인 텍스트로 인코딩된 마크업 포맷이 상호 운영성 때문에 많다는 점은 인지함
데이터 구조와 프로토콜에서 임의 문자군을 금지하기 시작하는 게 최악이라는 의견 자체가 현실과 동떨어진 사고방식이라고 봄. 진짜 최악은 파서 등 소프트웨어 결함으로 보안 침해가 발생하는 것임
사용자명에 UTF-8을 허용하는 시스템이 있는지 의문임. 프로그래밍적으로 조작되거나 평가되는 모든 식별자(로그인 사용자명, 비밀번호 등)는 반드시 ASCII여야 한다는 게 당연함. ISO-8859-1도 아니고, 오직 ASCII만 사용해야 함. 유니코드로는 이런 용도에 맞지 않음. 사용자명을 띄우는 경우 등에서는 상관없겠지만, 시스템 로그인의 식별자로서는 비-ASCII 인코딩은 무조건 금지임. 키보드 소프트웨어조차 ASCII를 벗어나면 시각적 표현에 대해 UTF-8의 일관성을 자장 담보할 수 없으며, 운영체제와 설정에 따라 더 혼란스러움. 앞으로 남겨질 바이너리와 유니코드 해석 AI가 일치한다는 보장도 없음. 또한 일관성 관련해서, IVS 상황이나 정규화(NFC/NFD/NFKC/NFKD) 문제를 명확하게 범위 내/외로 다루는지 RFC 9839도 기사도 명확하지 않음. 목적 섹션이 아예 빠져 있는 것 같음. 대략적으로 "비문자 코드 포인트"가 있다는 식의 모호한 언급만 있음
사용자명에서 왜 이모지를 금지해야 하는지 궁금함
IETF가 2025년까지 Bad Unicode 지원을 기다린 게 아니란 점을 말하고 싶음. 이미 예전부터 RFC 8264: PRECIS Framework에서 다양한 Bad Unicode 문제를 광범위하게 다룸. RFC 8265(링크), 8266(링크) 등 관련 RFC도 참고하면 도움됨. 일반적으로, 텍스트 방향을 바꾸거나 입력 기기마다 다르게 인코딩될 수 있는 비밀번호 등은 사용자명/패스워드에 쓰이면 안됨. 이러한 RFC 프로필을 통해 안전하게 대응 가능함. 이런 목적에서는 "failing closed"(더 엄격하게 차단)가 더 안전함. 새로운 이모지가 나온다고 해도, 사용자명에서 허용해서 모든 페이지에 영향을 주는 것보다는 차라리 금지하고 보수적으로 가는 걸 선호함
그래도 너무 닫힌 상태로 두면 20년 뒤에도 20년 전 이모지가 아직도 미지원 상태로 남게 되어 결국 사용자 불만만 커짐
Unicode는 "좋은" 부분이 분명 있지만, 예외적으로 제외해야 할 문자가 있음을 알아야 한다는 점이 실망 스러움. 언어 기록 방식을 포괄적으로 받아들이려다 너무 복잡해진 결과임. 어느 문자가 특별 취급되어야 한다는 점을 항상 생각해야 해서 피곤함. 그래서 Unicode 문자열은 독자적인 데이터 단위라고 생각해서 다룸. 입력 받고, 저장하고, 렌더링, 데이터 동등성 비교는 해도, 내용에 대해 해석하려 들지는 않음. 심지어 문자열을 이어붙이거나 다루는 것도 불안함
Unicode는 끝없는 트리비아와 나쁜 결정의 심연 같음. 예를 들어, 관련 RFC에서 구식 ASCII 제어 문자(표시 혼동 우려) 경고는 있지만, Explicit Directional Overrides 같은 치명적인 보안 문제가 있는 방향 전환 문자는 아무런 언급이 없음
간단한 예시로, 첫 번째 문자열이 고아 이모지 수정자로 끝나고 두 번째가 수정 가능한 이모지로 시작하면 이미 문제 발생임. 더 복잡한 케이스가 늘어날수록 문제만 커짐
복잡성이 크긴 하지만, 이런 것 중 서러게이트와 제어 코드는 언어 기록 목적이 아니라 이상한 설계가 과거를 위해 남겨진 결과임
Unicode가 불편하지만, 기존 다른 인코딩 표준보다는 덜 불편하다고 생각함
대부분의 문제는 유효하지 않은 UTF-8 바이트 시퀀스를 거부하거나 전체적으로 에러 반환하도록 처리하면 된다고 생각함. 예를 들어, 서러게이트 등은 원래 UTF-8에서 불법이기에, utf-8을 쓰는 언어라면 이런 시퀀스에 대해 에러를 반환해야 함. 실제로 문제가 되는 건 "코드 포인트"로 문제적인(non-printing, 등) 것들이라고 봄. 이건 불법 바이트 시퀀스와는 분명히 별도의 개념으로 다뤄야 더 유용함
충분히 합리적이라고 생각함. 이런 선택은 애플리케이션 구현자 몫이지, 범용 라이브러리에서 정할 사안이 아니라고 봄. 사용자명만 다루는 JSON 파서 같은 건 본 적이 없음
Unicode는 이미 각 코드 포인트의 범주(General Category)를 정의해서 이상한 문자 종류를 분류함. 관련 위키백과 문서를 참고할 수 있음. 예로, 파이썬에서 unicodedata.category(chr(0))은 "Cc"(control), unicodedata.category(chr(0xdead))은 "Cs"(surrogate)를 리턴함
모든 "legacy control" 문자를 리터럴 뿐만 아니라 이스케이프 문자열(e.g., "\u0027")까지 제외하는 건 과하다고 생각함. C1은 잘 안 쓰이니 괜찮지만, C0 문자 일부는 실사용 예제가 있음. escape, EOF, NUL 등은 명확한 쓰임새가 남아 있다고 봄
좀 특이한 C0 문자(U+001E Record Separator 등)는 데이터 스트림에서 쓸모가 많다고 생각함. 문서엔 막더라도, 스트림 데이터엔 유용함
프로그램 소스 코드에서 form feed(U+000C) 문자 쓰인 걸 봄. Emacs는 페이지 단위 내비게이션용으로 원래 지원하니, 이런 게 포함되곤 함
Unicode가 좋다고 생각하지 않음. 문자 집합이 무엇이든 실제로 쓸 문자종류(제어 문자, 그래픽 문자, 최대 길이 등)는 결국 각 어플리케이션에 맞게 결정해야 함. JSON 등에서 포함/제외를 시도해도 별 효과가 없음. 유니코드든 ASCII든 다른 문자셋이든 특정 서브셋(혹은 superset)에 이름 붙이는 게 때론 유용할 수는 있지만, 모두에게 좋은 선택이라 착각하면 안 됨. RFC 9839는 몇몇 유니코드 서브셋에 이름 붙이긴 하지만, 내가 만들 서비스에 무조건 옳다는 보장은 없음. 내 결론은 유니코드를 아예 쓰지 않거나 강제하지 않는 것도 고려해봐야 함
실제 문제는 조합 문자(combining character)임. 이 때문에 유니코드는 문자 집합에서 문자 묘사용 DSL로 바뀌었음
입력을 제어할지, 아니면 신뢰할 수 없는 입력에 대해 안전하게 출력하는 데이터타입(web+log+debug용)으로 감쌀지 고민임
한 그래픽 유닛에 들어갈 수 있는 유니코드 스칼라 값 개수에 대한 제한이 표준에 있었으면 함. 마지막으로 봤을 때(몇 년 전이지만) 표준에는 그런 제한이 없었고, 대신 스트리밍 애플리케이션에서는 그래픽 유닛을 128바이트로 제한하라는 권고만 있었음. 이런 한계를 표준에 명확히 두면 구현이 훨씬 쉬워지고 불필요한 제약도 없으리라 생각함
실제로 "제어 문자가 없디"라는 전제만으로 프로그램을 짜서 깨지는 케이스 겪었음(폼 피드는 페이지 구분 등, escape 문자는 터미널 용도 등으로 흔히 쓰임). "전부 UTF-8임"이라는 가정도 깨지곤 함(오래된 데이터 파일, 로그 등). 텍스트로 유의미한 처리를 안 한다면, 그냥 바이트 시퀀스로 내용 변경 없이 넘기는 게 제일 좋음. 하지만 Microsoft Windows로 인해 가끔 char16_t 시퀀스를 넘겨야만 할 때도 있음. UTF-16은 UTF-8과 입출력이 근본적으로 다름. 변환할 때는 외부 데이터 → 내부 형태 전환시 WTF-8(UTF-16), 서러게이트 이스케이프(UTF-8) 방식을 각각 써야 함. 두 방식 혼합은 불가함
Hacker News 의견
어떤 문자가 문제를 일으키는 건 분명하다고 생각하지만, 데이터 구조나 프로토콜 설계자가 모든 종류의 문자(심지어 적절히 이스케이프된 것조차)를 임의로 허용하지 않으려는 경향을 가지는 게 최악의 시나리오라는 느낌임. 예를 들어, 사용자명 유효성 검사는 다른 레이어에서 처리해야 한다고 봄. 사용자명을 60자 미만, 이모지나 zalgo 문자 금지, 널 바이트 금지 등으로 체크하고 API에서 적절한 에러를 반환하는 작업임. JSON 파싱 단계에서 사전 유효성 검증 대신 이런 문제로 실패하길 원치 않음. 물론 사용자명에는 특정 문자 클래스가 분명히 부적절함. 하지만 탭 문자 등이 실제로 사용되는 텍스트 파일을 전송한다면 내 언어의 utf8 "string" 타입에서 처리 가능한 것은 인코딩 가능하길 기대함. 특히 널 바이트의 용례가 많으며, 실제로 JSON에서 종종 보임. 하지만 제한된 "정상" 유니코드 집합만 써야 한다면 표준이 존재하는 것이 각자 미니 표준 만드는 것보다는 낫다고 생각함. 결론적으로 아이디어 자체는 좋아 보이나, 블로그 글에서 든 논리는 잘 납득이 안됨
2025년 기준, 로우 레벨 와이어 프로토콜에서 쓸 문자열 표현 방식은 아래 중 하나만 실질적으로 옹호 가능하다는 생각임
진지하게 말하면, 프레인 텍스트 파일에서 C0(줄바꿈과, 마지못해 HT 제외) 및 C1 문자를 사용하지 않았으면 함. ANSI 컬러 마크업 같은 걸 저장하고 싶어하는 건 이해하지만, 이런 경우 실제로는 플레인 텍스트가 아니라 일종의 텍스트 마크업 포맷임. 마크다운과 유사하지만, C0 범위의 인코딩을 쓴다는 점만 다름. 데이터가 'cat' 명령어 등으로 예쁘게 보인다는 이유만으로 플레인 텍스트라고 말할 수는 없음. 프레인 텍스트로 인코딩된 마크업 포맷이 상호 운영성 때문에 많다는 점은 인지함
데이터 구조와 프로토콜에서 임의 문자군을 금지하기 시작하는 게 최악이라는 의견 자체가 현실과 동떨어진 사고방식이라고 봄. 진짜 최악은 파서 등 소프트웨어 결함으로 보안 침해가 발생하는 것임
사용자명에 UTF-8을 허용하는 시스템이 있는지 의문임. 프로그래밍적으로 조작되거나 평가되는 모든 식별자(로그인 사용자명, 비밀번호 등)는 반드시 ASCII여야 한다는 게 당연함. ISO-8859-1도 아니고, 오직 ASCII만 사용해야 함. 유니코드로는 이런 용도에 맞지 않음. 사용자명을 띄우는 경우 등에서는 상관없겠지만, 시스템 로그인의 식별자로서는 비-ASCII 인코딩은 무조건 금지임. 키보드 소프트웨어조차 ASCII를 벗어나면 시각적 표현에 대해 UTF-8의 일관성을 자장 담보할 수 없으며, 운영체제와 설정에 따라 더 혼란스러움. 앞으로 남겨질 바이너리와 유니코드 해석 AI가 일치한다는 보장도 없음. 또한 일관성 관련해서, IVS 상황이나 정규화(NFC/NFD/NFKC/NFKD) 문제를 명확하게 범위 내/외로 다루는지 RFC 9839도 기사도 명확하지 않음. 목적 섹션이 아예 빠져 있는 것 같음. 대략적으로 "비문자 코드 포인트"가 있다는 식의 모호한 언급만 있음
사용자명에서 왜 이모지를 금지해야 하는지 궁금함
IETF가 2025년까지 Bad Unicode 지원을 기다린 게 아니란 점을 말하고 싶음. 이미 예전부터 RFC 8264: PRECIS Framework에서 다양한 Bad Unicode 문제를 광범위하게 다룸. RFC 8265(링크), 8266(링크) 등 관련 RFC도 참고하면 도움됨. 일반적으로, 텍스트 방향을 바꾸거나 입력 기기마다 다르게 인코딩될 수 있는 비밀번호 등은 사용자명/패스워드에 쓰이면 안됨. 이러한 RFC 프로필을 통해 안전하게 대응 가능함. 이런 목적에서는 "failing closed"(더 엄격하게 차단)가 더 안전함. 새로운 이모지가 나온다고 해도, 사용자명에서 허용해서 모든 페이지에 영향을 주는 것보다는 차라리 금지하고 보수적으로 가는 걸 선호함
Unicode는 "좋은" 부분이 분명 있지만, 예외적으로 제외해야 할 문자가 있음을 알아야 한다는 점이 실망 스러움. 언어 기록 방식을 포괄적으로 받아들이려다 너무 복잡해진 결과임. 어느 문자가 특별 취급되어야 한다는 점을 항상 생각해야 해서 피곤함. 그래서 Unicode 문자열은 독자적인 데이터 단위라고 생각해서 다룸. 입력 받고, 저장하고, 렌더링, 데이터 동등성 비교는 해도, 내용에 대해 해석하려 들지는 않음. 심지어 문자열을 이어붙이거나 다루는 것도 불안함
Unicode는 끝없는 트리비아와 나쁜 결정의 심연 같음. 예를 들어, 관련 RFC에서 구식 ASCII 제어 문자(표시 혼동 우려) 경고는 있지만, Explicit Directional Overrides 같은 치명적인 보안 문제가 있는 방향 전환 문자는 아무런 언급이 없음
간단한 예시로, 첫 번째 문자열이 고아 이모지 수정자로 끝나고 두 번째가 수정 가능한 이모지로 시작하면 이미 문제 발생임. 더 복잡한 케이스가 늘어날수록 문제만 커짐
복잡성이 크긴 하지만, 이런 것 중 서러게이트와 제어 코드는 언어 기록 목적이 아니라 이상한 설계가 과거를 위해 남겨진 결과임
Unicode가 불편하지만, 기존 다른 인코딩 표준보다는 덜 불편하다고 생각함
대부분의 문제는 유효하지 않은 UTF-8 바이트 시퀀스를 거부하거나 전체적으로 에러 반환하도록 처리하면 된다고 생각함. 예를 들어, 서러게이트 등은 원래 UTF-8에서 불법이기에, utf-8을 쓰는 언어라면 이런 시퀀스에 대해 에러를 반환해야 함. 실제로 문제가 되는 건 "코드 포인트"로 문제적인(non-printing, 등) 것들이라고 봄. 이건 불법 바이트 시퀀스와는 분명히 별도의 개념으로 다뤄야 더 유용함
Unicode는 이미 각 코드 포인트의 범주(General Category)를 정의해서 이상한 문자 종류를 분류함. 관련 위키백과 문서를 참고할 수 있음. 예로, 파이썬에서
unicodedata.category(chr(0))은 "Cc"(control),unicodedata.category(chr(0xdead))은 "Cs"(surrogate)를 리턴함모든 "legacy control" 문자를 리터럴 뿐만 아니라 이스케이프 문자열(e.g., "\u0027")까지 제외하는 건 과하다고 생각함. C1은 잘 안 쓰이니 괜찮지만, C0 문자 일부는 실사용 예제가 있음. escape, EOF, NUL 등은 명확한 쓰임새가 남아 있다고 봄
좀 특이한 C0 문자(U+001E Record Separator 등)는 데이터 스트림에서 쓸모가 많다고 생각함. 문서엔 막더라도, 스트림 데이터엔 유용함
프로그램 소스 코드에서 form feed(U+000C) 문자 쓰인 걸 봄. Emacs는 페이지 단위 내비게이션용으로 원래 지원하니, 이런 게 포함되곤 함
Unicode가 좋다고 생각하지 않음. 문자 집합이 무엇이든 실제로 쓸 문자종류(제어 문자, 그래픽 문자, 최대 길이 등)는 결국 각 어플리케이션에 맞게 결정해야 함. JSON 등에서 포함/제외를 시도해도 별 효과가 없음. 유니코드든 ASCII든 다른 문자셋이든 특정 서브셋(혹은 superset)에 이름 붙이는 게 때론 유용할 수는 있지만, 모두에게 좋은 선택이라 착각하면 안 됨. RFC 9839는 몇몇 유니코드 서브셋에 이름 붙이긴 하지만, 내가 만들 서비스에 무조건 옳다는 보장은 없음. 내 결론은 유니코드를 아예 쓰지 않거나 강제하지 않는 것도 고려해봐야 함
입력을 제어할지, 아니면 신뢰할 수 없는 입력에 대해 안전하게 출력하는 데이터타입(web+log+debug용)으로 감쌀지 고민임
한 그래픽 유닛에 들어갈 수 있는 유니코드 스칼라 값 개수에 대한 제한이 표준에 있었으면 함. 마지막으로 봤을 때(몇 년 전이지만) 표준에는 그런 제한이 없었고, 대신 스트리밍 애플리케이션에서는 그래픽 유닛을 128바이트로 제한하라는 권고만 있었음. 이런 한계를 표준에 명확히 두면 구현이 훨씬 쉬워지고 불필요한 제약도 없으리라 생각함
실제로 "제어 문자가 없디"라는 전제만으로 프로그램을 짜서 깨지는 케이스 겪었음(폼 피드는 페이지 구분 등, escape 문자는 터미널 용도 등으로 흔히 쓰임). "전부 UTF-8임"이라는 가정도 깨지곤 함(오래된 데이터 파일, 로그 등). 텍스트로 유의미한 처리를 안 한다면, 그냥 바이트 시퀀스로 내용 변경 없이 넘기는 게 제일 좋음. 하지만 Microsoft Windows로 인해 가끔 char16_t 시퀀스를 넘겨야만 할 때도 있음. UTF-16은 UTF-8과 입출력이 근본적으로 다름. 변환할 때는 외부 데이터 → 내부 형태 전환시 WTF-8(UTF-16), 서러게이트 이스케이프(UTF-8) 방식을 각각 써야 함. 두 방식 혼합은 불가함