🪢 문자열 이스케이프 / 언이스케이프
HTML 엔티티, JavaScript 문자열, JSON 문자열, Unicode(\uXXXX), URL 형식으로 문자열을 상호 변환합니다.
📖 변환 예
| Format | Raw | Escaped |
|---|---|---|
| HTML | <a> | <a> |
| JS | It's 'ok' | It\'s \'ok\' |
| JSON | tab here | tab\there |
| Unicode | 日本語 | \u65e5\u672c\u8a9e |
| URL | a b&c | a%20b%26c |
📖 자주 걸리는 지점
HTML 엔티티·JavaScript 문자열·JSON·Unicode (\uXXXX)·URL·CSV·SQL·정규식·셸 등 14 가지 형식으로 문자열을 이스케이프 / 언이스케이프합니다. 처리는 브라우저 안에서 끝납니다. 다만 이스케이프는 「문자열을 변환하는 작업」이 아니라 「출력 대상의 문법에 맞추는 작업」입니다 — 이 도구는 당신의 출력 대상을 모르므로 어떤 형식을 골라야 하는지는 판정할 수 없습니다. 그리고 잘못된 형식을 적용하는 것은 아무것도 하지 않는 것보다 나쁜 결과가 됩니다. 안전해진 기분이 드는데 실제로는 지켜지지 않기 때문입니다.
| 사례 | 무슨 일이 일어나는가 | 어떻게 하면 되는가 |
|---|---|---|
| 문맥이 다르면 올바른 이스케이프도 다르다 | 같은 값이라도 놓이는 자리마다 필요한 처리가 다릅니다. <div> 안이라면 엔티티화로 충분하지만 href="..." 안에서는 URL 로서의 타당성도 요구되고, onclick="..." 안에서는 JavaScript 와 HTML 두 층을 동시에 만족시켜야 합니다. 나아가 HTML 이스케이프가 전혀 듣지 않는 문맥도 있습니다 — href 에 javascript: 로 시작하는 값이 들어가면 엔티티화해도 실행되고, <style> 안이나 <script> 안에서 < 는 그저 글자로 취급될 뿐 구문은 열린 채입니다. 「일단 HTML 이스케이프」가 통하지 않는 자리가 있다는 뜻입니다. |
이스케이프는 출력하는 순간에, 템플릿 엔진에게 시키세요. Twig 의 |e('html_attr') / |e('js') / |e('url'), React 의 JSX, Go 의 html/template 처럼 문맥을 지정할 수 있는 구조를 쓰는 것이 정답입니다. 입력 시점에 이스케이프해서 저장하는 설계는 버리세요 — 저장한 값의 출력처가 하나라는 보장은 없고 메일 본문에도 CSV 에도 API 의 JSON 에도 흘러갑니다. 데이터베이스에는 늘 날 값을 넣고, 출력할 때마다 그 자리의 문맥으로 이스케이프한다. 이 원칙 하나로 위에 든 문제는 거의 전부 사라집니다. 이 도구는 그 결과가 맞는지 눈으로 확인하는 자리로 쓰세요. |
이중 이스케이프 (&lt; 가 화면에 나온다) |
화면에 <strong> 나 & 가 그대로 보이는 상태입니다. 원인은 거의 언제나 「두 번 이스케이프했다」는 것이며, 전형은 저장할 때 애플리케이션이 이스케이프하고 표시할 때 템플릿 엔진이 다시 한 번 이스케이프하는 조합입니다. 무서운 점은 이것이 버그로 눈에 띄지 않는다는 것입니다 — 영숫자뿐인 데이터에서는 아무 일도 일어나지 않고 아포스트로피나 & 가 들어간 이름의 행만 깨집니다. 게다가 깨진 데이터는 이미 데이터베이스 안에 있으므로 표시 측을 고쳐도 낫지 않습니다. 반대 방향의 사고도 있습니다: JSON 의 \n 이 한 번 더 이스케이프되어 \\n 이 되고, 줄바꿈이어야 할 것이 화면에 두 글자로 나타나는 경우입니다. |
먼저 어느 쪽에서 이중이 되고 있는지 가려내세요. 데이터베이스의 값을 그대로 여기에 붙여 넣고 「언이스케이프」 방향으로 HTML 을 고릅니다. 여기서 값이 변한다면 저장된 시점에 이미 이스케이프되어 있는 것 — 원인은 입력 측입니다. 변하지 않는다면 이중화는 표시 측에서 일어나고 있습니다. 복구는 한 번만 실행하는 마이그레이션으로 하고 반드시 대상을 좁히세요 (WHERE body LIKE '%&%'). 전체 행에 무조건 html_entity_decode 를 걸면 원래 올바르게 & 라고 쓰고 싶었던 행을 망칩니다. 실행 전에 반드시 백업을 뜨고 건수를 세어 본 뒤에 돌리세요. |
| 이스케이프는 새니타이즈가 아니다 | HTML 이스케이프는 「텍스트로서 안전하게 표시하는」 처리이지 사용자가 쓴 HTML 을 안전하게 그리는 처리가 아닙니다. 리치 텍스트 게시물처럼 태그를 허용하고 싶은 자리에서는 허용할 태그와 속성을 열거하는 새니타이저가 필요합니다. 같은 오해는 다른 형식에도 있습니다. SQL 문자열의 이스케이프 ('') 는 플레이스홀더의 대체가 되지 않습니다 — 테이블명이나 컬럼명, ORDER BY 의 방향, LIKE 의 와일드카드 % 와 _ 는 모두 문자열 이스케이프의 수비 범위 밖입니다. 셸의 따옴표도 마찬가지여서 값이 -rf 처럼 옵션으로 해석되는 상황은 따옴표로 막을 수 없습니다. |
목적마다 쓰는 도구를 바꾸세요. 태그를 허용한다면 전용 새니타이저 (PHP 라면 HTML Purifier, JS 라면 DOMPurify) 를 쓰고 직접 만든 정규식으로 태그를 제거하려 하지 마세요 — 이 방향의 자작은 예외 없이 뚫립니다. SQL 은 항상 플레이스홀더를 쓰고 테이블명이나 정렬 순서처럼 바인딩할 수 없는 부분은 반드시 허용 목록과 대조하세요 (['name','created_at'] 에 포함된 값만 통과). 셸은 인자를 배열로 넘기는 API (execve 계열, Python 의 subprocess.run([...])) 를 쓰고 사용자 입력 앞에 -- 를 두어 옵션 해석을 끊습니다. |
Unicode 이스케이프에는 BMP 바깥이라는 함정이 있습니다. \uXXXX 는 16 비트밖에 표현하지 못하므로 이모지나 일부 한자는 서로게이트 페어로 둘로 갈립니다 — 이모지 한 글자가 \ud83d\ude00 두 개가 된다는 뜻입니다. 여기서 글자 수를 세거나 도중에 자르면 글자가 반으로 갈려 깨집니다. ES6 이후라면 \u{1f600} 이라는 하나짜리 형식을 쓸 수 있습니다. 또 하나, 이 「비 ASCII 가 \uXXXX 로 둔갑하는」 성질은 검증을 방해합니다 — 이 사이트 자신이 템플릿이 JS 용으로 이스케이프한 문자열을 일본어 그대로 grep 해서 「배포되지 않았다」고 두 번 오판했습니다. 올바른 순서는 검색하기 전에 \uXXXX 를 복호하는 것입니다. 마지막으로 하나만 지켜 주세요: 언이스케이프한 문자열을 JSON.parse 이외의 실행계에, 특히 eval 에 넘기지 마세요. 복호는 검사를 위한 조작이지 실행을 위한 조작이 아닙니다.
📖 사용법
-
1
형식과 방향 선택변환 형식(HTML, JavaScript, JSON, Unicode, URL 등)과 방향(이스케이프/언이스케이프)을 선택하세요.
-
2
텍스트 입력왼쪽 입력란에 텍스트를 붙여넣거나 입력하세요. 실시간으로 변환됩니다.
-
3
결과 복사 또는 교체오른쪽 결과를 복사하거나 ⇄ 버튼으로 입출력을 바꿔 반대 방향으로 변환하세요.
❓ 자주 묻는 질문
HTML 이스케이프와 URL 인코딩의 차이는 무엇인가요?
일본어 등 비 ASCII 문자도 이스케이프할 수 있나요?
SQL 인젝션 방지에 이 도구를 사용할 수 있나요?
🐛 이 도구에서 문제가 발생했나요?
무료 · 가입 불필요. 재현 절차만이라도 도움이 됩니다. 보고는 운영자에게 직접 전달되어 개선에 사용됩니다.
보고 감사합니다!
운영자에게 전달되었습니다. 개선에 사용됩니다.