#문제 발견 |
[ 링크가 걸린 문자를 클릭하여 접속한 상태. ]
자주 애용하는 사이트 중 하나를 돌아다니던 중, 문자열이 깨지는 사태가 발생.
[ 링크가 걸린 문자에 마우스를 올려놓은 상태. ]
해당 링크가 걸려있는 부분에 마우스를 올려보니,
UTF-8 코딩이 되어있지 않은채 그대로 문자열이 삽입되어 있었다.
위의 경우 익플이 아닌 파폭이나 크롬의 경우 자동적으로 UTF-8 변환해주지만
익플의 경우 특별한 설정을 하지 않으면, 자동적으로 변환되지 않는다.
< Internet Explorer 쿼리문을 자동적으로 UTF-8 변환 전송 방법 >
[ 익스플로어 인터넷 옵션 도구 탭 ]
위 그림의 빨간색 네모칸이 그려져 있는 부분이 체크되어 있는 상태에서 한번 재부팅하면 적용된다.
|
인터넷 옵션으로 간단하게 처리하면 되는데, '이걸 자바스크립트에서 어떻게 변환하는가 ?' 에
관심을 갖은게 문제의 발단이 되었다 -_- . . .
이의 해결책중 하나라 encodeURIComponent 함수를 쓰면 된다는 구글형님의 조언을 듣고
당장 실행에 옮기기로 했다.
# 과정 |
|
[ 실험할 웹페이지 소스 ]
[ 실험할 웹페이지 ]
[ 실행한 결과 ]
음 ? ? ? 뭔가 이상하다.
해당 웹페이지 소스 문자열은 UTF-8 로 적혀있고 정상적으로 출력되면
%[Hex] 로 출력될 문자열은 많아야 12개정도 나와야 한다.
( 한글 문자당 3bytes 라고 생각했을때 )
그런데, 위 화면에선 24개로 나오는거로 봐선 인코딩 상에 문제가 있다는걸 어렴풋 생각해볼 수 있다.
[ 웹 페이지 인코딩 ]
여기서 기본 인코딩(한국어)를 UTF-8로 바꾸면
[ 웹 페이지 인코딩 방식 변환 (한국어->UTF-8) ]
정상적으로 출력되는걸 확인할 수 있다.
이 경우 페이지의 meta contents charset 을 utf-8 을 명확히 기재하지 않은 잘못이 있는데
그렇다면, encodeURIComponent 함수 내부에선 어떻게 해석하기에 위와 같은 기묘한 결과를 내는걸까 ?
직접적으로 디버깅해보지 않아 아래의 답이 명확하다고 답하기 힘들지만 추측으로는 아래와 같다.
< 가정 1 > Windows 기준으로 메시지를 출력하기 위해선 MessageBox 함수를 호출할 필요성이 있는데 이를 Ansi 함수로 작성하게 되면, 한국어 외 타언어를 출력할 시 문자가 깨지는 사태가 발생하므로 MessageBox는 반드시 '유니코드' 로 호출할 것이다.
< 추측 흐름 > 01. 문자열을 얻어옴.(페이지가 UTF-8의 경우 UTF-8 에 해당하는 문자열 Hex 를 얻어옴.)
02. 해당 문자열(UTF-8)을 페이지 인코딩(한국어)에 맞추어 유니코드로 변환함.
03. 유니코드로 변환된 문자열을 UTF-8 문자열(%[Hex])로 변환시킴.
04. UTF-8 문자열을 다시 페이지 인코딩에 맞추어 유니코드로 변환함.
05. MessageBoxW 을 호출하여 alert 을 호출함.
|
[ encodeURIComponent 으로 문자열을 변환 후 alert 호출까지의 추측 과정 ]
위 과정의 04,05 번의 경우엔 깨질 일이 없으니 01~03번을 기준으로
위 추측을 바탕으로 C언어로 작성해보았다.
[ C언어를 통한 첫번째 실험 소스 및 실행 파일 ]
[ C언어를 통한 첫번째 실험 결과 ]
[ 이전 잘못된 인코딩(한국어)으로 인한 웹페이지 실행한 결과 ]
위 검은색 콘솔창과 잘못된 인코딩으로 출력된 메시지창의 값을 비교해보면
앞부분 3개까진 똑같이 들어간다.
여기서, 추측해볼 수 있는건, 추측과정의 01번하고 03번은 확실하게 맞다는 이야기가 된다.
그럼, 02번의 UTF-8 문자열을 유니코드로 변환시에 문제가 발생하고 있다는 이야기인데
이의 중간 과정을 알아보기 위헤 웹페이지 소스를 바꾸어보기로 했다.
[ 실험할 웹페이지 소스 ]
[ 실험할 웹페이지 ]
[ 실험한 결과 ]
여기서 살펴보기 전에 잠깐 한가지 짚어보자.
위 메시지 창이 추측 과정의 04~05번에 해당하듯, 유니코드가 정상적으로 변환되었으리라 라는 보장은 없다.
(직접 디버깅해보지 않았으니...)
하지만, 한가지 확인으로 신빙성을 조금은 높혀볼 수 있다.
C언어를 통한 실험을 했을 때 03번의 Hex 3개는 정확하게 맞아 들어갔고
이는 02번에 해당하는 유니코드 Hex 값의 2개는 정확하게 맞아 들어간다는 추측을 해볼 수 있다.
( 02번의 Hex 값 앞의 2개는 9B 5A, \u5A9B )
이 추측을 토대로 www.unicode.org 에서 제공하는 code charts 를 확인해보면
[ 유니코드 5A9B ]
비슷하게 생겼다. 이를 통해 신빙성은 조금은 높아졌다. 해볼만한 가치가 있다 !!! (야호!)
여기서, 조금더 분석을 해보기 위해 Alert Test 에 출력된 메시지 박스의 내용을 조금 분석해볼 필요가 있다.
위의 괴상한 문자를 추출해서 핵스로 출력하면 아래와 같은 결과가 나온다.
[ Alert Test 의 메시지 박스 내용을 추출한 문자열의 Hex 값 ]
여기서, 눈치 게임이 시작되는데, 뭔가 특정 패턴이 보인다.
Hex 문자열 사이에 'FD FF' 라는게 좀 많이 보인다.
이걸 분석해볼 가치가 있는가는 일단 추출한 Hex 문자열을 UTF-8 로 변환시켜볼 필요성이 있다.
[ 추출한 Hex 값의 내용을 UTF-8로 변환 ]
[ 이전 잘못된 인코딩(한국어)으로 인한 웹페이지 실행한 결과 ]
충분한 가치가 있다 !!!
(완전히 똑같다.)
IE 내부에선 어떤식으로 번역하고 있는가 Hex값을 분석해 볼 필요가 있다.
이를 분석하기 위해서 https://msdn.microsoft.com/en-us/goglobal/cc305154 를 참고하였다.
처음, UTF-8 페이지의 '가나다라'에 해당하는 Hex 문자열은
EA B0 80 EB 82 98 EB 8B A4 EB 9D BC |
[ "가나다라" UTF-8 문자열 Hex ]
이와 같다. 이를 MultiByteToWideChar 을 통해 처리하게 되면
(EA B0) (80) (EB 82) (98 EB) (8B A4) (EB 9D) (BC 00) |
[ MultiByteToWideChar 의 유니코드 인코딩 번역 방법 ]
위와 같이 처리되어, 위 msdn 페이지의 표에 없는 문자는 그 문자 그대로 2bytes 를 출력하고
( 예를 들어, 80 같은 경우, 80 00 와 같이 2bytes 를 사용한다. )
표에는 번호가 있으나 내부에 문자가 없는 경우엔 2bytes 로 3F 00 값을 가진 '?' 를 넣게 된다.
[ C언어를 통한 첫번째 실험 결과 ]
이를 기준으로 분석해보면 얼추 맞게 들어가고 있다는 이야기가 된다.
하지만, IE은 이와 같이 해석하지 않는다.
다시, msdn 을 통해 분석해보면
(EA B0) (80 (EB) (82) 98) (EB (8B) A4) (EB (9D) BC) |
[ encodeURIComponent 의 유니코드 인코딩 번역 방법 ]
이와 같이 해석하게 되는데 이렇게 보면 보기 힘드므로 아래의 표와 같이 순서를 작성했다.
01. EA B0 |
[ encodeURIComponent 의 유니코드 인코딩 번역 방법 순서 ]
x 라고 표기된 부분은 해석 실패로 'FD FF' Hex 값을 갖게 되는 부분이다.
[ Alert Test 메시지 내용에서 추출한 Hex 값의 내용을 UTF-8로 변환 ]
위 내용을 분석한 바탕으로 C언어로 작성하게 되면
[ C언어를 통한 마지막 실험 소스 및 실행 파일 ]
[ C언어를 통한 마지막 실험 실행 결과 ]
[ 이전 잘못된 인코딩(한국어)으로 인한 웹페이지 실행한 결과 ]
똑같이 맞아 떨어지는 것을 확인할 수 있다.
# 결론 |
추측컨데, 이 문제는 encodeURIComponent 함수만이 아닐 것으로 보인다.
encodeURIComponent 와 같은 문자열을 다루는 함수를 사용시 조금 주의할 필요성이 있다고 본다.
네○파라 vol.0 암호화 루틴 (0) | 2015.08.20 |
---|---|
if 와 매크로와 세미콜론의 위험성. (0) | 2015.07.27 |
미연시계의 횡포. 2***AME (0) | 2015.05.08 |
엔스크립트에 대해서 잠깐 분석해봄. (0) | 2015.05.01 |
네○파라 vol.1 암호화 루틴 (2) | 2014.12.31 |
|
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |