Vibe Guardian

Vibe Guardian

목록으로
BLOG DETAIL

unsafe-inline 없이 CSP 설정하는 방법 — nonce와 hash 사용법

#CSP nonce#unsafe-inline제거#CSP고급설정#XSS방어

ARTICLE CONTENT

1. CSP를 설정할 때 왜 unsafe-inline부터 고민하게 될까

웹사이트 보안을 점검하다 보면 가장 먼저 마주치는 항목 중 하나가 CSP입니다. 특히 unsafe-inline은 설정을 쉽게 만들지만, 장기적으로는 XSS방어 측면에서 부담이 될 수 있어 많은 개발자가 unsafe-inline제거를 고민하게 됩니다.
실제로 서비스 운영 중에는 빠르게 기능을 붙이느라 인라인 스크립트나 스타일을 많이 쓰는 경우가 있는데, 이때 CSP를 적용하려고 하면 어디부터 손봐야 할지 막막해지기 쉽습니다.
그래서 많은 사람들이 CSP nonce, hash, 그리고 CSP고급설정 같은 키워드를 검색하게 됩니다. 단순히 “정책을 넣는 방법”이 아니라, 기존 구조를 크게 흔들지 않으면서 보안을 강화하는 방법을 찾기 때문입니다.
이 글에서는 unsafe-inline 없이 CSP를 구성하는 기본 흐름과, nonce와 hash를 어떻게 활용하는지, 그리고 어떤 상황에서 각각 더 적합한지 정리해보겠습니다.

1) unsafe-inline이 편하지만 위험한 이유

unsafe-inline은 CSP에서 인라인 스크립트와 스타일을 허용해 주기 때문에 초기 설정은 쉽습니다. 하지만 이 옵션이 들어가면 브라우저가 “이 인라인 코드는 허용해도 된다”는 식으로 폭넓게 해석할 여지가 생깁니다.
그 결과 공격자가 주입한 스크립트가 실행될 가능성이 커져 XSS방어 효과가 크게 떨어질 수 있습니다.
물론 모든 인라인 코드가 바로 문제라는 뜻은 아니지만, 보안 정책의 목적이 “예외를 줄이고 신뢰할 수 있는 코드만 허용하는 것”이라면 unsafe-inline은 장기적으로 제거하는 편이 좋습니다.
특히 로그인, 결제, 관리자 페이지처럼 민감한 화면일수록 CSP 정책은 좀 더 엄격하게 가져가는 경우가 많습니다.

2) nonce 방식은 어떤 구조에서 잘 맞을까

CSP nonce는 매 요청마다 서버가 무작위 값 하나를 만들어 CSP 헤더와 <script> 또는 <style> 태그에 함께 넣는 방식입니다. 브라우저는 CSP 헤더에 적힌 nonce와 태그의 nonce가 일치할 때만 실행을 허용합니다.
이 방식의 장점은 페이지에 필요한 일부 인라인 코드를 허용하면서도, 나머지 임의 삽입 코드는 막을 수 있다는 점입니다. 그래서 unsafe-inline제거를 진행할 때 가장 많이 검토되는 방식 중 하나입니다.
예를 들어 서버 렌더링 페이지에서 꼭 필요한 초기화 스크립트가 있을 때, 전체 인라인 허용 대신 CSP nonce를 사용하면 보안과 편의성을 함께 맞출 수 있습니다.
다만 nonce 값은 요청마다 달라져야 하며, 정적 HTML만 배포하는 구조에서는 적용 방식이 조금 더 복잡해질 수 있습니다.

3) hash 방식은 어떤 경우에 유리할까

hash 방식은 특정 인라인 코드의 내용을 해시로 계산해 CSP에 등록하는 방법입니다. 브라우저는 실제 인라인 코드가 해시와 일치할 때만 실행을 허용합니다.
이 방식은 코드가 자주 바뀌지 않는 경우에 특히 유용합니다. 예를 들어 배포 시점에 고정되는 작은 초기화 스크립트나 간단한 설정 코드처럼 변경 빈도가 낮은 경우에는 hash 기반 정책이 관리하기 쉬운 편입니다.
CSP고급설정을 고민할 때 nonce와 hash 중 어느 쪽이 더 적합한지는 페이지 성격에 따라 달라집니다. 동적으로 생성되는 코드가 많으면 nonce가, 정적인 인라인 코드가 많으면 hash가 더 적합한 경우가 많습니다.
다만 hash는 코드 내용이 조금만 바뀌어도 다시 계산해야 하므로, 운영 중 잦은 수정이 있는 환경에서는 관리 부담이 생길 수 있습니다.

4) nonce와 hash를 함께 볼 때 중요한 차이

