Content Security Policy (CSP) ãšãã®ä»ã®ããã³ããšã³ãã»ãã¥ãªãã£ããããŒã«é¢ããå æ¬çã¬ã€ããWebã¢ããªã±ãŒã·ã§ã³ãæ»æããä¿è·ããäžçäžã®ãŠãŒã¶ãŒã»ãã¥ãªãã£ã匷åããŸãã
ããã³ããšã³ãã»ãã¥ãªãã£ããããŒïŒã³ã³ãã³ãã»ãã¥ãªãã£ããªã·ãŒ(CSP)ããã¹ã¿ãŒãã
仿¥ã®ããžã¿ã«ç°å¢ã«ãããŠãWebã¢ããªã±ãŒã·ã§ã³ã¯ãŸããŸãè€éåã»çžäºæ¥ç¶åããŠãããã»ãã¥ãªãã£äžã®è åšããä¿è·ããããšãæãéèŠã§ããããã¯ãšã³ãã®ã»ãã¥ãªãã£ã泚ç®ãããã¡ã§ãããããã³ããšã³ãã®ã»ãã¥ãªãã£ãåæ§ã«éèŠã§ããããã³ããšã³ãã»ãã¥ãªãã£ããããŒã¯æåã®é²è¡ç·ãšããŠæ©èœãããã©ãŠã¶ã«ã©ã®ããã«æ¯ãèãã¹ãããæç€ºããããŸããŸãªæ»æãããŠãŒã¶ãŒãä¿è·ããã¡ã«ããºã ãæäŸããŸãããããã®ããããŒã®äžã§ããã³ã³ãã³ãã»ãã¥ãªãã£ããªã·ãŒ(CSP)ã¯ãåºç¯å²ã®ãªã¹ã¯ã軜æžããããã®åŒ·åãªããŒã«ãšããŠéç«ã£ãŠããŸãã
ããã³ããšã³ãã»ãã¥ãªãã£ããããŒãšã¯ïŒ
ããã³ããšã³ãã»ãã¥ãªãã£ããããŒã¯ãWebãµãŒããŒããã©ãŠã¶ã«éä¿¡ããHTTPã¬ã¹ãã³ã¹ããããŒã§ãããããã®ããããŒã«ã¯ããã©ãŠã¶ãåä¿¡ããã³ã³ãã³ããã©ã®ããã«åŠçãã¹ããã®æç€ºãå«ãŸããŠããŸããããã«ãããæ¬¡ã®ãããªäžè¬çãªæ»æãé²ãããšãã§ããŸãïŒ
- ã¯ãã¹ãµã€ãã¹ã¯ãªããã£ã³ã°(XSS): ä¿¡é ŒããããŠã§ããµã€ãã«æªæã®ããã¹ã¯ãªãããæ³šå ¥ããããšã
- ã¯ãªãã¯ãžã£ããã³ã°: ãŠãŒã¶ãŒãéšããŠãèªèããŠãããã®ãšã¯ç°ãªããã®ãã¯ãªãã¯ãããããšã
- äžéè æ»æ: ãŠãŒã¶ãŒãšãµãŒããŒéã®éä¿¡ãååããããšã
æãéèŠãªããã³ããšã³ãã»ãã¥ãªãã£ããããŒã«ã¯ã以äžã®ãããªãã®ããããŸãïŒ
- ã³ã³ãã³ãã»ãã¥ãªãã£ããªã·ãŒ(CSP): ãã©ãŠã¶ããªãœãŒã¹ãèªã¿èŸŒãããšãèš±å¯ãããœãŒã¹ãå®çŸ©ããŸãã
- Strict-Transport-Security (HSTS): ãŠã§ããµã€ããšã®ãã¹ãŠã®éä¿¡ã§HTTPSã䜿çšãããããã©ãŠã¶ã«åŒ·å¶ããŸãã
- X-Frame-Options: ãŠã§ããµã€ããiframeã«åã蟌ãŸããã®ãé²ããã¯ãªãã¯ãžã£ããã³ã°æ»æã軜æžããŸãã
- X-XSS-Protection: ãã©ãŠã¶ã«çµã¿èŸŒãŸããXSSãã£ã«ã¿ãŒãæå¹ã«ããŸãã(泚æïŒå€ãã®å ŽåCSPã«åã£ãŠä»£ããããŠããŸãããäŸç¶ãšããŠé²åŸ¡å±€ãæäŸã§ããŸã)ã
- Referrer-Policy: ãªã¯ãšã¹ããšå ±ã«éä¿¡ããããªãã¡ã©ãŒæ å ±ã®éãå¶åŸ¡ããŸãã
- Feature-Policy (çŸåšã¯Permissions-Policy): éçºè ããã©ãŠã¶ã®æ©èœãAPIãéžæçã«æå¹åã»ç¡å¹åã§ããããã«ããŸãã
ã³ã³ãã³ãã»ãã¥ãªãã£ããªã·ãŒ(CSP)ã®è©³çŽ°è§£èª¬
ã³ã³ãã³ãã»ãã¥ãªãã£ããªã·ãŒ(CSP)ã¯ãç¹å®ã®ããŒãžã«å¯ŸããŠãŠãŒã¶ãŒãšãŒãžã§ã³ããèªã¿èŸŒãããšãèš±å¯ãããªãœãŒã¹ãå¶åŸ¡ããHTTPã¬ã¹ãã³ã¹ããããŒã§ããããã¯æ¿èªãããã³ã³ãã³ãã®ãœãŒã¹ããã¯ã€ããªã¹ãåãããã®ã§ãXSSæ»æã®ãªã¹ã¯ãå€§å¹ ã«åæžããŸããã¹ã¯ãªãããã¹ã¿ã€ã«ã·ãŒããç»åããã©ã³ããªã©ã®ãªãœãŒã¹ãèªã¿èŸŒãããšãã§ãããªãªãžã³ãæç€ºçã«å®çŸ©ããããšã«ãããCSPã¯æ»æè ãããªãã®ãŠã§ããµã€ãã«æªæã®ããã³ãŒããæ³šå ¥ããã®ãã¯ããã«å°é£ã«ããŸãã
CSPã®ä»çµã¿
CSPã¯ãããŸããŸãªçš®é¡ã®ã³ã³ãã³ãã«å¯ŸããŠæ¿èªããããœãŒã¹ã®ãªã¹ãããã©ãŠã¶ã«æäŸããããšã§æ©èœããŸãããã©ãŠã¶ãCSPã«éåãããªãœãŒã¹ã«ééãããšããã®ãªãœãŒã¹ããããã¯ããéåãå ±åããŸãããã®ãããã¯ã¡ã«ããºã ã«ãããæ»æè ãHTMLã«æªæã®ããã³ãŒããæ³šå ¥ã§ãããšããŠãããã®å®è¡ãé²ãããšãã§ããŸãã
CSPãã£ã¬ã¯ãã£ã
CSPãã£ã¬ã¯ãã£ãã¯CSPããªã·ãŒã®äžæ žããªãèŠçŽ ã§ãããããã¯ããŸããŸãªçš®é¡ã®ãªãœãŒã¹ã«å¯ŸããŠèš±å¯ããããœãŒã¹ãæå®ããŸããæãäžè¬çã«äœ¿çšããããã£ã¬ã¯ãã£ãã«ã¯ã以äžã®ãããªãã®ããããŸãïŒ
- default-src: ãã¹ãŠã®ãªãœãŒã¹ã¿ã€ãã®ããã©ã«ããœãŒã¹ãèšå®ããŸããããã¯ãããå ·äœçãªä»ã®ãã£ã¬ã¯ãã£ããå®çŸ©ãããŠããªãå Žåã«é©çšããããã©ãŒã«ããã¯ãã£ã¬ã¯ãã£ãã§ãã
- script-src: JavaScriptã«èš±å¯ããããœãŒã¹ãæå®ããŸãã
- style-src: CSSã¹ã¿ã€ã«ã·ãŒãã«èš±å¯ããããœãŒã¹ãæå®ããŸãã
- img-src: ç»åã«èš±å¯ããããœãŒã¹ãæå®ããŸãã
- font-src: ãã©ã³ãã«èš±å¯ããããœãŒã¹ãæå®ããŸãã
- media-src: ãªãŒãã£ãªããã³ãããªã«èš±å¯ããããœãŒã¹ãæå®ããŸãã
- object-src: Flashã®ãããªãã©ã°ã€ã³ã«èš±å¯ããããœãŒã¹ãæå®ããŸãã(å¯èœã§ããã°ãã©ã°ã€ã³ãèš±å¯ããªãã®ãæåã§ã)ã
- frame-src: ãã¬ãŒã (iframe)ã«èš±å¯ããããœãŒã¹ãæå®ããŸãã
- connect-src: ãããã¯ãŒã¯ãªã¯ãšã¹ã(AJAX, WebSockets)ã«èš±å¯ããããœãŒã¹ãæå®ããŸãã
- base-uri:
<base>èŠçŽ ã§äœ¿çšã§ããURLãå¶éããŸãã - form-action: ãã©ãŒã ãéä¿¡ã§ããURLãå¶éããŸãã
- frame-ancestors:
<frame>,<iframe>,<object>,<embed>, ãŸãã¯<applet>ã䜿çšããŠããŒãžãåã蟌ãããšãã§ããæå¹ãªèŠªãæå®ããŸãããã®ãã£ã¬ã¯ãã£ãã¯ã¯ãªãã¯ãžã£ããã³ã°ã«å¯Ÿããä¿è·ãæäŸããŸãã - upgrade-insecure-requests: ãµã€ãã®ãã¹ãŠã®å®å šã§ãªãURL(HTTPã§èªã¿èŸŒãŸãã)ããå®å šãªURL(HTTPSã§èªã¿èŸŒãŸãã)ã«çœ®ãæãããããã®ããã«æ±ããããŠãŒã¶ãŒãšãŒãžã§ã³ãã«æç€ºããŸãããã®ãã£ã¬ã¯ãã£ãã¯ãHTTPããHTTPSãžç§»è¡äžã®ãŠã§ããµã€ãã察象ãšããŠããŸãã
- report-uri: CSPéåã«é¢ããã¬ããŒãããã©ãŠã¶ãéä¿¡ããå ã®URLãæå®ããŸãã`report-to` ãåªå ããããéæšå¥šã§ãã
- report-to: `Report-To` ããããŒã§å®çŸ©ãããã°ã«ãŒãåãæå®ããŸããããã«ãããè€æ°ã®ã¬ããŒããšã³ããã€ã³ããæå®ãããªã©ããã詳现ãªã¬ããŒãå¶åŸ¡ãå¯èœã«ãªããŸãã
CSPãœãŒã¹å€
ãœãŒã¹å€ã¯ããªãœãŒã¹ã®èªã¿èŸŒã¿ãèš±å¯ããããªãªãžã³ãå®çŸ©ããŸããäžè¬çãªãœãŒã¹å€ã«ã¯ã以äžã®ãããªãã®ããããŸãïŒ
- *: ãããããœãŒã¹ããã®ã³ã³ãã³ããèš±å¯ããŸã(æ¬çªç°å¢ã§ã®äœ¿çšã¯é¿ããŠãã ããïŒ)ã
- 'self': ä¿è·ãããããã¥ã¡ã³ããšåããªãªãžã³(ã¹ããŒã ããã¹ããããŒã)ããã®ã³ã³ãã³ããèš±å¯ããŸãã
- 'none': ãããªããœãŒã¹ããã®ã³ã³ãã³ããèš±å¯ããŸããã
- 'unsafe-inline': ã€ã³ã©ã€ã³ã®JavaScriptãšCSSã®äœ¿çšãèš±å¯ããŸã(æ¬çªç°å¢ã§ã®äœ¿çšã¯é¿ããŠãã ããïŒ)ã
- 'unsafe-eval': åçãªã³ãŒãè©äŸ¡(äŸ:
eval(),Function())ã®äœ¿çšãèš±å¯ããŸã(æ¬çªç°å¢ã§ã®äœ¿çšã¯é¿ããŠãã ããïŒ)ã - 'strict-dynamic': ããŒã¯ã¢ããå ã«ååšããã¹ã¯ãªããã«ãã³ã¹ãŸãã¯ããã·ã¥ãä»äžããããšã§æç€ºçã«äžããããä¿¡é Œãããã®ç¥å ã«ãã£ãŠèªã¿èŸŒãŸãããã¹ãŠã®ã¹ã¯ãªããã«äŒæãããããšãæå®ããŸãã
- 'unsafe-hashes': ç¹å®ã®ã€ã³ã©ã€ã³ã€ãã³ããã³ãã©ãèš±å¯ããŸããããã¯è€éã§å©çãéå®çãªãããäžè¬çã«æšå¥šãããŸããã
- data:: data URL (äŸ: åã蟌ã¿ç»å) ããã®ãªãœãŒã¹èªã¿èŸŒã¿ãèš±å¯ããŸããæ³šæããŠäœ¿çšããŠãã ããã
- mediastream:: `mediastream:` URIãã¡ãã£ã¢ãœãŒã¹ãšããŠäœ¿çšããããšãèš±å¯ããŸãã
- blob:: `blob:` URIãã¡ãã£ã¢ãœãŒã¹ãšããŠäœ¿çšããããšãèš±å¯ããŸãã
- filesystem:: ãã¡ã€ã«ã·ã¹ãã ããã®ãªãœãŒã¹èªã¿èŸŒã¿ãèš±å¯ããŸãã
- https://example.com: ç¹å®ã®ãã¡ã€ã³ãšããŒãããã®ã³ã³ãã³ããèš±å¯ããŸãã
- *.example.com: example.comã®ä»»æã®ãµããã¡ã€ã³ããã®ã³ã³ãã³ããèš±å¯ããŸãã
- nonce-{random-value}: äžèŽããnonce屿§ãæã€ã¹ã¯ãªãããã¹ã¿ã€ã«ãèš±å¯ããŸããããã«ã¯ããªã¯ãšã¹ãããšã«ãµãŒããŒãµã€ãã§ã©ã³ãã ãªnonceå€ãçæããå¿ èŠããããŸãã
- sha256-{hash-value}: äžèŽããSHA256ãSHA384ããŸãã¯SHA512ããã·ã¥ãæã€ã¹ã¯ãªãããã¹ã¿ã€ã«ãèš±å¯ããŸãã
CSPã¢ãŒãïŒåŒ·å¶ãšã¬ããŒãå°çš
CSPã¯2ã€ã®ã¢ãŒãã§å±éã§ããŸãïŒ
- 匷å¶ã¢ãŒã: ãã®ã¢ãŒãã§ã¯ããã©ãŠã¶ã¯CSPã«éåãããªãœãŒã¹ããããã¯ããŸããããã¯æ¬çªç°å¢ã§æšå¥šãããã¢ãŒãã§ããCSP㯠`Content-Security-Policy` ããããŒã䜿çšããŠéä¿¡ãããŸãã
- ã¬ããŒãå°çšã¢ãŒã: ãã®ã¢ãŒãã§ã¯ããã©ãŠã¶ã¯CSPéåãå ±åããŸããããªãœãŒã¹ã¯ãããã¯ããŸãããããã¯CSPã匷å¶ããåã«ãã¹ãããã³è©äŸ¡ããã®ã«åœ¹ç«ã¡ãŸããCSP㯠`Content-Security-Policy-Report-Only` ããããŒã䜿çšããŠéä¿¡ãããŸãã
CSPã®å®è£ ïŒã¹ããããã€ã¹ãããã¬ã€ã
CSPã®å®è£ ã¯é£ããæãããããããŸããããäœç³»çãªã¢ãããŒãã«åŸãããšã§ãWebã¢ããªã±ãŒã·ã§ã³ã广çã«ä¿è·ã§ããŸãã
1. ã¬ããŒãå°çšããªã·ãŒããå§ãã
ãŸããã¬ããŒãå°çšã¢ãŒãã§CSPãå±éããããšããå§ããŸããããã«ããããŠã§ããµã€ãã®æ©èœã劚ããããšãªãéåãç£èŠã§ããŸããreport-uri ãŸã㯠report-to ãã£ã¬ã¯ãã£ããèšå®ããŠãéåã¬ããŒããæå®ã®ãšã³ããã€ã³ãã«éä¿¡ããŸãã
ããããŒäŸ (ã¬ããŒãå°çš):
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report
2. éåã¬ããŒããåæãã
éåã¬ããŒããæ³šææ·±ãåæããŠãã©ã®ãªãœãŒã¹ããªããããã¯ãããŠããã®ããç¹å®ããŸããããã¯ããŠã§ããµã€ãã®ãªãœãŒã¹äŸåé¢ä¿ãçè§£ããæœåšçãªã»ãã¥ãªãã£è匱æ§ãç¹å®ããã®ã«åœ¹ç«ã¡ãŸãã
éåã¬ããŒãã¯éåžžãèšå®ããã report-uri ãŸã㯠report-to ãšã³ããã€ã³ãã«JSONãã€ããŒããšããŠéä¿¡ãããŸãããããã®ã¬ããŒãã«ã¯ããããã¯ãããURIãéåãããã£ã¬ã¯ãã£ããããã¥ã¡ã³ãURIãªã©ã®éåã«é¢ããæ
å ±ãå«ãŸããŠããŸãã
3. CSPããªã·ãŒãæŽç·Žããã
éåã¬ããŒãã«åºã¥ããŠã匷åãªã»ãã¥ãªãã£äœå¶ãç¶æãã€ã€ãæ£åœãªãªãœãŒã¹ãèš±å¯ããããã«CSPããªã·ãŒãæŽç·ŽãããŸãããããã¯ãããŠãããªãœãŒã¹ã«ç¹å®ã®ãœãŒã¹å€ã远å ããŸããã€ã³ã©ã€ã³ã¹ã¯ãªãããã¹ã¿ã€ã«ã«ã¯ã'unsafe-inline' ã®äœ¿çšãé¿ããããã«ãã³ã¹ãŸãã¯ããã·ã¥ã䜿çšããããšãæ€èšããŠãã ããã
4. 匷å¶ã¢ãŒãã«ç§»è¡ãã
CSPããªã·ãŒãæ£åœãªãªãœãŒã¹ããããã¯ããŠããªããšç¢ºä¿¡ã§ãããã匷å¶ã¢ãŒãã«ç§»è¡ããŸããããã«ãããæ®ãã®éåããããã¯ãããXSSæ»æã«å¯Ÿããå ç¢ãªã»ãã¥ãªãã£å±€ãæäŸãããŸãã
ããããŒäŸ (匷å¶):
Content-Security-Policy: default-src 'self'; script-src 'self' https://example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data:; report-uri /csp-report
5. CSPããªã·ãŒãç£èŠã»ç¶æãã
CSPã¯äžåºŠèšå®ããã°çµãããšãã解決çã§ã¯ãããŸããããŠã§ããµã€ããé²åããæ°ããªã»ãã¥ãªãã£è åšãåºçŸããã«ã€ããŠãCSPããªã·ãŒãç¶ç¶çã«ç£èŠããæŽæ°ããããšãäžå¯æ¬ ã§ãã宿çã«éåã¬ããŒãã確èªããå¿ èŠã«å¿ããŠããªã·ãŒã調æŽããŠãã ããã
CSPã®å®çšäŸ
ããŸããŸãªã·ããªãªã«å¯Ÿå¿ããCSPã®å®çšäŸãããã€ãèŠãŠã¿ãŸãããïŒ
äŸ1ïŒã·ã³ãã«ãªãŠã§ããµã€ãåãã®åºæ¬çãªCSP
ãã®CSPã¯ãåäžãªãªãžã³ããã®ã³ã³ãã³ããšããããããœãŒã¹ããã®ç»åãèš±å¯ããŸãã
Content-Security-Policy: default-src 'self'; img-src *
äŸ2ïŒç¹å®ã®ã¹ã¯ãªããããã³ã¹ã¿ã€ã«ãœãŒã¹ãæã€CSP
ãã®CSPã¯ãåäžãªãªãžã³ããã³ç¹å®ã®CDNããã®ã¹ã¯ãªããããããŠåäžãªãªãžã³ããã³ã€ã³ã©ã€ã³ã¹ã¿ã€ã«ãèš±å¯ããŸãã
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'
äŸ3ïŒã€ã³ã©ã€ã³ã¹ã¯ãªããã«ãã³ã¹ã䜿çšããCSP
ãã®CSPã¯ãåã€ã³ã©ã€ã³ã¹ã¯ãªããã«äžæã®ãã³ã¹ãèŠæ±ããŸãã
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-r4nd0mn0nc3'
HTML:
<script nonce="r4nd0mn0nc3">console.log('Hello, world!');</script>
éèŠ: nonceå€ã¯ãªã¯ãšã¹ãããšã«ãµãŒããŒã§åçã«çæããå¿ èŠããããŸããããã«ãããæ»æè ãnonceãåå©çšããã®ãé²ããŸãã
äŸ4ïŒã¯ãªãã¯ãžã£ããã³ã°ãé²ãããã«frame-ancestorsãå¶éããCSP
ãã®CSPã¯ãããŒãžã `https://example.com` 以å€ã®ãã¡ã€ã³ã®iframeã«åã蟌ãŸããã®ãé²ããŸãã
Content-Security-Policy: frame-ancestors 'self' https://example.com
äŸ5ïŒ'strict-dynamic'ãš'self'ãžã®ãã©ãŒã«ããã¯ã䜿çšãããããå¶éçãªCSP
ãã®CSPã¯ã`strict-dynamic`ããµããŒãããŠããªãå€ããã©ãŠã¶ããµããŒããã€ã€ãã¢ãã³ãã©ãŠã¶ã§ã¯`strict-dynamic`ãæŽ»çšããŸãããŸããéåãç£èŠããããã®`report-uri`ãå«ãŸããŠããŸãã
Content-Security-Policy: default-src 'self'; script-src 'strict-dynamic' 'nonce-{random-nonce}' 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; report-uri /csp-report
ãµãŒããŒãµã€ãã§`{random-nonce}`ãåçã«çæãããnonceå€ã«çœ®ãæããããšãå¿ããªãã§ãã ããã
CSPãšã·ã³ã°ã«ããŒãžã¢ããªã±ãŒã·ã§ã³(SPA)
SPAã«CSPãå®è£ ããããšã¯ããããã®ã¢ããªã±ãŒã·ã§ã³ã®åçãªæ§è³ªã®ããå°é£ãªå ŽåããããŸããSPAã¯DOMãçæã»æäœããããã«JavaScriptã«å€§ããäŸåããŠãããããæ éã«æ±ããªããšCSPéåã«ã€ãªããå¯èœæ§ããããŸãã
SPAã«CSPãå®è£ ããããã®ãã³ããããã€ã玹ä»ããŸãïŒ
'unsafe-inline'ãš'unsafe-eval'ãé¿ãã: ãããã®ãã£ã¬ã¯ãã£ãã¯SPAã§ã¯å¯èœãªéãé¿ããã¹ãã§ãããããã¯ã¢ããªã±ãŒã·ã§ã³ã®ã»ãã¥ãªãã£ãå€§å¹ ã«åŒ±ããŸãã- ãã³ã¹ãŸãã¯ããã·ã¥ã䜿çšãã: ã€ã³ã©ã€ã³ã¹ã¯ãªãããã¹ã¿ã€ã«ã«ã¯ãã³ã¹ãŸãã¯ããã·ã¥ã䜿çšããŸããããã¯SPAã§æšå¥šãããã¢ãããŒãã§ãã
- Trusted Typesãæ€èšãã: Trusted Typesã¯DOMããŒã¹ã®XSSè匱æ§ãé²ãã®ã«åœ¹ç«ã€ãã©ãŠã¶APIã§ããCSPãšçµã¿åãããŠäœ¿çšããããšã§ãã»ãã¥ãªãã£ãããã«åŒ·åã§ããŸãã
- CSPäºæã®ãã¬ãŒã ã¯ãŒã¯ã䜿çšãã: äžéšã®ããã³ããšã³ããã¬ãŒã ã¯ãŒã¯ïŒç¹å®ã®æ§æãæã€ReactãAngularãVue.jsãªã©ïŒã¯ãCSPãããç°¡åã«å®è£ ããããã®æ©èœãæäŸããŠããŸãã
ãã®ä»ã®éèŠãªããã³ããšã³ãã»ãã¥ãªãã£ããããŒ
CSPã¯ããã³ããšã³ãã»ãã¥ãªãã£ã®ç€ã§ãããå æ¬çãªé²åŸ¡æŠç¥ãæäŸããããã«ã¯ä»ã®ããããŒãéèŠãªåœ¹å²ãæãããŸãïŒ
Strict-Transport-Security (HSTS)
Strict-Transport-Security (HSTS) ããããŒã¯ããŠã§ããµã€ããžã®æ¥ç¶ã«åžžã«HTTPSã䜿çšãããããã©ãŠã¶ã«æç€ºããŸããããã«ãããæ¥ç¶ãHTTPã«ããŠã³ã°ã¬ãŒãããããšããäžéè
æ»æãé²ããŸãã
ããããŒäŸ:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
max-age: ãã©ãŠã¶ããµã€ãã«HTTPSçµç±ã§ã®ã¿ã¢ã¯ã»ã¹ããããšãèšæ¶ãã¹ãæé(ç§åäœ)ãæå®ããŸããæ¬çªç°å¢ã§ã¯31536000ç§(1幎)ã®å€ãæšå¥šãããŸããincludeSubDomains: HSTSããªã·ãŒããã¡ã€ã³ã®ãã¹ãŠã®ãµããã¡ã€ã³ã«é©çšãããããšã瀺ããŸããpreload: ãã¡ã€ã³ããã©ãŠã¶ã«ããªããŒããããHSTSæå¹ãã¡ã€ã³ã®ãªã¹ãã«å«ããããšãèš±å¯ããŸããããã«ã¯ãGoogleã管çããHSTSããªããŒããªã¹ãã«ãã¡ã€ã³ãç³è«ããå¿ èŠããããŸãã
X-Frame-Options
X-Frame-Options ããããŒã¯ããŠã§ããµã€ããiframeã«åã蟌ãŸãããã©ãããå¶åŸ¡ããããšã«ãããã¯ãªãã¯ãžã£ããã³ã°æ»æãé²ããŸãã
ããããŒäŸ:
X-Frame-Options: DENY
å¯èœãªå€:
DENY: ãªãªãžã³ã«é¢ä¿ãªããããŒãžãiframeã«è¡šç€ºãããã®ãé²ããŸããSAMEORIGIN: iframeã®ãªãªãžã³ãããŒãžã®ãªãªãžã³ãšäžèŽããå Žåã«ã®ã¿ãããŒãžãiframeã«è¡šç€ºãããã®ãèš±å¯ããŸããALLOW-FROM uri: iframeã®ãªãªãžã³ãæå®ãããURIãšäžèŽããå Žåã«ã®ã¿ãããŒãžãiframeã«è¡šç€ºãããã®ãèš±å¯ããŸããæ³šæïŒãã®ãªãã·ã§ã³ã¯éæšå¥šã§ããããã¹ãŠã®ãã©ãŠã¶ã§ãµããŒããããŠãããšã¯éããŸããã
泚æ: CSPã® frame-ancestors ãã£ã¬ã¯ãã£ãã¯ããã¬ãŒãã³ã°ãå¶åŸ¡ããããã®ããæè»ã§åŒ·åãªæ¹æ³ãæäŸããäžè¬çã« X-Frame-Options ãããåªå
ãããŸãã
X-XSS-Protection
X-XSS-Protection ããããŒã¯ããã©ãŠã¶ã«çµã¿èŸŒãŸããXSSãã£ã«ã¿ãŒãæå¹ã«ããŸããCSPã¯XSSæ»æãé²ãããã®ããå
ç¢ãªãœãªã¥ãŒã·ã§ã³ã§ããããã®ããããŒã¯ãç¹ã«CSPãå®å
šã«ã¯ãµããŒãããŠããªãå€ããã©ãŠã¶ã«å¯ŸããŠã远å ã®é²åŸ¡å±€ãæäŸã§ããŸãã
ããããŒäŸ:
X-XSS-Protection: 1; mode=block
1: XSSãã£ã«ã¿ãŒãæå¹ã«ããŸãã0: XSSãã£ã«ã¿ãŒãç¡å¹ã«ããŸããmode=block: XSSæ»æãæ€åºãããå Žåã«ããŒãžããããã¯ãããããã©ãŠã¶ã«æç€ºããŸããreport=uri: XSSæ»æãæ€åºãããå Žåã«ãã©ãŠã¶ãã¬ããŒããéä¿¡ããå ã®URLãæå®ããŸãã
Referrer-Policy
Referrer-Policy ããããŒã¯ããªã¯ãšã¹ããšå
±ã«éä¿¡ããããªãã¡ã©ãŒæ
å ±ã®éãå¶åŸ¡ããŸãããªãã¡ã©ãŒæ
å ±ã¯ãŠã§ããµã€ãããŸããã§ãŠãŒã¶ãŒã远跡ããããã«äœ¿çšãããå¯èœæ§ãããããããããå¶åŸ¡ããããšã§ãŠãŒã¶ãŒã®ãã©ã€ãã·ãŒãåäžãããããšãã§ããŸãã
ããããŒäŸ:
Referrer-Policy: strict-origin-when-cross-origin
äžè¬çãªå€ã®ããã€ã:
no-referrer: RefererããããŒãéä¿¡ããŸãããno-referrer-when-downgrade: TLS(HTTPS)ã®ãªããªãªãžã³ã«ã¯RefererããããŒãéä¿¡ããŸãããorigin: RefererããããŒã«ãªãªãžã³(ã¹ããŒã ããã¹ããããŒã)ã®ã¿ãéä¿¡ããŸããorigin-when-cross-origin: ã¯ãã¹ãªãªãžã³ãªã¯ãšã¹ãã«ã¯ãªãªãžã³ããåäžãªãªãžã³ãªã¯ãšã¹ãã«ã¯å®å šãªURLãéä¿¡ããŸããsame-origin: åäžãªãªãžã³ãªã¯ãšã¹ãã«ã¯RefererããããŒãéä¿¡ããŸãããã¯ãã¹ãªãªãžã³ãªã¯ãšã¹ãã«ã¯éä¿¡ããŸãããstrict-origin: ãããã³ã«ã®ã»ãã¥ãªãã£ã¬ãã«ãåã(HTTPSããHTTPS)å Žåã«ã®ã¿ãªãªãžã³ãéä¿¡ããããå®å šã§ãªãå®å (HTTPSããHTTP)ã«ã¯ããããŒãéä¿¡ããŸãããstrict-origin-when-cross-origin: åäžãªãªãžã³ãªã¯ãšã¹ããå®è¡ããéã«ãªãªãžã³ãéä¿¡ããŸããã¯ãã¹ãªãªãžã³ãªã¯ãšã¹ãã®å Žåããããã³ã«ã®ã»ãã¥ãªãã£ã¬ãã«ãåã(HTTPSããHTTPS)å Žåã«ã®ã¿ãªãªãžã³ãéä¿¡ããããå®å šã§ãªãå®å (HTTPSããHTTP)ã«ã¯ããããŒãéä¿¡ããŸãããunsafe-url: ãªãªãžã³ã«é¢ä¿ãªããRefererããããŒã«å®å šãªURLãéä¿¡ããŸããæ©å¯æ å ±ãæŒæŽ©ããå¯èœæ§ãããããã现å¿ã®æ³šæãæã£ãŠäœ¿çšããŠãã ããã
Permissions-Policy (æ§Feature-Policy)
Permissions-Policy ããããŒ(æ§ç§° Feature-Policy)ã¯ãéçºè
ããã©ãŠã¶ã®æ©èœãAPIãéžæçã«æå¹åã»ç¡å¹åã§ããããã«ããŸããããã«ãããã¢ããªã±ãŒã·ã§ã³ã®æ»æå¯Ÿè±¡é åãæžããããŠãŒã¶ãŒã®ãã©ã€ãã·ãŒãåäžãããããšãã§ããŸãã
ããããŒäŸ:
Permissions-Policy: geolocation=()
ãã®äŸã§ã¯ããŠã§ããµã€ãã®å°çäœçœ®æ å ±APIãç¡å¹ã«ããŠããŸãã
Permissions-Policy ã§å¶åŸ¡ã§ãããã®ä»ã®æ©èœã«ã¯ã以äžã®ãããªãã®ããããŸãïŒ
cameramicrophonegeolocationaccelerometergyroscopemagnetometerusbmidipaymentfullscreen
ç°ãªããã©ãããã©ãŒã ã§ã®ã»ãã¥ãªãã£ããããŒã®èšå®
ã»ãã¥ãªãã£ããããŒã®èšå®æ¹æ³ã¯ã䜿çšããŠããWebãµãŒããŒããã©ãããã©ãŒã ã«ãã£ãŠç°ãªããŸãã以äžã«äžè¬çãªäŸãããã€ã瀺ããŸãïŒ
Apache
Apacheã§ã¯ã.htaccess ãã¡ã€ã«ãŸãã¯ãµãŒããŒèšå®ãã¡ã€ã«(httpd.conf)ã«è¿œå ããããšã§ã»ãã¥ãªãã£ããããŒãèšå®ã§ããŸãã
.htaccess èšå®äŸ:
<IfModule mod_headers.c>
Header set Content-Security-Policy "default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data:; report-uri /csp-report"
Header set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Header set X-Frame-Options "DENY"
Header set X-XSS-Protection "1; mode=block"
Header set Referrer-Policy "strict-origin-when-cross-origin"
</IfModule>
Nginx
Nginxã§ã¯ãNginxèšå®ãã¡ã€ã«(nginx.conf)ã®serverãããã¯ã«è¿œå ããããšã§ã»ãã¥ãªãã£ããããŒãèšå®ã§ããŸãã
Nginx èšå®äŸ:
server {
listen 443 ssl;
server_name example.com;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data:; report-uri /csp-report";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
add_header X-Frame-Options "DENY";
add_header X-XSS-Protection "1; mode=block";
add_header Referrer-Policy "strict-origin-when-cross-origin";
...
}
Node.js (Express)
Node.jsã§ã¯ãHelmetã®ãããªããã«ãŠã§ã¢ã䜿çšããŠã»ãã¥ãªãã£ããããŒãèšå®ã§ããŸãã
Helmetã䜿çšããäŸ:
const express = require('express');
const helmet = require('helmet');
const app = express();
app.use(helmet());
// Customize CSP if needed
app.use(helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "https://cdn.example.com"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:"],
reportUri: '/csp-report'
},
}));
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.listen(3000, () => {
console.log('Server listening on port 3000');
});
Cloudflare
Cloudflareã§ã¯ãããŒãžã«ãŒã«ãŸãã¯å€æã«ãŒã«ã䜿çšããŠã»ãã¥ãªãã£ããããŒãèšå®ã§ããŸãã
ã»ãã¥ãªãã£ããããŒã®ãã¹ã
ã»ãã¥ãªãã£ããããŒãå®è£ ããåŸã¯ãããããæ£ããæ©èœããŠããããšã確èªããããã«ãã¹ãããããšãéèŠã§ãããŠã§ããµã€ãã®ã»ãã¥ãªãã£ããããŒãåæããã®ã«åœ¹ç«ã€ããã€ãã®ãªã³ã©ã€ã³ããŒã«ããããŸãïŒ
- SecurityHeaders.com: ã»ãã¥ãªãã£ããããŒãåæããããã®ã·ã³ãã«ã§å¹æçãªããŒã«ã
- Mozilla Observatory: ã»ãã¥ãªãã£ããããŒãå«ããŠã§ããµã€ãã®ã»ãã¥ãªãã£ããã¹ãããããã®å æ¬çãªããŒã«ã
- WebPageTest.org: ãŠã©ãŒã¿ãŒãã©ãŒã«ãã£ãŒãã§HTTPããããŒã衚瀺ã§ããŸãã
çµè«
ããã³ããšã³ãã»ãã¥ãªãã£ããããŒãç¹ã«ã³ã³ãã³ãã»ãã¥ãªãã£ããªã·ãŒ(CSP)ã¯ãWebã¢ããªã±ãŒã·ã§ã³ãããŸããŸãªæ»æããä¿è·ãããŠãŒã¶ãŒã®ã»ãã¥ãªãã£ã匷åããããã«äžå¯æ¬ ã§ãããããã®ããããŒãæ éã«å®è£ ããã³ç¶æããããšã«ãããXSSãã¯ãªãã¯ãžã£ããã³ã°ããã®ä»ã®ã»ãã¥ãªãã£è匱æ§ã®ãªã¹ã¯ãå€§å¹ ã«åæžã§ããŸããã¬ããŒãå°çšããªã·ãŒããå§ããéåã¬ããŒããåæããããªã·ãŒãæŽç·Žããããã®åŸåŒ·å¶ã¢ãŒãã«ç§»è¡ããããšãå¿ããªãã§ãã ããããŠã§ããµã€ããé²åããæ°ããªè åšãåºçŸããã«ã€ããŠãã»ãã¥ãªãã£ããããŒã宿çã«ç£èŠã»æŽæ°ããŠãã ããã
ããã³ããšã³ãã»ãã¥ãªãã£ã«å¯ŸããŠç©æ¥µçãªã¢ãããŒããæ¡çšããããšã§ããŠãŒã¶ãŒãšããžãã¹ãä¿è·ãããããå®å šã§ä¿¡é Œæ§ã®é«ãWebã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ã§ããŸãã