ã³ã³ãã³ãã»ãã¥ãªãã£ããªã·ãŒ(CSP)ãšãªãªãžã³éãªãœãŒã¹å ±æ(CORS)ãçšããŠããã³ããšã³ãã®ã»ãã¥ãªãã£ã匷åããçŸä»£ã®è åšãããŠã§ãã¢ããªã±ãŒã·ã§ã³ãä¿è·ããããã®å æ¬çã¬ã€ãã
ããã³ããšã³ãã»ãã¥ãªãã£ã®åŒ·åïŒã³ã³ãã³ãã»ãã¥ãªãã£ããªã·ãŒãšCORS
仿¥ã®çžäºæ¥ç¶ãããããžã¿ã«ç°å¢ã«ãããŠãããã³ããšã³ãã®ã»ãã¥ãªãã£ã¯æéèŠã§ãããŠã§ãã¢ããªã±ãŒã·ã§ã³ã¯ãŸããŸãå·§åŠãªæ»æã®æšçãšãªã£ãŠãããå ç¢ãªã»ãã¥ãªãã£å¯Ÿçãäžå¯æ¬ ã§ããã»ãã¥ã¢ãªããã³ããšã³ãã¢ãŒããã¯ãã£ã®2ã€ã®éèŠãªèŠçŽ ããã³ã³ãã³ãã»ãã¥ãªãã£ããªã·ãŒ(CSP)ãšãªãªãžã³éãªãœãŒã¹å ±æ(CORS)ã§ãããã®å æ¬çãªã¬ã€ãã§ã¯ããããã®æè¡ãæ·±ãæãäžãããŠã§ãã¢ããªã±ãŒã·ã§ã³ãçŸä»£ã®è åšãã匷åããããã®å®è·µçãªäŸãšå®çšçãªæŽå¯ãæäŸããŸãã
ã³ã³ãã³ãã»ãã¥ãªãã£ããªã·ãŒ(CSP)ãšã¯ïŒ
ã³ã³ãã³ãã»ãã¥ãªãã£ããªã·ãŒ(CSP)ã¯ãã¯ãã¹ãµã€ãã¹ã¯ãªããã£ã³ã°(XSS)ãããŒã¿ã€ã³ãžã§ã¯ã·ã§ã³æ»æãšãã£ãç¹å®ã®çš®é¡ã®æ»æãæ€åºããç·©åããã®ã«åœ¹ç«ã€è¿œå ã®ã»ãã¥ãªãã£å±€ã§ããCSPã¯ããŠã§ããµãŒããŒããã©ãŠã¶ã«Content-Security-Policy HTTPã¬ã¹ãã³ã¹ããããŒãéä¿¡ããããšã§å®è£ ãããŸãããã®ããããŒã¯ããã©ãŠã¶ããªãœãŒã¹ãèªã¿èŸŒãããšãèš±å¯ãããŠãããœãŒã¹ã®ãã¯ã€ããªã¹ããå®çŸ©ããŸãããã©ãŠã¶ãèªã¿èŸŒããã³ã³ãã³ãã®ãœãŒã¹ãå¶éããããšã§ãCSPã¯æ»æè ããŠã§ããµã€ãã«æªæã®ããã³ãŒããæ³šå ¥ããã®ãå€§å¹ ã«å°é£ã«ããŸãã
CSPã®ä»çµã¿
CSPã¯ãæ¿èªããããœãŒã¹ããã®ã¿ãªãœãŒã¹(äŸïŒã¹ã¯ãªãããã¹ã¿ã€ã«ã·ãŒããç»åããã©ã³ã)ãèªã¿èŸŒããããã©ãŠã¶ã«æç€ºããããšã§æ©èœããŸãããããã®ãœãŒã¹ã¯ãCSPããããŒå ã§ãã£ã¬ã¯ãã£ãã䜿çšããŠæå®ãããŸãããã©ãŠã¶ãæç€ºçã«èš±å¯ãããŠããªããœãŒã¹ãããªãœãŒã¹ãèªã¿èŸŒãããšãããšããã®ãªã¯ãšã¹ãããããã¯ããéåãå ±åããŸãã
CSPãã£ã¬ã¯ãã£ãïŒå æ¬çæŠèŠ
CSPãã£ã¬ã¯ãã£ãã¯ãç¹å®ã®ãœãŒã¹ããèªã¿èŸŒãããšãã§ãããªãœãŒã¹ã®çš®é¡ãå¶åŸ¡ããŸãã以äžã«ãæãéèŠãªãã£ã¬ã¯ãã£ãã®ããã€ãã玹ä»ããŸãïŒ
- default-src: ãã¹ãŠã®ã³ã³ãã³ãã¿ã€ãã®ããã©ã«ããœãŒã¹ãæå®ããŸããããã¯ãããå ·äœçãªä»ã®ãã£ã¬ã¯ãã£ããååšããªãå Žåã«é©çšããããã©ãŒã«ããã¯ãã£ã¬ã¯ãã£ãã§ãã
- script-src: ã¹ã¯ãªãããèªã¿èŸŒãããœãŒã¹ãæå®ããŸããããã¯XSSæ»æãé²ãäžã§éåžžã«éèŠã§ãã
- style-src: ã¹ã¿ã€ã«ã·ãŒããèªã¿èŸŒãããœãŒã¹ãæå®ããŸãã
- img-src: ç»åãèªã¿èŸŒãããœãŒã¹ãæå®ããŸãã
- font-src: ãã©ã³ããèªã¿èŸŒãããœãŒã¹ãæå®ããŸãã
- media-src: é³å£°ãåç»ãèªã¿èŸŒãããœãŒã¹ãæå®ããŸãã
- object-src: ãã©ã°ã€ã³(äŸïŒFlash)ãèªã¿èŸŒãããœãŒã¹ãæå®ããŸããããã¯åºæã®ã»ãã¥ãªãã£ãªã¹ã¯ã®ããããã©ã°ã€ã³ãå®å šã«ç¡å¹ã«ããããã«ãã°ãã° 'none' ã«èšå®ãããŸãã
- frame-src: ãã¬ãŒã (äŸïŒ<iframe>)ãèªã¿èŸŒãããœãŒã¹ãæå®ããŸãã
- connect-src: ãŠãŒã¶ãŒãšãŒãžã§ã³ããXMLHttpRequestãWebSocketãEventSourceãªã©ã®ã¹ã¯ãªããã€ã³ã¿ãŒãã§ãŒã¹ã䜿çšããŠæ¥ç¶ã§ããURLãæå®ããŸãã
- base-uri: ããã¥ã¡ã³ãã®<base>èŠçŽ ã§äœ¿çšã§ããURLãæå®ããŸãã
- form-action: ãã©ãŒã ã®éä¿¡å ãšãªãURLãæå®ããŸãã
- upgrade-insecure-requests: å®å šã§ãªããªã¯ãšã¹ã(HTTP)ãå®å šãªãªã¯ãšã¹ã(HTTPS)ã«èªåçã«ã¢ããã°ã¬ãŒããããããŠãŒã¶ãŒãšãŒãžã§ã³ãã«æç€ºããŸãã
- report-uri: ãã©ãŠã¶ãCSPéåã«é¢ããã¬ããŒããéä¿¡ãã¹ãURLãæå®ããŸãããã®ãã£ã¬ã¯ãã£ãã¯`report-to`ãåªå ããããéæšå¥šã§ãã
- report-to: `Report-To`ããããŒã§å®çŸ©ãããã¬ããŒãã£ã³ã°ã°ã«ãŒãåãæå®ãããã©ãŠã¶ãCSPéåã«é¢ããã¬ããŒããããã«éä¿¡ããããã«ããŸãã
CSPãœãŒã¹ãªã¹ãããŒã¯ãŒã
CSPãã£ã¬ã¯ãã£ãå ã§ã¯ããœãŒã¹ãªã¹ãããŒã¯ãŒãã䜿çšããŠèš±å¯ããããœãŒã¹ãå®çŸ©ã§ããŸãã以äžã¯äžè¬çãªããŒã¯ãŒãã®äžéšã§ãïŒ
- 'self': ããã¥ã¡ã³ããšåããªãªãžã³(ã¹ããŒã ãšãã¹ã)ããã®ãªãœãŒã¹ãèš±å¯ããŸãã
- 'none': ãã¹ãŠã®ãœãŒã¹ããã®ãªãœãŒã¹ãäžèš±å¯ã«ããŸãã
- 'unsafe-inline': ã€ã³ã©ã€ã³ã¹ã¯ãªãããã¹ã¿ã€ã«ã®äœ¿çšãèš±å¯ããŸã(äŸïŒ<script>ã¿ã°ãstyle屿§)ãXSSã«å¯ŸããCSPã®ä¿è·ãå€§å¹ ã«åŒ±ããããã现å¿ã®æ³šæãæã£ãŠäœ¿çšããŠãã ããã
- 'unsafe-eval':
eval()ãFunction()ã®ãããªåçã³ãŒãè©äŸ¡é¢æ°ã®äœ¿çšãèš±å¯ããŸããé倧ãªã»ãã¥ãªãã£ãªã¹ã¯ãããããããã现å¿ã®æ³šæãæã£ãŠäœ¿çšããŠãã ããã - 'unsafe-hashes': æå®ãããããã·ã¥ã«äžèŽããç¹å®ã®ã€ã³ã©ã€ã³ã€ãã³ããã³ãã©ã<style>ã¿ã°ãèš±å¯ããŸãããã©ãŠã¶ã®ãµããŒããå¿ èŠã§ããæ³šæããŠäœ¿çšããŠãã ããã
- 'strict-dynamic': nonceãŸãã¯ããã·ã¥ã䌎ãããšã§ããŒã¯ã¢ããå ã«ååšããã¹ã¯ãªããã«æç€ºçã«äžããããä¿¡é Œãããã®ã«ãŒãã¹ã¯ãªããã«ãã£ãŠèªã¿èŸŒãŸãããã¹ãŠã®ã¹ã¯ãªããã«äŒæãããã¹ãã§ããããšãæå®ããŸãã
- data: data: URIãèš±å¯ããŸã(äŸïŒbase64ã§ãšã³ã³ãŒããããã€ã³ã©ã€ã³ç»å)ãæ³šæããŠäœ¿çšããŠãã ããã
- https:: ä»»æã®ãã¡ã€ã³ããHTTPSçµç±ã§ãªãœãŒã¹ãèªã¿èŸŒãããšãèš±å¯ããŸãã
- [hostname]: ç¹å®ã®ãã¡ã€ã³ããã®ãªãœãŒã¹ãèš±å¯ããŸã(äŸïŒexample.com)ãããŒãçªå·ãæå®ããããšãå¯èœã§ã(äŸïŒexample.com:8080)ã
- [scheme]://[hostname]:[port]: å®å šä¿®é£ŸURIã§ãæå®ãããã¹ããŒã ããã¹ããããŒãããã®ãªãœãŒã¹ãèš±å¯ããŸãã
CSPã®å®è·µäŸ
CSPããããŒã®å®è·µçãªäŸãããã€ãèŠãŠã¿ãŸãããïŒ
äŸ1ïŒ'self'ã䜿çšããåºæ¬çãªCSP
ãã®ããªã·ãŒã¯ãåäžãªãªãžã³ããã®ãªãœãŒã¹ã®ã¿ãèš±å¯ããŸãïŒ
Content-Security-Policy: default-src 'self'
äŸ2ïŒç¹å®ã®ãã¡ã€ã³ããã®ã¹ã¯ãªãããèš±å¯ãã
ãã®ããªã·ãŒã¯ãèªãã¡ã€ã³ãšä¿¡é Œã§ããCDNããã®ã¹ã¯ãªãããèš±å¯ããŸãïŒ
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com
äŸ3ïŒã€ã³ã©ã€ã³ã¹ã¯ãªãããšã¹ã¿ã€ã«ãç¡å¹ã«ãã
ãã®ããªã·ãŒã¯ã€ã³ã©ã€ã³ã¹ã¯ãªãããšã¹ã¿ã€ã«ãèš±å¯ãããXSSã«å¯Ÿãã匷åãªé²åŸ¡ãšãªããŸãïŒ
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'
éèŠïŒã€ã³ã©ã€ã³ã¹ã¯ãªãããç¡å¹ã«ããã«ã¯ãã€ã³ã©ã€ã³ã¹ã¯ãªãããå€éšãã¡ã€ã«ã«ç§»åããããã«HTMLããªãã¡ã¯ã¿ãªã³ã°ããå¿ èŠããããŸãã
äŸ4ïŒã€ã³ã©ã€ã³ã¹ã¯ãªããã«ãã³ã¹ã䜿çšãã
ã€ã³ã©ã€ã³ã¹ã¯ãªããã䜿çšããå¿ èŠãããå Žåã¯ããã³ã¹(æå·åŠçã«ã©ã³ãã ãªãäžåºŠã ã䜿çšãããããŒã¯ã³)ã䜿çšããŠç¹å®ã®ã€ã³ã©ã€ã³ã¹ã¯ãªãããããã¯ããã¯ã€ããªã¹ãã«ç»é²ããŸããããã¯'unsafe-inline'ãããå®å šã§ãããµãŒããŒã¯ãªã¯ãšã¹ãããšã«äžæã®ãã³ã¹ãçæãããããCSPããããŒãš<script>ã¿ã°ã®äž¡æ¹ã«å«ããå¿ èŠããããŸãã
Content-Security-Policy: default-src 'self'; script-src 'nonce-r4nd0mN0nc3'; style-src 'self'
<script nonce="r4nd0mN0nc3"> console.log('Inline script'); </script>
泚ïŒãªã¯ãšã¹ãããšã«æ°ãããã³ã¹ãçæããããšãå¿ããªãã§ãã ããããã³ã¹ãåå©çšããŠã¯ãããŸããïŒ
äŸ5ïŒã€ã³ã©ã€ã³ã¹ã¿ã€ã«ã«ããã·ã¥ã䜿çšãã
ãã³ã¹ãšåæ§ã«ãããã·ã¥ã䜿çšããŠç¹å®ã®ã€ã³ã©ã€ã³<style>ãããã¯ããã¯ã€ããªã¹ãã«ç»é²ã§ããŸããããã¯ãã¹ã¿ã€ã«ã³ã³ãã³ãã®SHA256ãSHA384ããŸãã¯SHA512ããã·ã¥ãçæããããšã«ãã£ãŠè¡ãããŸãã
Content-Security-Policy: default-src 'self'; style-src 'sha256-HASHEDSTYLES'
<style sha256="HASHEDSTYLES"> body { background-color: #f0f0f0; } </style>
泚ïŒããã·ã¥ã¯ãã³ã¹ãããæè»æ§ãäœããã¹ã¿ã€ã«ã³ã³ãã³ããå°ãã§ã倿Žããããšããã·ã¥ã¯ç¡å¹ã«ãªããŸãã
äŸ6ïŒCSPéåãå ±åãã
CSPéåãç£èŠããã«ã¯ãreport-uriãŸãã¯report-toãã£ã¬ã¯ãã£ãã䜿çšããŸãïŒ
Content-Security-Policy: default-src 'self'; report-to csp-endpoint;
ãŸããReport-ToããããŒãèšå®ããå¿
èŠããããŸããReport-ToããããŒã¯1ã€ä»¥äžã®ã¬ããŒãã£ã³ã°ã°ã«ãŒããå®çŸ©ããã¬ããŒããã©ãã«ãã©ã®ããã«éä¿¡ããããæå®ããŸãã
Report-To: {"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"https://example.com/csp-report"}]}
CSPã®ãã¹ããšãããã€
CSPãå®è£
ããã«ã¯ãæ
éãªèšç»ãšãã¹ããå¿
èŠã§ãããŸãå¶éã®å³ããããªã·ãŒããå§ããå¿
èŠã«å¿ããŠåŸã
ã«ç·©ããŠãããŸããContent-Security-Policy-Report-OnlyããããŒã䜿çšããŠããªãœãŒã¹ããããã¯ããã«ããªã·ãŒããã¹ãããŸãããã®ããããŒã¯ããªã·ãŒã匷å¶ããã«éåãå ±åãããããæ¬çªç°å¢ã«ãããã€ããåã«åé¡ãç¹å®ããŠä¿®æ£ããããšãã§ããŸãã
Content-Security-Policy-Report-Only: default-src 'self'; report-to csp-endpoint;
ãã©ãŠã¶ã«ãã£ãŠçæãããã¬ããŒããåæããŠéåãç¹å®ããããã«å¿ããŠããªã·ãŒã調æŽããŸããããªã·ãŒãæ£ããæ©èœããŠãããšç¢ºä¿¡ã§ããããContent-Security-PolicyããããŒã䜿çšããŠãããã€ããŸãã
CSPã®ãã¹ããã©ã¯ãã£ã¹
- default-srcããå§ããïŒåžžã«
default-srcãå®çŸ©ããŠãããŒã¹ã©ã€ã³ãšãªãããªã·ãŒã確ç«ããŸãã - å ·äœçã«æå®ããïŒç¹å®ã®ãã£ã¬ã¯ãã£ããšãœãŒã¹ãªã¹ãããŒã¯ãŒãã䜿çšããŠãããªã·ãŒã®ç¯å²ãéå®ããŸãã
- 'unsafe-inline'ãš'unsafe-eval'ãé¿ããïŒãããã®ããŒã¯ãŒãã¯CSPãå€§å¹ ã«åŒ±äœåããããããå¯èœãªéãé¿ããã¹ãã§ãã
- ã€ã³ã©ã€ã³ã¹ã¯ãªãããšã¹ã¿ã€ã«ã«ã¯ãã³ã¹ãŸãã¯ããã·ã¥ã䜿çšããïŒã€ã³ã©ã€ã³ã¹ã¯ãªãããã¹ã¿ã€ã«ã䜿çšããå¿ èŠãããå Žåã¯ããã³ã¹ãŸãã¯ããã·ã¥ã䜿çšããŠç¹å®ã®ã³ãŒããããã¯ããã¯ã€ããªã¹ãã«ç»é²ããŸãã
- CSPéåãç£èŠããïŒ
report-uriãŸãã¯report-toãã£ã¬ã¯ãã£ãã䜿çšããŠCSPéåãç£èŠããããã«å¿ããŠããªã·ãŒã調æŽããŸãã - 培åºçã«ãã¹ãããïŒ
Content-Security-Policy-Report-OnlyããããŒã䜿çšããŠãæ¬çªç°å¢ã«ãããã€ããåã«ããªã·ãŒããã¹ãããŸãã - ååŸ©ãšæ¹åïŒCSPã¯äžåºŠèšå®ããã°çµããã§ã¯ãããŸãããã¢ããªã±ãŒã·ã§ã³ãè åšã®ç¶æ³ã®å€åã«é©å¿ããããã«ãããªã·ãŒãç¶ç¶çã«ç£èŠããæ¹åããŠãã ããã
ãªãªãžã³éãªãœãŒã¹å ±æ(CORS)ãšã¯ïŒ
ãªãªãžã³éãªãœãŒã¹å ±æ(CORS)ã¯ããããªãªãžã³(ãã¡ã€ã³)ã®ãŠã§ãããŒãžããç°ãªããªãªãžã³ã®ãªãœãŒã¹ã«ã¢ã¯ã»ã¹ã§ããããã«ããä»çµã¿ã§ããããã©ã«ãã§ã¯ããã©ãŠã¶ã¯åäžãªãªãžã³ããªã·ãŒã匷å¶ããã¹ã¯ãªããããã®ã¹ã¯ãªããã®çæå ãšã¯ç°ãªããªãªãžã³ã«ãªã¯ãšã¹ããè¡ãããšãé²ããŸããCORSã¯ããã®å¶éãéžæçã«ç·©åããæ¹æ³ãæäŸããæ£åœãªãªãªãžã³éãªã¯ãšã¹ããèš±å¯ãã€ã€ãæªæã®ããæ»æããä¿è·ããŸãã
åäžãªãªãžã³ããªã·ãŒã®çè§£
åäžãªãªãžã³ããªã·ãŒã¯ããããŠã§ããµã€ãã®æªæã®ããã¹ã¯ãªãããå¥ã®ãŠã§ããµã€ãã®æ©å¯ããŒã¿ã«ã¢ã¯ã»ã¹ããã®ãé²ãåºæ¬çãªã»ãã¥ãªãã£ã¡ã«ããºã ã§ãããªãªãžã³ã¯ã¹ããŒã (ãããã³ã«)ããã¹ã(ãã¡ã€ã³)ãããŒãã«ãã£ãŠå®çŸ©ãããŸãã2ã€ã®URLãåããªãªãžã³ãæã€ã®ã¯ãã¹ããŒã ããã¹ããããŒãããã¹ãŠåãå Žåã®ã¿ã§ãã
äŸïŒ
https://www.example.com/app1/index.htmlãšhttps://www.example.com/app2/index.htmlã¯åããªãªãžã³ã§ããhttps://www.example.com/index.htmlãšhttp://www.example.com/index.htmlã¯ç°ãªããªãªãžã³ã§ã (ã¹ããŒã ãç°ãªã)ãhttps://www.example.com/index.htmlãšhttps://sub.example.com/index.htmlã¯ç°ãªããªãªãžã³ã§ã (ãã¹ããç°ãªã)ãhttps://www.example.com:8080/index.htmlãšhttps://www.example.com:80/index.htmlã¯ç°ãªããªãªãžã³ã§ã (ããŒããç°ãªã)ã
CORSã®ä»çµã¿
ãŠã§ãããŒãžããªãªãžã³éãªã¯ãšã¹ããè¡ããšããã©ãŠã¶ã¯ãŸããµãŒããŒã«ãããªãã©ã€ãããªã¯ãšã¹ããéä¿¡ããŸããããªãã©ã€ããªã¯ãšã¹ãã¯HTTP OPTIONSã¡ãœããã䜿çšããå®éã®ãªã¯ãšã¹ãã䜿çšããHTTPã¡ãœãããšããããŒã瀺ãããããŒãå«ã¿ãŸãããµãŒããŒã¯ãã®åŸããªãªãžã³éãªã¯ãšã¹ããèš±å¯ãããŠãããã©ããã瀺ãããããŒã§å¿çããŸãã
ãµãŒããŒããªã¯ãšã¹ããèš±å¯ããå Žåãã¬ã¹ãã³ã¹ã«Access-Control-Allow-OriginããããŒãå«ããŸãããã®ããããŒã¯ããªãœãŒã¹ãžã®ã¢ã¯ã»ã¹ãèš±å¯ãããŠãããªãªãžã³ãæå®ããŸãããã©ãŠã¶ã¯ãã®åŸãå®éã®ãªã¯ãšã¹ããç¶è¡ããŸãããµãŒããŒããªã¯ãšã¹ããèš±å¯ããªãå ŽåãAccess-Control-Allow-OriginããããŒã¯å«ããããããã©ãŠã¶ã¯ãªã¯ãšã¹ãããããã¯ããŸãã
CORSããããŒïŒè©³çްãªè§£èª¬
CORSã¯ããã©ãŠã¶ãšãµãŒããŒéã®éä¿¡ã«HTTPããããŒãå©çšããŸããäž»èŠãªCORSããããŒã¯ä»¥äžã®éãã§ãïŒ
- Access-Control-Allow-Origin: ãªãœãŒã¹ãžã®ã¢ã¯ã»ã¹ãèš±å¯ãããŠãããªãªãžã³ãæå®ããŸãããã®ããããŒã«ã¯ç¹å®ã®ãªãªãžã³(äŸïŒ
https://www.example.com)ãã¯ã€ã«ãã«ãŒã(*)ããŸãã¯nullãå«ããããšãã§ããŸãã*ã䜿çšãããšä»»æã®ãªãªãžã³ããã®ãªã¯ãšã¹ããèš±å¯ãããŸãããã»ãã¥ãªãã£äžã®çç±ããäžè¬çã«ã¯æšå¥šãããŸããã`null`ã®äœ¿çšã¯ããªãœãŒã¹ã`file://`ãããã³ã«ãããŒã¿URIã䜿çšããŠååŸãããå Žåãªã©ã®ãäžéæãªã¬ã¹ãã³ã¹ãã«ã®ã¿é©ããŠããŸãã - Access-Control-Allow-Methods: ãªãªãžã³éãªã¯ãšã¹ãã§èš±å¯ãããHTTPã¡ãœãããæå®ããŸã(äŸïŒ
GET, POST, PUT, DELETE)ã - Access-Control-Allow-Headers: ãªãªãžã³éãªã¯ãšã¹ãã§èš±å¯ãããHTTPããããŒãæå®ããŸããããã¯ã«ã¹ã¿ã ããããŒãæ±ãäžã§éèŠã§ãã
- Access-Control-Allow-Credentials: ãã©ãŠã¶ããªãªãžã³éãªã¯ãšã¹ãã«ã¯ã¬ãã³ã·ã£ã«(äŸïŒã¯ãããŒãèªèšŒããããŒ)ãå«ããã¹ããã©ããã瀺ããŸããã¯ã¬ãã³ã·ã£ã«ãèš±å¯ããã«ã¯ããã®ããããŒã
trueã«èšå®ããå¿ èŠããããŸãã - Access-Control-Expose-Headers: ã¯ã©ã€ã¢ã³ãã«å ¬éã§ããããããŒãæå®ããŸããããã©ã«ãã§ã¯ãéãããããããŒã»ããã®ã¿ãå ¬éãããŸãã
- Access-Control-Max-Age: ãã©ãŠã¶ãããªãã©ã€ããªã¯ãšã¹ãããã£ãã·ã¥ã§ããæå€§æé(ç§åäœ)ãæå®ããŸãã
- Origin: ããã¯ãªã¯ãšã¹ãã®ãªãªãžã³ã瀺ãããã«ãã©ãŠã¶ããéä¿¡ããããªã¯ãšã¹ãããããŒã§ãã
- Vary: äžè¬çãªHTTPããããŒã§ãããCORSã«ãšã£ãŠéèŠã§ãã`Access-Control-Allow-Origin`ãåçã«çæãããå Žåãã¬ã¹ãã³ã¹ã`Origin`ãªã¯ãšã¹ãããããŒã«åºã¥ããŠå€åããããšããã£ãã·ã¥ã¡ã«ããºã ã«æç€ºããããã«ãã¬ã¹ãã³ã¹ã«`Vary: Origin`ããããŒãå«ããã¹ãã§ãã
CORSã®å®è·µäŸ
CORSèšå®ã®å®è·µçãªäŸãããã€ãèŠãŠã¿ãŸãããïŒ
äŸ1ïŒç¹å®ã®ãªãªãžã³ããã®ãªã¯ãšã¹ããèš±å¯ãã
ãã®èšå®ã¯https://www.example.comããã®ãªã¯ãšã¹ãã®ã¿ãèš±å¯ããŸãïŒ
Access-Control-Allow-Origin: https://www.example.com
äŸ2ïŒä»»æã®ãªãªãžã³ããã®ãªã¯ãšã¹ããèš±å¯ãã(éæšå¥š)
ãã®èšå®ã¯ä»»æã®ãªãªãžã³ããã®ãªã¯ãšã¹ããèš±å¯ããŸããã»ãã¥ãªãã£ãªã¹ã¯ãããããå¯èœæ§ããããããæ³šæããŠäœ¿çšããŠãã ããïŒ
Access-Control-Allow-Origin: *
äŸ3ïŒç¹å®ã®ã¡ãœãããšããããŒãèš±å¯ãã
ãã®èšå®ã¯GETãPOSTãPUTã¡ãœãããããã³Content-TypeãšAuthorizationããããŒãèš±å¯ããŸãïŒ
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization
äŸ4ïŒã¯ã¬ãã³ã·ã£ã«ãèš±å¯ãã
ã¯ã¬ãã³ã·ã£ã«(äŸïŒã¯ãããŒ)ãèš±å¯ããã«ã¯ãAccess-Control-Allow-Credentialsãtrueã«èšå®ããç¹å®ã®ãªãªãžã³ãæå®ããå¿
èŠããããŸã(ã¯ã¬ãã³ã·ã£ã«ãèš±å¯ããå Žåã*ã¯äœ¿çšã§ããŸãã)ïŒ
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Credentials: true
ãŸããJavaScriptã®fetch/XMLHttpRequestãªã¯ãšã¹ãã§credentials: 'include'ãèšå®ããå¿
èŠããããŸãã
fetch('https://api.example.com/data', {
credentials: 'include'
})
CORSããªãã©ã€ããªã¯ãšã¹ã
ç¹å®ã®çš®é¡ã®ãªãªãžã³éãªã¯ãšã¹ã(äŸïŒã«ã¹ã¿ã ããããŒãæã€ãªã¯ãšã¹ãããGETãHEADãPOST(Content-Typeãapplication/x-www-form-urlencodedãmultipart/form-dataãtext/plainã®å Žå)以å€ã®ã¡ãœãããæã€ãªã¯ãšã¹ã)ã«å¯ŸããŠããã©ãŠã¶ã¯OPTIONSã¡ãœããã䜿çšããŠããªãã©ã€ããªã¯ãšã¹ããéä¿¡ããŸãããµãŒããŒã¯ãå®éã®ãªã¯ãšã¹ããèš±å¯ãããŠãããã©ããã瀺ãããã«ãé©åãªCORSããããŒã§ããªãã©ã€ããªã¯ãšã¹ãã«å¿çããå¿
èŠããããŸãã
ããªãã©ã€ããªã¯ãšã¹ããšã¬ã¹ãã³ã¹ã®äŸã§ãïŒ
ããªãã©ã€ããªã¯ãšã¹ã (OPTIONS):
OPTIONS /data HTTP/1.1
Origin: https://www.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, Authorization
ããªãã©ã€ãã¬ã¹ãã³ã¹ (200 OK):
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400
Access-Control-Max-AgeããããŒã¯ããã©ãŠã¶ãããªãã©ã€ãã¬ã¹ãã³ã¹ããã£ãã·ã¥ã§ããæéãæå®ããããªãã©ã€ããªã¯ãšã¹ãã®æ°ãæžãããŸãã
CORSãšJSONP
JSON with Padding (JSONP)ã¯ãåäžãªãªãžã³ããªã·ãŒãåé¿ããããã®å€ãæè¡ã§ããããããJSONPã«ã¯é倧ãªã»ãã¥ãªãã£ãªã¹ã¯ããããããCORSãåªå ããŠé¿ããã¹ãã§ããJSONPã¯ããŒãžã«<script>ã¿ã°ãæ³šå ¥ããããšã«äŸåããŠãããããã«ããä»»æã®ã³ãŒããå®è¡ãããå¯èœæ§ããããŸããCORSã¯ããªãªãžã³éãªã¯ãšã¹ããåŠçããããã®ããå®å šã§æè»ãªæ¹æ³ãæäŸããŸãã
CORSã®ãã¹ããã©ã¯ãã£ã¹
- *ã®äœ¿çšãé¿ããïŒ
Access-Control-Allow-OriginããããŒã§ã¯ã€ã«ãã«ãŒã(*)ã䜿çšãããšãä»»æã®ãªãªãžã³ããã®ãªã¯ãšã¹ããèš±å¯ãããŠããŸãããé¿ããŠãã ããã代ããã«ããªãœãŒã¹ãžã®ã¢ã¯ã»ã¹ãèš±å¯ãããŠããç¹å®ã®ãªãªãžã³ãæå®ããŸãã - ã¡ãœãããšããããŒãå
·äœçã«æå®ããïŒ
Access-Control-Allow-MethodsãšAccess-Control-Allow-HeadersããããŒã§èš±å¯ãããHTTPã¡ãœãããšããããŒãæ£ç¢ºã«æå®ããŸãã - Access-Control-Allow-Credentialsã¯æ
éã«äœ¿çšããïŒãªãªãžã³éãªã¯ãšã¹ãã§ã¯ã¬ãã³ã·ã£ã«(äŸïŒã¯ãããŒ)ãèš±å¯ããå¿
èŠãããå Žåã«ã®ã¿
Access-Control-Allow-Credentialsãæå¹ã«ããŸããã¯ã¬ãã³ã·ã£ã«ãèš±å¯ããããšã®ã»ãã¥ãªãã£äžã®æå³ãèªèããŠãã ããã - ããªãã©ã€ããªã¯ãšã¹ããä¿è·ããïŒãµãŒããŒãããªãã©ã€ããªã¯ãšã¹ããé©åã«åŠçããæ£ããCORSããããŒãè¿ãããšã確èªããŠãã ããã
- HTTPSã䜿çšããïŒãªãªãžã³ãšã¯ãã¹ãªãªãžã³ã§ã¢ã¯ã»ã¹ãããªãœãŒã¹ã®äž¡æ¹ã§åžžã«HTTPSã䜿çšããŠãã ãããããã¯äžéè æ»æããä¿è·ããã®ã«åœ¹ç«ã¡ãŸãã
- Vary: Origin: `Access-Control-Allow-Origin`ããããŒãåçã«çæããŠããå Žåã¯ããã£ãã·ã¥ã®åé¡ãé²ãããã«åžžã«`Vary: Origin`ããããŒãå«ããŠãã ããã
å®è·µã«ãããCSPãšCORSïŒçµã¿åãããã¢ãããŒã
CSPãšCORSã¯ã©ã¡ããã»ãã¥ãªãã£äžã®æžå¿µã«å¯ŸåŠããŸãããç°ãªãã¬ã€ã€ãŒã§åäœããçžäºã«è£å®çãªä¿è·ãæäŸããŸããCSPã¯ãã©ãŠã¶ãæªæã®ããã³ã³ãã³ããèªã¿èŸŒãã®ãé²ãããšã«çŠç¹ãåœãŠãCORSã¯ã©ã®ãªãªãžã³ããµãŒããŒäžã®ãªãœãŒã¹ã«ã¢ã¯ã»ã¹ã§ããããå¶åŸ¡ããããšã«çŠç¹ãåœãŠãŠããŸãã
CSPãšCORSãçµã¿åãããããšã§ããŠã§ãã¢ããªã±ãŒã·ã§ã³ã®ã»ãã¥ãªãã£äœå¶ãããå ç¢ã«ããããšãã§ããŸããããšãã°ãCSPã䜿çšããŠã¹ã¯ãªãããèªã¿èŸŒãŸãããœãŒã¹ãå¶éããCORSã䜿çšããŠã©ã®ãªãªãžã³ãAPIãšã³ããã€ã³ãã«ã¢ã¯ã»ã¹ã§ããããå¶åŸ¡ã§ããŸãã
äŸïŒCSPãšCORSã§APIãä¿è·ãã
https://api.example.comã§ãã¹ããããŠããAPIãhttps://www.example.comããã®ã¿ã¢ã¯ã»ã¹å¯èœã«ããããšããŸãããµãŒããŒã以äžã®ããããŒãè¿ãããã«èšå®ã§ããŸãïŒ
APIã¬ã¹ãã³ã¹ããã㌠(https://api.example.com):
Access-Control-Allow-Origin: https://www.example.com
Content-Type: application/json
ãããŠããŠã§ããµã€ã(https://www.example.com)ã以äžã®CSPããããŒã䜿çšããããã«èšå®ã§ããŸãïŒ
ãŠã§ããµã€ãCSPããã㌠(https://www.example.com):
Content-Security-Policy: default-src 'self'; script-src 'self'; connect-src 'self' https://api.example.com;
ãã®CSPããªã·ãŒã«ããããŠã§ããµã€ãã¯ã¹ã¯ãªãããèªã¿èŸŒã¿ãAPIã«æ¥ç¶ã§ããŸãããä»ã®ãã¡ã€ã³ããã¹ã¯ãªãããèªã¿èŸŒãã ãæ¥ç¶ãããããããšã¯ã§ããªããªããŸãã
çµè«
ã³ã³ãã³ãã»ãã¥ãªãã£ããªã·ãŒ(CSP)ãšãªãªãžã³éãªãœãŒã¹å ±æ(CORS)ã¯ãããã³ããšã³ãã¢ããªã±ãŒã·ã§ã³ã®ã»ãã¥ãªãã£ã匷åããããã®äžå¯æ¬ ãªããŒã«ã§ããCSPãšCORSãæ éã«èšå®ããããšã§ãXSSæ»æãããŒã¿ã€ã³ãžã§ã¯ã·ã§ã³æ»æããã®ä»ã®ã»ãã¥ãªãã£è匱æ§ã®ãªã¹ã¯ãå€§å¹ ã«åæžã§ããŸããå¶éã®å³ããããªã·ãŒããå§ãã培åºçã«ãã¹ãããã¢ããªã±ãŒã·ã§ã³ãšé²åããè åšã®ç¶æ³ã®å€åã«é©å¿ããããã«èšå®ãç¶ç¶çã«ç£èŠããã³æ¹åããããšãå¿ããªãã§ãã ãããããã³ããšã³ãã®ã»ãã¥ãªãã£ãåªå ããããšã§ããŠãŒã¶ãŒãä¿è·ãã仿¥ã®ãŸããŸãè€éåããããžã¿ã«äžçã§ãŠã§ãã¢ããªã±ãŒã·ã§ã³ã®å®å šæ§ã確ä¿ããããšãã§ããŸãã