프론트엔드에서 대비할 수 있는 보안 전략

배성규·2025년 5월 20일
2

최근 다양한 기업의 보안 사고를 접하면서 프론트엔드 개발자로서도 보안에 대한 고민이 필요하다고 느꼈습니다. 사용자 입력 처리, 인증 등에서 취약점이 발생할 수 있는 만큼, 주요 공격 유형과 대응 전략을 정리해보았습니다.

1. XSS (Cross-Site Scripting)

공격자가 웹사이트에 악성 스크립트 삽입하여 사용자의 브라우저에서 악성 스크립트가 실행되도록 하는 공격 기법입니다.

예를 들어 아래와 같은 입력값은 사용자 브라우저에서 의도치 않은 스크립트를 실행시킬 수 있습니다.

  • <script>alert("XSS");</script>
  • <img src = '#' onerror='alert('XSS');"/>
  • <a href = 'javascript:alert('XSS')'>XSS</a>

🛡 React는 기본적으로 XSS를 방지합니다

최신 브라우저 환경에서는 대부분 막힌 공격 기법이며 리액트의 경우 jsx에서 모든 값을 자동으로 이스케이프하여 기본적인 XSS를 방지합니다.

const userInput = '<script>alert('XSS');</script>

function MyComponent() {
 	return <div>{userInput}</div> 
}

해당 코드는 입력값을 HTML로 해석하지 않고 단순 텍스트로 처리합니다. 따라서 브라우저에서는 문자 그대로 표시되어 스크립트가 실행되지 않습니다.

⚠️ dangerouslySetInnerHTML 사용 시 주의

직접 HTML을 삽입하고자 하는 경우에는 dangerouslySetInnerHTML 프로퍼티를 사용합니다.
이름부터 사용에 주의해야하는 것만큼 해당 프로퍼티를 사용하는 경우 dompurify와 같은 라이브러리를 적용하여 보안 문제에 대비하는 것이 좋습니다.

function Component() {
  const htmlContent = {__html:"<p>의도한 삽입</p>"}; 
  return <div dangerouslySetInnerHTML = {htmlContent} />;                     
            
}

📜 콘텐츠 보안 정책 (Content Security Policy)

브라우저 단에서 악성 스크립트 실행을 방지하기 위해 CSP 헤더 설정도 고려할 수 있습니다.
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com;

2. CSRF (Cross-Site Request Forgery)

사용자가 인증된 상태임을 악용하여 사용자의 의지와 무관하게 서버에 요청을 보내는 공격 기법입니다.
-> 로그인된 상태에서 사용자가 악성 웹사이트를 방문하여 악성 코드가 실행되면 사용자의 브라우저를 통해 사용자의 쿠키 등의 세션 정보를 사용하여 웹사이트에 요청을 보냅니다.
-> 서버는 사용자가 요청을 보낸 것으로 생각하고 처리합니다.

2-1. CSRF 토큰 사용

백엔드에서 발급한 CSRF 토큰을 HTML의 태그로 전달하고, 프론트엔드에서 이를 요청 시 헤더에 포함시켜 방어할 수 있습니다.

프론트엔드에서는 토큰을 쿠키나 로컬스토리지에서 꺼내 헤더에 넣는 작업을 합니다.

<!-- index.html -->
<meta name="csrf-token" content="random-token-value">
// API 요청 시 CSRF 토큰 포함
// 서버는 이 토큰을 검증함으로 요청의 출처가 올바른지 확인할 수 있습니다. 
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');

fetch('/api/transfer-money', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-CSRF-Token': csrfToken
  },
  body: JSON.stringify({ amount: 1000, to: 'account123' })
});

2-2. SameSite 쿠키 속성 활용

브라우저가 쿠키를 타 도메인 요청에 자동으로 전송하지 않도록 하는 방식입니다.

  • SameSite = Strict
    쿠키가 현재 사이트와 동일한 사이트에서 시작한 요청에만 전송됩니다.

  • SameSite = Lax
    Strict보다는 약간 완화된 설정입니다. 링크 클릭, 메서드 폼 제출 등 안전하다고 판단되는 일부 최상위 레벨 탐색 시에는 다른 사이트에서 요청되었더라도 쿠키를 전송합니다.

  • SameSite=None;Secure
    모든 요청에 쿠키를 전송합니다. Secure 속성을 함께 사용하여 https에서만 쿠키를 전송하도록 제한합니다.

3. 토큰 / API 키 노출 방지

프론트엔드에서 .env 파일은 빌드 시점에 클라이언트 번들에 포함됩니다. 민감한 정보는 절대 포함하면 안됩니다.

  • 비공개 API 키
  • 관리자 계정의 비밀번호
  • 데이터베이스 접속 정보

서비스의 기본 URL, 구글 맵과 같은 서비스의 제한된 프론트용 키 등의 값만 포함하여 사용하도록 합니다.

4. 마무리

프론트엔드는 사용자와 직접 닿아있는 영역인 만큼 보안에 대한 작은 실수 하나가 전체 시스템을 위협할 수 있습니다. 이 외에도 https 강제화, 패키지 취약점 점검, x-frame-options 등도 함께 고려해볼 수 있습니다.

혹시 추가하고 싶은 보안 전략이나 실무 경험이 있으면 댓글로 같이 공유해주시면 좋을 것 같습니다!

profile
FE 유망주🧑‍💻

12개의 댓글

comment-user-thumbnail
2025년 5월 24일

CORS와 같은 브라우저 정책도 보안 정책인 것 같은데 추가 어떠신가영

1개의 답글
comment-user-thumbnail
2025년 5월 24일

React가 기본적으로 XSS를 방지한다는게 신기한데요? 쿠키 사용할 때 SameSite로 애먹은 적이 있어 재밌게 읽었습니다🌟

1개의 답글
comment-user-thumbnail
2025년 5월 25일

보안 이슈를 방지하는 방법들이 다양하네요! 잘 몰랐던 내용이 있어서 재밌게 읽었습니다 ㅎㅎ

1개의 답글
comment-user-thumbnail
2025년 5월 27일

사소하다고 생각하면, 넘길 수 있는 부분인데 중요한 것들이네요~!
좋은 글 공유 감사합니다!

1개의 답글
comment-user-thumbnail
2025년 5월 30일

FE도 보안에서 자유롭지 않다는 거 다시 한 번 깨달았습니다. 잘 정리된 글 감사합니다 🙏
혹시 실무에서는 dangerouslySetInnerHTML 사용이 꼭 필요한 상황이 있었을까요? 저는 아직 실제로 써본 적은 없어서 사용하는 상황이 궁금하네요~!

1개의 답글
comment-user-thumbnail
2025년 5월 31일

react에서 에디터를 구현하고 그것을 보여줄 때 dangerouslySetInnerHTML 를 사용했던 기억이 있네요. side effect를 막는 처리를 했었는데 정확히 기억이 안나는군요 ㅎㅎ 재밌게 잘 읽었습니다.

답글 달기
comment-user-thumbnail
2025년 6월 1일

보안에 대해서 깊게 고려하지 못하고 넘어가게 되는데 다시 정리해주셔서 감사합니다!
잘 몰랐던 내용도 있고 공유해주신 키워드들 통해서 더 찾아봐야겠네요 공유 감사합니다!

답글 달기