Next에서 CSP 설정 방법 2가지

제리추·2024년 5월 28일
1
post-thumbnail

프론트엔드 보안을 공부하는 중에 클릭재킹을 방지하기 위해 CSP 설정을 하는 방법을 찾아보았습니다.

들어가기 앞서 클릭재킹이 궁금하시다면 이 포스트를 참고해주세요.

🐹들어가기 앞서

1) 클릭재킹이란?

사용자의 의도와 다르게 버튼과 링크를 클릭해 의도하지 않은 처리를 실행하게 하는 해킹 방식입니다.

2) 클릭재킹의 구조

  1. 공격 대상의 웹 애플리케이션 페이지를 iframe을 사용해 피싱 사이트와 중첩합니다.
  2. CSS를 사용해 iframe이 보이지 않게 만듭니다.
  3. 피싱 사이트 상의 버튼 위치와 공격 대상의 페이지에서 중요한 기능이 중첩되도록 CSS 조정합니다.
  4. 피싱 사이트에 접속한 사용자가 피싱 사이트에서 버튼을 클릭하도록 유도합니다.
  5. 사용자가 피싱 사이트에서 버튼을 클릭해도 실제로는 투명하게 겹쳐진 공격 대상의 페이지 버튼이 클릭하게 만듭니다.

3) CSP란?

  • CSP는 웹 애플리케이션의 보안 강화를 위한 보안 정책을 의미합니다. CSP를 사용하면 웹 페이지의 리소스 로딩 및 실행에 대한 제한을 설정해 악성 스크립트 실행을 방지하고 XSS 및 기타 웹 공격을 예방 가능합니다.

  • CSP frame-ancestors (프레임 내부에 삽입을 제한)
    Content-Security-Policy : frame-ancestors ‘none’ : 모든 출처의 프레임 내부에 삽입을 제한
    Content-Security-Policy : frame-ancestors ‘self’ : 동일 출처의 내부에 삽입을 허가합니다.
    Content-Security-Policy : frame-ancestors uri : 출처를 지정한 것만 허가합니다.

🐹 Next에서 클릭재킹 방지하는 2가지 방법

1. Meta 태그를 통해 CSP 설정하기

// ** /login/layout.tsx **
import { Metadata } from 'next';

export const metadata: Metadata = {
  title: 'LoginPage',
  description: '로그인 페이지',
  other: {
    'http-equiv': 'Content-Security-Policy',
    content:
      "default-src 'self' 'unsafe-eval' 'unsafe-inline' https:; img-src 'self' data: blob: https:; font-src 'self' data: https:;",
  },
};

const LoginLayout = ({ children }: { children: React.ReactNode }) => {
  return <section>{children}</section>;
};

export default LoginLayout;

CSP-Meta-tag-image

  • layout의 metadata의 other를 통해 CSP를 설정합니다. 위 사진을 보면 잘 적용된 것을 볼 수 있습니다. 이렇게 설정했을 경우 네트워크 탭에서 확인이 불가능하며 html 태그를 통해 확인이 가능합니다.

  • 메타 태그로 설정된 CSP는 보안 수준이 HTTP 헤더로 설정된 CSP보다는 낮을 수 있지만, 웹 애플리케이션의 보안을 강화하는 것에 도움이 됩니다. 가능하다면 HTTP 응답 헤더를 통해 CSP를 설정하는 것이 메타 태그를 통해 설정하는 것 보다 안전한 방법입니다.

그렇다면 meta 태그보다 HTTP 헤더로 설정하는 이유가 무엇일까요?

  1. 우선 순위: 브라우저는 HTTP 응답 헤더에 설정된 CSP를 <meta> 태그에 설정된 CSP보다 우선적으로 적용합니다.
  2. 일관성: HTTP 응답 헤더를 통해 설정된 CSP는 모든 HTML 문서와 관련된 리소스에 적용되므로, 보안 정책을 일관되게 적용할 수 있습니다.
  3. 보안 강화: HTTP 응답 헤더로 CSP를 설정하면, 초기 HTML 로드 이전에 CSP가 적용되므로 보안이 강화됩니다. <meta> 태그는 HTML 문서의 일부분으로 로드되기 때문에, 잠재적으로 CSP가 로드되기 전에 발생할 수 있는 공격을 막지 못할 수 있습니다.

2. Next.js에서 HTTP 응답 헤더로 CSP 설정 방법

// ** next.config.js **

const { createVanillaExtractPlugin } = require('@vanilla-extract/next-plugin');
const withVanillaExtract = createVanillaExtractPlugin();

/** @type {import('next').NextConfig} */
const nextConfig = {
  async headers() {
    return [
      {
        source: '/login',
        headers: [
          {
            key: 'Content-Security-Policy',
            value:
              "default-src 'self' 'unsafe-eval' 'unsafe-inline' https:; img-src 'self' data: blob: https:; font-src 'self' data: https:;",
          },
        ],
      },
    ];
  },
};

module.exports = withVanillaExtract(nextConfig);![](https://velog.velcdn.com/images/jerrychu/post/c4c6156f-2ba9-4af5-8e3c-2bb8a11a75e1/image.png)
  • Next.js 프로젝트인 경우 위와 같이 next.config.js 파일을 이용해서 응답 헤더를 설정 가능합니다. 또한 HTTP를 header를 통해 CSP를 설정하게 된다면 meta 태그를 통해 중복 설정할 필요가 없습니다.

마무리

  • CSP는 웹 애플리케이션의 보안을 강화하는데 도움을 주는 도구입니다. 적절한 CSP 정책을 설정하면 웹 페이지의 취약성을 줄이고, 사용자 데이터 안정성을 보장할 수 있습니다.
profile
안녕하세요. 소프트웨어 엔지니어 제리입니다 🐹

2개의 댓글

comment-user-thumbnail
2024년 8월 23일

안녕하세요~ 블로그 글을 보고 해당 공격이 있는지, 또 CSP 개념이 뭔지 알 수 있게 되어 감사합니다!
궁금한 점이 있는데, 예시에서 CSP 헤더 값으로 unsafe-eval이나 unsafe-inline 같은 것들을 설정하면 보안 상 위험할 거 같은데도 설정하신 이유가 있을까요? 일반적으로 권장되는 게 아니라 사용하시는 도메인 내에서 해당 설정이 필요하셔서 넣으신 건지 궁금합니다!

1개의 답글