Today's AntipatternAll Posts
테마
GitHubToday's AntipatternAll Posts

안티패턴을 통해 더 나은 코드를 작성하는 방법을 배워보세요. 개발자들이 실수하는 패턴들을 분석하고 개선방안을 제시합니다.

연결하기

© 2025 Smelly.dev All rights reserved.

June 25, 2025

innerHTML의 위험한 유혹 🚨

JavaScript
React
보안
성능
UX
컴포넌트

Summary

innerHTML은 XSS 공격에 취약하고 성능 저하를 유발하므로, 안전한 DOM API나 프레임워크 바인딩을 사용해야 합니다.

Why Wrong?

innerHTML 속성을 사용하여 사용자로부터 받은 문자열이나 동적으로 생성된 HTML을 삽입하는 것은 보안 취약점(XSS), 성능 저하, 유지보수 어려움 등의 문제를 일으킬 수 있습니다.

How to Fix?

textContent, createElement, React/Vue 등의 안전한 바인딩 방식을 사용해야 하며, 불가피하게 dangerouslySetInnerHTML을 쓸 때는 검증된 HTML만 사용해야 합니다.

Before Code (Bad)

// HTML
// <div id="comment-section"></div>

// JavaScript - 안전하지 않은 예시
const userInput = "<img src='x' onerror='alert(\"XSS Attack!\")'>";
const commentDiv = document.getElementById('comment-section');

commentDiv.innerHTML = `<p><b>새 댓글:</b> ${userInput}</p>`;

// React (anti-pattern)
// <div dangerouslySetInnerHTML={{ __html: userInput }} />

After Code (Good)

// HTML
// <div id="comment-section"></div>

// JavaScript - 안전한 예시
const userInput = "<img src='x' onerror='alert(\"XSS Attack!\")'>";
const commentDiv = document.getElementById('comment-section');

const pElement = document.createElement('p');
const bElement = document.createElement('b');
bElement.textContent = '새 댓글: ';
pElement.appendChild(bElement);
pElement.appendChild(document.createTextNode(userInput));
commentDiv.appendChild(pElement);

// React - JSX 예시
function CommentDisplay({ commentText }) {
  return (
    <p>
      <b>새 댓글:</b> {commentText}
    </p>
  );
}