둘 다 unsafe-inline제거를 위한 대표적인 방법이지만, 실제 운영 환경에서는 역할이 조금 다릅니다.
nonce는 “이번 요청에서 허용된 코드”를 지정하는 느낌이고, hash는 “이 내용 자체가 허용된 코드”를 지정하는 느낌에 가깝습니다.
그래서 서버 측에서 매번 출력되는 스크립트가 있다면 nonce가 더 자연스럽고, 템플릿에 고정된 스크립트라면 hash가 더 단순할 수 있습니다.
CSP nonce를 쓰면 요청마다 값이 달라지므로 캐시 전략과의 조합도 함께 고려해야 합니다. 반면 hash는 정적 자산처럼 관리할 수 있어 배포 체계와 잘 맞는 경우가 있습니다.
결국 중요한 것은 “어떤 방식이 더 좋아 보이느냐”가 아니라, 현재 서비스 구조에서 유지보수가 가능한지를 보는 것입니다.

5) CSP를 설정할 때 자주 놓치는 부분

CSP는 단순히 script-src만 막는다고 끝나지 않습니다. 실제로는 style-src, img-src, connect-src, font-src 같은 항목도 함께 살펴봐야 합니다.
예를 들어 API 호출이 정상적으로 안 되거나 이미지가 깨지는 문제는 CSP의 다른 디렉티브 때문에 생기는 경우가 많습니다. 이 때문에 CSP고급설정은 “더 빡세게 막는 것”이 아니라, 필요한 자원만 정확하게 허용하는 작업에 가깝습니다.
또한 브라우저 콘솔에 뜨는 오류를 그냥 넘기면, 나중에 배포 후 기능 장애로 이어질 수 있습니다.
따라서 unsafe-inline을 제거할 때는 한 번에 전부 바꾸기보다, 현재 페이지에서 실제로 어떤 리소스가 필요한지 하나씩 확인하는 방식이 안전합니다.

6) XSS방어 관점에서 CSP가 도움이 되는 이유

CSP는 XSS를 “완전히 없애는 도구”는 아니지만, 공격 성공 가능성을 낮추는 데 분명히 도움이 됩니다.
특히 인라인 스크립트 실행을 제한하면, 단순한 문자열 삽입이나 일부 스크립트 주입이 곧바로 실행되는 것을 막을 수 있습니다. 이런 점에서 XSS방어의 보조 수단으로 많이 사용됩니다.
다만 CSP만 믿고 입력값 검증이나 출력 이스케이프를 소홀히 하면 안 됩니다. 보안은 여러 겹으로 구성되는 경우가 많고, CSP는 그중 한 겹을 강화하는 역할에 가깝습니다.
그래서 보통은 입력 검증, 템플릿 이스케이프, 쿠키 보안 설정과 함께 CSP를 적용하는 흐름이 더 현실적입니다.

7) 실제로 점검할 때 어떤 식으로 접근하면 좋을까

CSP를 처음 적용할 때는 기존 페이지가 어떤 보안 상태인지 먼저 보는 것이 좋습니다. HTTPS 적용 여부, 인증서 상태, 보안 헤더, 쿠키 설정, API 접근 방식 등을 함께 확인하면 CSP 적용 전에 문제를 미리 찾을 수 있습니다.
이때 Vibe Guardian처럼 URL만 입력해 웹사이트의 기본 보안 상태를 빠르게 확인하는 도구를 활용하면, 어디서부터 손봐야 할지 정리하는 데 도움이 될 수 있습니다.
예를 들어 브라우저에서 실제로 발생하는 Mixed Content, XSS 관련 위험 신호, 노출 가능성이 있는 설정 문제를 먼저 확인한 뒤 CSP를 설계하면 시행착오를 줄일 수 있습니다.
기본적인 보안은 한 번 정리해두면 이후 프로젝트에서도 그대로 적용할 수 있기 때문에, 이런 점검 과정을 습관처럼 가져가는 편이 좋습니다.

2. unsafe-inline 없이 CSP를 설계하는 기본 흐름

1) 먼저 인라인 코드가 꼭 필요한지 확인하기

가장 좋은 방법은 애초에 인라인 스크립트와 스타일을 줄이는 것입니다. 많은 경우 작은 스크립트는 외부 파일로 분리해도 충분합니다.
이렇게 구조를 바꾸면 unsafe-inline제거가 훨씬 쉬워지고, CSP nonce나 hash를 최소한으로만 사용해도 됩니다.
실무에서는 레거시 코드 때문에 인라인을 완전히 없애기 어려운 경우도 많지만, 그래도 새로 추가되는 코드는 외부화하는 방향이 일반적으로 유리합니다.

2) 필요한 예외만 nonce 또는 hash로 열어두기

