개발 이야기

innerHTML은 안전한가?

효빈 2024. 10. 13. 15:48

웹 개발을 하다 보면 DOM을 동적으로 변경해야 할 때가 많습니다. 그중에서 가장 간단하게 사용할 수 있는 방법 중 하나가 innerHTML입니다. 하지만, innerHTML은 편리함과 동시에 몇 가지 중요한 단점이 있어 무조건 사용하기에는 위험한 부분이 있습니다. 이번 글에서는 innerHTML의 단점과 이를 대체할 수 있는 안전하고 효율적인 방법들을 소개하겠습니다.

 

1. 보안 취약성: XSS 공격의 위험

innerHTML의 가장 큰 단점 중 하나는 XSS(Cross-Site Scripting) 공격에 취약하다는 점입니다. 사용자가 입력한 데이터를 검증 없이 innerHTML에 삽입하면, 악의적인 코드가 HTML에 포함되어 실행될 수 있습니다.

<div id="content"></div>

<script>
  const userInput = "<script>alert('XSS 공격');</script>";
  document.getElementById('content').innerHTML = userInput;  // XSS 공격이 가능해짐
</script>

 

이 코드를 실행하면, <script> 태그 안의 악성 코드가 실행되어 보안 문제를 일으킬 수 있습니다.

이러한 경우에는 innerHTML 대신, textContent 또는 innerText를 사용하면, HTML 태그를 실행하지 않고 텍스트로만 처리할 수 있어 XSS 공격을 방지할 수 있습니다.

const userInput = "<script>alert('XSS 공격');</script>";
document.getElementById('content').textContent = userInput;  // 태그가 실행되지 않음

 

2. 성능 문제: DOM 재렌더링의 부담

innerHTML을 사용하면 요소의 내용을 변경할 때 전체 DOM을 다시 파싱하고 렌더링해야 하기 때문에, 대규모 DOM 구조에서는 성능 저하가 발생할 수 있습니다. 특히, 많은 양의 데이터를 반복적으로 삽입하거나 업데이트하는 경우에는 이 문제가 두드러집니다.

 

이때에는, DOM 조작 메서드를 사용하면 성능 최적화가 가능합니다. createElement, appendChild, insertBefore 같은 메서드를 통해 필요한 부분만 업데이트하면 전체 DOM을 다시 렌더링 할 필요가 없습니다.

const newDiv = document.createElement('div');
newDiv.textContent = "Hello World!";
document.getElementById('content').appendChild(newDiv);

 

3. 이벤트 핸들러 손실 문제

innerHTML로 DOM을 업데이트할 경우, 해당 요소에 이미 바인딩된 이벤트 핸들러가 제거될 수 있습니다. 예를 들어, 기존에 클릭 이벤트가 바인딩된 버튼이 있을 때 innerHTML로 그 요소를 업데이트하면, 클릭 이벤트가 사라지게 됩니다.

 

대체 방식으로는, DOM API를 사용하여 요소를 직접 수정하거나 추가하는 방법이 있습니다. DOM API를 사용하면 기존의 이벤트 핸들러가 유지됩니다.

또한, 더 복잡한 이벤트 핸들링이 필요한 경우 Virtual DOM을 사용하는 React나 Vue 같은 프레임워크를 고려해볼 수 있습니다. 이러한 프레임워크는 이벤트 핸들러를 안전하게 유지하면서 DOM 업데이트를 효율적으로 처리해 줍니다.

 

4. 복잡한 HTML 구조의 유지보수 문제

innerHTML을 사용하여 긴 HTML 문자열을 삽입하는 경우, 코드의 가독성이 떨어지고 유지보수가 어려워집니다. HTML과 자바스크립트가 섞이면서 코드가 복잡해지고 실수할 가능성이 커집니다.

 

이 경우에는, 템플릿 리터럴을 사용하면 복잡한 HTML 구조도 가독성을 유지하면서 삽입할 수 있습니다. 템플릿 리터럴을 사용하면 자바스크립트 내에서 HTML을 직관적으로 구성할 수 있어 유지보수가 수월합니다.

const content = `
  <div>
    <h1>Welcome!</h1>
    <p>This is a dynamically generated paragraph.</p>
  </div>
`;
document.getElementById('content').innerHTML = content;

 

템플릿 리터럴을 사용하면 코드의 구조를 더 명확하게 만들 수 있습니다. 다만, 여전히 XSS 공격의 위험이 있으므로 데이터가 사용자 입력에서 온 경우라면 innerHTML 대신 textContent를 사용하는 것이 좋습니다.

 

innerHTML은 간편하게 사용할 수 있는 도구이지만, 보안과 성능, 유지보수 측면에서 적절한 대체 방안을 사용하는 것이 중요합니다. 작은 텍스트 조작에는 textContentinnerText를, 복잡한 DOM 조작에는 createElement와 같은 DOM API를 사용하는 것이 좋습니다. 또한, 규모가 큰 프로젝트나 복잡한 이벤트 처리가 필요한 경우에는 React나 Vue와 같은 프레임워크를 사용하는 것도 좋은 선택입니다.