← 모두의 툴

SVG 미리보기에서 script 태그가 실행 안 되는 이유 — img+Blob 방식의 안전장치

가이드 · 2026-08-19 최종 확인

SVG는 이미지 포맷이면서 동시에 XML 문서입니다. 그리고 XML 문서 안에는 <script> 태그와 onload, onclick 같은 이벤트 핸들러 속성을 넣을 수 있습니다. 즉 SVG 파일 하나가 사실상 작은 웹페이지처럼 동작할 수 있다는 뜻이고, 이건 출처를 모르는 SVG를 함부로 열었을 때 실제로 악용될 수 있는 잘 알려진 XSS(크로스사이트 스크립팅) 공격 벡터입니다. 그런데 이 사이트의 SVG 뷰어를 포함한 대부분의 안전한 SVG 미리보기 도구는 스크립트가 든 SVG를 붙여넣어도 아무 일도 일어나지 않습니다. 왜 그럴까요?

1. SVG는 원래 스크립트를 실행할 수 있는 포맷이다

브라우저 주소창에 SVG 파일을 직접 열거나, HTML 문서 안에 <object>·<iframe>·<embed> 태그로 SVG를 삽입하면, 그 SVG는 완전한 독립 문서(document context)로 취급됩니다. 이 경우 내부의 <script> 태그와 이벤트 핸들러가 그대로 실행됩니다. 마찬가지로 SVG 마크업 문자열을 innerHTML로 DOM에 직접 삽입해도 스크립트가 실행됩니다. 사용자가 붙여넣은 SVG 코드를 이런 방식으로 렌더링하는 도구는 그 자체로 XSS 공격에 노출됩니다.

2. 이 도구가 쓰는 방어 기법: img + Blob

이 사이트의 SVG 뷰어는 입력된 코드를 먼저 DOMParser로 파싱해 문법 오류(<parsererror>)가 있는지 검사합니다. 파싱에 성공하면, 원본 코드 문자열을 그대로 Blob(MIME 타입 image/svg+xml)으로 감싸고, URL.createObjectURL()로 만든 임시 URL을 <img> 태그의 src에 넣어 표시합니다. 핵심은 여기에 있습니다 — 브라우저는 <img> 태그로 로드된 리소스를 "정적 이미지 컨텍스트"로 취급하도록 스펙에 정의돼 있고, 이 컨텍스트에서는 그 이미지가 SVG(XML)라 하더라도 내부의 스크립트나 이벤트 핸들러가 절대 실행되지 않습니다. 이건 우연히 그렇게 동작하는 게 아니라, 브라우저 벤더들이 의도적으로 정한 보안 경계입니다.

왜 안전한가: <img src="blob:...">로 불러온 SVG는 렌더링(모양을 그리는 것)만 되고, 그 안의 코드가 "실행"되는 문서 컨텍스트 자체가 아예 생성되지 않습니다. img로 SVG를 로드하는 것은 사실상 png·jpg 같은 래스터 이미지를 로드하는 것과 동일한 보안 취급을 받습니다.

3. 반대로 위험한 방식들

렌더링 방식스크립트 실행 여부
<img src="..."> (Blob URL / data URI)❌ 실행 안 됨 — 안전
element.innerHTML = svgCode✅ 실행됨 — 위험
<object data="..." type="image/svg+xml">✅ 실행됨 — 위험
<iframe src="...">✅ 실행됨 — 위험 (단, cross-origin 격리는 있음)
CSS background-image: url(...)❌ 실행 안 됨 — 안전

<object>·<iframe>은 SVG를 완전한 독립 문서로 취급하기 때문에 스크립트가 살아납니다. 반면 <img>와 CSS background-image는 SVG를 순수한 그림으로만 취급합니다. 사용자가 업로드하거나 붙여넣은 SVG를 미리보기로 보여줘야 하는 웹서비스를 만든다면, 반드시 <img> 방식을 써야 합니다.

4. 줌 기능이 화질 저하 없이 동작하는 이유(덤)

이 도구의 줌 기능은 이미지를 다시 렌더링하는 게 아니라 CSS transform:scale()로 이미 표시된 요소를 확대·축소합니다. SVG는 픽셀이 아니라 수학적 경로(path)로 정의된 벡터 포맷이라, 4배까지 확대해도 래스터 이미지처럼 계단현상(pixelation)이 생기지 않고 선명하게 유지됩니다.

5. 인라인 SVG가 꼭 필요한 경우엔?

애니메이션 상호작용이나 CSS 스타일링이 SVG 내부 요소 단위로 필요해서 어쩔 수 없이 인라인으로 삽입해야 하는 경우도 있습니다. 이럴 땐 img 방식을 포기하는 대신, DOMPurify 같은 라이브러리의 SVG 프로필(USE_PROFILES: {svg: true})로 <script>·이벤트핸들러·<foreignObject> 등 위험 요소를 제거한 뒤 삽입하는 방식이 표준적인 대안입니다.

자주 묻는 질문

Q. SVG 안에 스크립트 태그가 있으면 실행되나요?

A. 이 도구에서는 실행되지 않습니다. 파싱에 성공한 코드를 Blob으로 감싸 <img> 태그의 src로 표시하는데, 브라우저는 이미지로 로드된 SVG의 스크립트와 이벤트 핸들러를 원천적으로 차단합니다.

Q. CSS 애니메이션이나 SMIL 애니메이션이 든 SVG도 재생되나요?

A. 네. img 태그로 표시되는 SVG는 스크립트만 차단될 뿐, CSS 애니메이션과 SMIL(<animate> 등) 애니메이션은 이미지 자체의 렌더링 기능이라 정상적으로 재생됩니다.

Q. 그럼 이 방식이면 100% 안전한가요?

A. 스크립트 실행이라는 관점에서는 안전합니다. 다만 img+Blob 방식이 XSS는 막아주지만, 외부 리소스를 참조하는 SVG(<image xlink:href="외부URL"> 등)의 경우 그 리소스 요청 자체는 발생할 수 있어, 극도로 민감한 서비스라면 별도의 콘텐츠 검증이 추가로 필요할 수 있습니다.

Q. innerHTML로 SVG를 넣는 도구는 다 위험한가요?

A. 사용자가 직접 입력한 SVG를 검증·정화(sanitize) 없이 innerHTML로 그대로 삽입하는 도구라면 위험합니다. 다만 서비스가 자체 생성한(사용자 입력이 섞이지 않은) SVG를 삽입하는 경우라면 위험이 없습니다 — 위험은 "신뢰할 수 없는 입력"을 그대로 실행 가능한 컨텍스트에 넣을 때 발생합니다.