unsafe-inline을 완전히 없애려면, 실제로 필요한 부분만 예외 처리해야 합니다.
이때 nonce는 매 요청마다 바뀌는 값으로 허용 범위를 좁히는 데 좋고, hash는 고정된 코드 블록을 안정적으로 허용하는 데 적합합니다.
둘 다 XSS방어에 더 유리한 구조를 만들 수 있지만, 설정 방식이 달라서 운영 방식까지 함께 고려해야 합니다.

3) 브라우저 콘솔 오류를 기준으로 반복 조정하기

CSP는 한 번에 완성되기보다, 오류를 보면서 조정하는 경우가 많습니다.
차단된 스크립트, 스타일, API 호출, 폰트 로드 문제 등을 확인하면서 필요한 지시어를 추가하거나 조정해야 합니다.
이 과정에서 CSP고급설정이란 결국 복잡한 문법을 외우는 것보다, 실제 동작을 보며 정책을 다듬는 일에 가깝습니다.

3. CSP nonce 적용 시 알아두면 좋은 점

1) 요청마다 nonce를 새로 생성해야 함

nonce는 재사용하면 보안 의미가 약해집니다. 매 요청마다 새 값을 발급하고, 응답 헤더와 HTML 태그에 동일하게 반영해야 합니다.
이 과정이 서버 렌더링 구조와 잘 맞으면 관리가 수월하지만, 클라이언트 렌더링이 많은 구조에서는 설계가 조금 더 필요합니다.

2) 템플릿과 렌더링 구조를 같이 봐야 함

CSP nonce는 단순히 헤더만 넣는다고 끝나지 않습니다. 실제 스크립트 태그에도 nonce를 함께 넣어야 하므로, 템플릿 엔진이나 프레임워크 레벨에서 처리하는 경우가 많습니다.
따라서 페이지마다 스크립트가 다르게 출력되는 구조라면 nonce 방식이 자연스럽지만, 정적 페이지 중심이라면 hash가 더 단순할 수 있습니다.

3) 캐시와의 충돌 가능성 체크

요청마다 값이 바뀌는 특성 때문에 캐시 정책과 함께 검토해야 합니다.
특히 프론트에서 HTML을 강하게 캐시하는 구조라면 nonce가 일치하지 않아 문제가 생길 수 있으므로, 배포 방식과 함께 점검하는 것이 좋습니다.

4. hash 기반 CSP가 적합한 경우

1) 코드 내용이 자주 바뀌지 않을 때

hash는 특정 코드 내용이 유지될수록 관리가 쉬워집니다.
간단한 초기화 코드나 고정 템플릿 조각처럼 수정이 잦지 않다면, hash를 미리 계산해 정책에 넣는 방식이 잘 맞습니다.

2) 정적 페이지 비중이 높을 때

정적 사이트나 변경 빈도가 낮은 랜딩 페이지는 hash 기반 정책을 적용하기 편한 편입니다.
이 경우 unsafe-inline제거를 하면서도 운영 부담을 비교적 낮게 유지할 수 있습니다.

3) 배포 프로세스에 해시 갱신이 포함될 수 있을 때

배포할 때 자동으로 hash를 갱신할 수 있는 체계가 있다면 관리가 수월합니다.
반대로 사람이 수동으로 매번 해시를 수정해야 한다면 실수 가능성이 커질 수 있으므로 주의가 필요합니다.

5. CSP고급설정에서 함께 확인할 항목

1) script-src 외의 디렉티브도 점검하기

style-src, connect-src, img-src, frame-src 등도 실제 서비스에 큰 영향을 줍니다.
특히 외부 API, 추적 도구, 폰트, 이미지 CDN을 쓰는 경우 차단 이슈가 생길 수 있습니다.

2) 브라우저별 동작 차이 살펴보기

CSP는 브라우저에 따라 에러 메시지나 동작 방식이 조금 다르게 보일 수 있습니다.
그래서 개발 환경에서 한 번 통과했다고 끝내기보다, 실제 사용자 환경에서도 확인하는 편이 좋습니다.

3) 보안 헤더 전체를 함께 보는 습관

CSP만 따로 떼어 보기보다 HSTS, X-Content-Type-Options, Referrer-Policy 같은 헤더도 같이 점검하면 전체 보안 수준을 더 안정적으로 올릴 수 있습니다.
기본적인 보안 헤더는 서로 보완 관계에 있는 경우가 많습니다.

6. 실무에서 자주 나오는 시행착오

1) 너무 빠르게 정책을 잠그는 경우

처음부터 매우 엄격하게 설정하면 화면 일부가 안 뜨거나 기능이 깨질 수 있습니다.
그래서 보통은 차단 로그를 보면서 단계적으로 조정하는 방식이 많이 쓰입니다.

2) 인라인 코드가 숨어 있는 경우

겉으로는 외부 파일만 사용하는 것처럼 보여도, 템플릿 안에 작은 인라인 코드가 남아 있는 경우가 있습니다.
이런 부분은 unsafe-inline제거 후에 갑자기 오류가 나타나는 원인이 됩니다.

