OPEN HYPER STEP
← 목록으로 (stack-analysis)
STACK-ANALYSIS · 104 / 120
stack-analysis
CHAPTER 104 / 120
읽기 약 2
FUNCTION

CSP(Content Security Policy) 완벽 설정


핵심 개념

CSP 디렉티브·nonce·report-uri·실전 정책 — XSS 95% 방어.

본문

CSP 기본 디렉티브

📋 코드 (12줄)
default-src 'self'              # 모든 리소스 기본값
script-src 'self'                # JS 출처
style-src 'self' 'unsafe-inline' # CSS 출처
img-src 'self' data: https:      # 이미지
font-src 'self'                  # 폰트
connect-src 'self' wss:          # XHR·WebSocket
frame-src 'none'                 # iframe
object-src 'none'                # plugin (deprecated)
base-uri 'self'                  # base 태그
form-action 'self'               # form 제출 대상
frame-ancestors 'none'           # 부모 frame (clickjacking)
upgrade-insecure-requests        # http → https 자동

Next.js CSP 적용

TYPESCRIPT📋 코드 (29줄)
// next.config.js
const ContentSecurityPolicy = `
  default-src 'self';
  script-src 'self' 'unsafe-eval' 'unsafe-inline' https://www.googletagmanager.com https://www.google-analytics.com;
  style-src 'self' 'unsafe-inline';
  img-src 'self' blob: data: https:;
  font-src 'self' https://fonts.gstatic.com;
  connect-src 'self' https://www.google-analytics.com https://api.example.com wss://realtime.example.com;
  frame-src 'self' https://www.youtube.com;
  frame-ancestors 'none';
  base-uri 'self';
  form-action 'self';
  upgrade-insecure-requests;
`.replace(/\s{2,}/g, ' ').trim();


module.exports = {
  async headers() {
    return [{
      source: '/(.*)',
      headers: [
        { key: 'Content-Security-Policy', value: ContentSecurityPolicy },
        { key: 'X-Frame-Options', value: 'DENY' },
        { key: 'X-Content-Type-Options', value: 'nosniff' },
        { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
      ],
    }];
  },
};

Nonce — 인라인 스크립트 안전하게

TYPESCRIPT📋 코드 (38줄)
// middleware.ts
import { NextResponse } from 'next/server';

export function middleware(request: NextRequest) {
  const nonce = Buffer.from(crypto.randomUUID()).toString('base64');

  const csp = `
    default-src 'self';
    script-src 'self' 'nonce-${nonce}' 'strict-dynamic';
    style-src 'self' 'unsafe-inline';
  `.replace(/\s{2,}/g, ' ').trim();

  const requestHeaders = new Headers(request.headers);
  requestHeaders.set('x-nonce', nonce);

  const response = NextResponse.next({ request: { headers: requestHeaders } });
  response.headers.set('Content-Security-Policy', csp);
  return response;
}


// app/layout.tsx
import { headers } from 'next/headers';

export default async function RootLayout({ children }) {
  const nonce = (await headers()).get('x-nonce');

  return (
    <html>
      <head>
        <Script id="ga" nonce={nonce}>{`
          // 인라인 스크립트 안전
        `}</Script>
      </head>
      <body>{children}</body>
    </html>
  );
}

CSP Report-Only (먼저 모니터링)

TYPESCRIPT📋 코드 (26줄)
headers: [{
  key: 'Content-Security-Policy-Report-Only',
  value: `${ContentSecurityPolicy}; report-to csp-endpoint`,
}, {
  key: 'Reporting-Endpoints',
  value: 'csp-endpoint="/api/csp-report"',
}]


// API
app.post('/api/csp-report', async (req, res) => {
  const report = req.body;
  await db.cspViolation.create({
    data: {
      blockedUri: report['blocked-uri'],
      violatedDirective: report['violated-directive'],
      sourceFile: report['source-file'],
      lineNumber: report['line-number'],
      ip: req.ip,
    },
  });
  res.status(204).end();
});


// → 1주일 모니터 → 정책 조정 → enforce 모드 전환

일반적인 CSP 함정

📋 코드 (17줄)
1. 'unsafe-inline' 남발
   → nonce/hash로 점진 제거

2. 'unsafe-eval' 필요
   → modern build로 제거 (eval 안 쓰는 라이브러리)

3. data: URI 너무 광범위
   → 이미지만 허용, 스크립트 차단

4. * (any) 사용
   → 명시적 화이트리스트


5. localhost 개발 vs 프로덕션 분리
const csp = process.env.NODE_ENV === 'production'
  ? STRICT_CSP
  : DEV_CSP;

추가 보안 헤더

TYPESCRIPT📋 코드 (20줄)
{
  // Clickjacking 방어
  key: 'X-Frame-Options', value: 'DENY',

  // MIME type sniffing 방어
  key: 'X-Content-Type-Options', value: 'nosniff',

  // Referrer 정보 제한
  key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin',

  // 권한 정책 (Camera·Microphone 등)
  key: 'Permissions-Policy',
  value: 'camera=(), microphone=(), geolocation=(self), payment=()',

  // CORP (Cross-Origin Resource Policy)
  key: 'Cross-Origin-Resource-Policy', value: 'same-origin',

  // COOP (Cross-Origin Opener Policy)
  key: 'Cross-Origin-Opener-Policy', value: 'same-origin',
}

검증 도구

📋 코드 (11줄)
1. SecurityHeaders.com
   - 헤더 점수 (A+ 목표)

2. Mozilla Observatory
   - https://observatory.mozilla.org

3. CSP Evaluator (Google)
   - https://csp-evaluator.withgoogle.com

4. report-uri.com
   - CSP 위반 수집·시각화

다음 챕터

CH.105 "SQL Injection 방어".


AI 프롬프트
🤖 AI에게 잘 물어보는 법 — 모델·전략별 프롬프트
Claude

무료: Sonnet 4.6 / Pro $20/mo: Opus 4.6

내 코드의 CSP 보안 부분을 분석해서
실전 분석 + 개선 우선순위를 알려줘.
ChatGPT

무료: GPT-5.5 / Plus $20/mo: GPT-5.5 Pro

CSP 보안 관련 베스트 프랙티스 5가지를
비교 분석해서 패턴 추출를 알려줘.
Gemini

무료: 2.5 Flash / Pro $19.99/mo: 3.1 Pro

내 프로젝트 전체에서 CSP 보안
최적화 가능 위치를 보고해줘.
Grok

무료: Grok 4.1 / SuperGrok $30/mo

2026년 한국 시장의 CSP 보안
트렌드를 솔직히 알려줘.

⭐ 이것만 기억하세요
CSP(Content Security Policy) 완벽 설정 이 3가지만 확실히 잡으세요
1.CSP는 XSS 95% 방어 — Report-Only로 1주 모니터 후 enforce
2.nonce + strict-dynamic = 인라인 스크립트 안전
3.추가 헤더 (X-Frame, Permissions-Policy 등) 7종 필수


공유하기
진행도 104 / 120