웹취약 점검사이트에서 점수는 무시하고 넘어갔는데
천천히 보니 보안상에도 문제가 있을 것 같아 CSP설정을 nginx와 php내부에서 하게되었다.
웹 보안 점검(SecurityHeaders, CSP 검사 사이트 등)을 돌리다 보면 CSP(Content Security Policy) 항목에서 자주 감점을 맞는다.
- CSP가 없다
- CSP가 unsafe-inline을 사용하고 있다
- CSP 헤더를 파싱할 수 없다
처음에는 “점수 문제 아닌가?” 싶었지만, 실제로 적용해보니 서비스를 깨뜨리지 않고 CSP를 제대로 적용하는 건 생각보다 까다로웠다.
시작은 Report-Only
처음에는 nginx에 아래처럼 Report-Only로 CSP를 걸었다.
add_header Content-Security-Policy-Report-Only "
default-src 'self';
base-uri 'self';
object-src 'none';
frame-ancestors 'self';
form-action 'self';
" always;
- 차단은 안 함
- 콘솔/리포트로 위반만 확인
- 이 상태는 “CSP를 테스트 중”이지, 방어라고 부르긴 어렵다.
CDN 사용으로 인한 첫 번째 벽
- https://cdn.jsdelivr.net는 다음 CDN을 사용 중이었다.
- 그래서 CSP를 실제로 적용하려면 명시적 허용이 필요했다.
script-src 'self' https://cdn.jsdelivr.net;;
style-src 'self' https://cdn.jsdelivr.net;;
Enforcement로 전환 → 사이트 꺠짐 현상
Report-Only를 Content-Security-Policy로 바꾸자마자:
- CSS 깨짐
- 클릭 안 됨
- 이미지 안 나옴
원인:
- 인라인 <style> 차단
- 인라인 <script> / onclick 차단
unsafe-inline의 유혹 (그리고 감점)
급한 복구용으로 아래처럼 풀면 사이트는 정상 동작한다.
script-src 'self' https://cdn.jsdelivr.net 'unsafe-inline';
style-src 'self' https://cdn.jsdelivr.net 'unsafe-inline';
하지만 보안 검사 사이트에서는 바로 감점:
Content Security Policy implemented unsafely(unsafe-inline 사용)
이건 점수 문제만이 아니라, XSS 방어력이 실제로 떨어진다.
결론: nonce 방식이 정답
unsafe-inline 없이 인라인 코드를 살리는 유일한 현실적인 방법은 nonce 방식이다.
PHP에서 nonce 생성 + CSP 헤더/인라인 코드에 nonce 적용
$csp_nonce = base64_encode(random_bytes(16));
$csp = "default-src 'self'; "
. "base-uri 'self'; "
. "object-src 'none'; "
. "frame-ancestors 'self'; "
. "form-action 'self'; "
. "script-src 'self' https://cdn.jsdelivr.net 'nonce-{$csp_nonce}'; "
. "style-src 'self' https://cdn.jsdelivr.net 'nonce-{$csp_nonce}'; "
. "img-src 'self' https://cdn.jsdelivr.net data: blob:; "
. "font-src 'self' https://cdn.jsdelivr.net data:; "
. "connect-src 'self'; "
. "upgrade-insecure-requests";
header("Content-Security-Policy: {$csp}");
<style nonce="<?= htmlspecialchars($csp_nonce) ?>">
/* 기존 CSS 그대로 */
</style><script nonce="<?= htmlspecialchars($csp_nonce) ?>">
// 기존 JS 그대로
</script>
나름 모든 부분이 해결된 듯 하다.
- 사이트 정상 동작
- unsafe-inline 제거
- CSP 검사 감점 사라짐
- XSS 주입 난이도 대폭 상승
CSP는 “헤더 하나 추가하면 끝”인 기능이 아니다.
- Report-Only → Enforcement
- unsafe-inline → nonce
- 점수보다 실제 방어 구조
이 과정을 거쳐야 비로소 “CSP를 적용했다”고 말할 수 있다.
한 줄 요약
CSP는 점수를 위한 설정이 아니라 XSS가 터졌을 때 피해를 줄이기 위한 최후의 안전벨트다.