3) XSS방어를 CSP 하나로 끝내려는 경우

CSP는 중요한 방어 수단이지만, 입력 검증과 출력 인코딩을 대신하지는 못합니다.
즉, CSP는 보안의 마지막 방어선 중 하나로 보는 것이 적절합니다.

7. 어떤 상황에서 unsafe-inline 없이 CSP를 고려하면 좋을까

1) 로그인이나 결제처럼 민감한 화면이 있을 때

민감 정보가 오가는 페이지는 XSS방어 우선순위가 높기 때문에 unsafe-inline을 줄이는 것이 특히 중요합니다.

2) 레거시 코드 정리가 필요한 프로젝트일 때

기존 코드가 인라인 위주로 쌓여 있다면 한 번에 다 바꾸기 어렵습니다.
이럴 때 CSP nonce나 hash를 활용하면 완전한 재작성 없이도 점진적으로 보안을 강화할 수 있습니다.

3) 새 프로젝트에서 처음부터 보안 기준을 잡고 싶을 때

새로 만드는 서비스라면 초기에 정책을 정리해 두는 편이 훨씬 효율적입니다.
기본 구조를 잘 잡아두면 이후 기능 추가 시에도 CSP고급설정을 크게 흔들지 않고 유지할 수 있습니다.

unsafe-inline 없이 CSP를 설정하는 방법은 단순히 보안 문법을 바꾸는 일이 아니라, 서비스 구조를 조금 더 안전한 방향으로 정리하는 과정에 가깝습니다. CSP nonce는 동적으로 생성되는 인라인 코드에, hash는 고정된 코드 블록에 잘 맞는 편이며, 둘 다 unsafe-inline제거XSS방어에 도움이 됩니다. 다만 실제로는 화면 구성, 배포 방식, 캐시 정책, 외부 리소스 사용 여부까지 함께 봐야 하기 때문에 CSP고급설정은 단계적으로 접근하는 것이 좋습니다. 직접 전화로 문의해 바로 답을 듣는 방식보다, 이런 보안 점검 도구나 브라우저 콘솔을 함께 활용하면 현재 사이트의 문제 지점을 먼저 확인한 뒤 필요한 부분만 정리할 수 있다는 차이가 있습니다. 결국 이 서비스는 “지금 내 웹사이트의 기본 보안 상태가 괜찮은지 빠르게 확인하고 싶을 때”, 그리고 CSP를 도입하거나 정리하는 과정에서 우선순위를 잡고 싶을 때 유용하게 활용할 수 있습니다.

다른 콘텐츠도 함께 보세요

같은 주제에서 이어서 읽기 좋은 글들을 랜덤으로 추천합니다.

4 ARTICLES

Cursor로 30분 만에 만든 서비스, 배포 전 보안 3분 체크법

배포 전에 왜 보안을 한 번 더 봐야 할까 1) 빠르게 만든 서비스일수록 놓치기 쉬운 부분 Cursor로 기능을 빠르게 구현하고 나면, 생각보다 금방 배포 단계까지 가는 경우가 많습니다. 특히 AI개발 흐름에서는 아이디어를 바로 코드로 옮길 수 있어서…

#Cursor배포#바이브코딩배포#빠른보안점검+1

AI가 자동으로 만든 API에서 인증 로직이 빠지는 이유

왜 AI가 만든 API에서 인증 문제가 자주 보일까 1) 빠르게 만든 API일수록 놓치기 쉬운 것들 AI를 활용해 코드를 만들면 화면 구성이나 기본 CRUD API는 매우 빠르게 완성되는 경우가 많습니다. 하지만 속도가 빨라질수록 세부 보안 검토는 뒤…

#API인증누락#바이브코딩취약점#AI생성API+1

바이브 코딩 스타트업의 보안 점검 루틴 — 배포마다 딱 3분 투자

배포 직전에 보안 점검이 자주 비는 이유 1) 빠르게 만드는 흐름이 우선되기 때문 바이브코딩스타트업처럼 속도가 중요한 팀에서는 기능 개발과 수정이 먼저 잡히고, 보안 점검은 뒤로 밀리는 경우가 많습니다. 특히 작은 팀일수록 “일단 배포하고 나중에 보자…

#바이브코딩스타트업#보안루틴#배포프로세스+1

X-Content-Type-Options nosniff 한 줄로 MIME 공격 막기

X-Content-Type-Options nosniff가 왜 자주 검색될까 1) 기본 보안 설정이지만 놓치기 쉬운 항목 웹사이트를 운영하다 보면 HTTPS, 인증서, 쿠키 설정처럼 눈에 띄는 보안 항목은 비교적 잘 챙기게 됩니다. 그런데 , , ,

#X-Content-Type-Options#nosniff#MIME공격방지+1