è·¨åèæ¬æ»å» XSS æ¯æå¸¸è§ãå±å®³æå¤§çç½é¡µå®å ¨æ¼æ´ã

为äºé²æ¢å®ä»¬ï¼è¦éåå¾å¤ç¼ç¨æªæ½ï¼é常麻ç¦ãå¾å¤äººæåºï¼è½ä¸è½æ ¹æ¬ä¸è§£å³é®é¢ï¼æµè§å¨èªå¨ç¦æ¢å¤é¨æ³¨å ¥æ¶æèæ¬ï¼
è¿å°±æ¯"ç½é¡µå®å ¨æ¿ç"ï¼Content Security Policyï¼ç¼©å CSPï¼çæ¥åãæ¬æè¯¦ç»ä»ç»å¦ä½ä½¿ç¨ CSP 鲿¢ XSS æ»å»ã

ä¸ãç®ä»
CSP çå®è´¨å°±æ¯ç½ååå¶åº¦ï¼å¼åè æç¡®åè¯å®¢æ·ç«¯ï¼åªäºå¤é¨èµæºå¯ä»¥å è½½åæ§è¡ï¼çåäºæä¾ç½ååãå®çå®ç°åæ§è¡å ¨é¨ç±æµè§å¨å®æï¼å¼åè åªéæä¾é ç½®ã
CSP 大大å¢å¼ºäºç½é¡µçå®å ¨æ§ãæ»å»è å³ä½¿åç°äºæ¼æ´ï¼ä¹æ²¡æ³æ³¨å ¥èæ¬ï¼é¤éè¿æ§å¶äºä¸å°åå ¥äºç½ååçå¯ä¿¡ä¸»æºã
ä¸¤ç§æ¹æ³å¯ä»¥å¯ç¨ CSPãä¸ç§æ¯éè¿ HTTP 头信æ¯çContent-Security-Policyçåæ®µã

Content-Security-Policy: script-src 'self'; object-src 'none'; style-src cdn.example.org third-party.org; child-src https:
å¦ä¸ç§æ¯éè¿ç½é¡µç<meta>æ ç¾ã
<meta http-equiv="Content-Security-Policy" content="script-src 'self'; object-src 'none'; style-src cdn.example.org third-party.org; child-src https:">
ä¸é¢ä»£ç ä¸ï¼CSP åäºå¦ä¸é ç½®ã
- èæ¬ï¼åªä¿¡ä»»å½ååå
<object>æ ç¾ï¼ä¸ä¿¡ä»»ä»»ä½URLï¼å³ä¸å 载任ä½èµæº- æ ·å¼è¡¨ï¼åªä¿¡ä»»
cdn.example.orgåthird-party.org- æ¡æ¶ï¼frameï¼ï¼å¿ 须使ç¨HTTPSåè®®å è½½
- å ¶ä»èµæºï¼æ²¡æéå¶
å¯ç¨åï¼ä¸ç¬¦å CSP çå¤é¨èµæºå°±ä¼è¢«é»æ¢å è½½ã
Chrome çæ¥éä¿¡æ¯ã

Firefox çæ¥éä¿¡æ¯ã

äºãéå¶é项
CSP æä¾äºå¾å¤éå¶éé¡¹ï¼æ¶åå®å ¨çå个æ¹é¢ã
2.1 èµæºå è½½éå¶
以ä¸é项éå¶åç±»èµæºçå è½½ã
script-srcï¼å¤é¨èæ¬style-srcï¼æ ·å¼è¡¨img-srcï¼å¾åmedia-srcï¼åªä½æä»¶ï¼é³é¢åè§é¢ï¼font-srcï¼å使件object-srcï¼æä»¶ï¼æ¯å¦ Flashï¼child-srcï¼æ¡æ¶frame-ancestorsï¼åµå ¥çå¤é¨èµæºï¼æ¯å¦<frame>ã<iframe>ã<embed>å<applet>ï¼connect-srcï¼HTTP è¿æ¥ï¼éè¿ XHRãWebSocketsãEventSourceçï¼worker-srcï¼workerèæ¬manifest-srcï¼manifest æä»¶
2.2 default-src
default-srcç¨æ¥è®¾ç½®ä¸é¢å个é项çé»è®¤å¼ã
Content-Security-Policy: default-src 'self'
ä¸é¢ä»£ç éå¶ææçå¤é¨èµæºï¼é½åªè½ä»å½åååå è½½ã
å¦æåæ¶è®¾ç½®æä¸ªå项éå¶ï¼æ¯å¦font-srcï¼ådefault-srcï¼åè
ä¼è¦çåè
ï¼å³å使件ä¼éç¨font-srcçå¼ï¼å
¶ä»èµæºä¾ç¶éç¨default-srcçå¼ã
2.3 URL éå¶
ææ¶ï¼ç½é¡µä¼è·å ¶ä» URL åçèç³»ï¼è¿æ¶ä¹å¯ä»¥å 以éå¶ã
frame-ancestorsï¼éå¶åµå ¥æ¡æ¶çç½é¡µbase-uriï¼éå¶<base#href>form-actionï¼éå¶<form#action>
2.4 å ¶ä»éå¶
å ¶ä»ä¸äºå®å ¨ç¸å ³çåè½ï¼ä¹æ¾å¨äº CSP éé¢ã
block-all-mixed-contentï¼HTTPS ç½é¡µä¸å¾å è½½ HTTP èµæºï¼æµè§å¨å·²ç»é»è®¤å¼å¯ï¼upgrade-insecure-requestsï¼èªå¨å°ç½é¡µä¸ææå è½½å¤é¨èµæºç HTTP 龿¥æ¢æ HTTPS åè®®plugin-typesï¼éå¶å¯ä»¥ä½¿ç¨çæä»¶æ ¼å¼sandboxï¼æµè§å¨è¡ä¸ºçéå¶ï¼æ¯å¦ä¸è½æå¼¹åºçªå£çã
2.5 report-uri
ææ¶ï¼æä»¬ä¸ä»
叿鲿¢ XSSï¼è¿å¸æè®°å½æ¤ç±»è¡ä¸ºãreport-uriå°±ç¨æ¥åè¯æµè§å¨ï¼åºè¯¥ææ³¨å
¥è¡ä¸ºæ¥åç»åªä¸ªç½åã
Content-Security-Policy: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;
ä¸é¢ä»£ç æå®ï¼å°æ³¨å
¥è¡ä¸ºæ¥åç»/my_amazing_csp_report_parserè¿ä¸ª URLã
æµè§å¨ä¼ä½¿ç¨POSTæ¹æ³ï¼åéä¸ä¸ªJSON对象ï¼ä¸é¢æ¯ä¸ä¸ªä¾åã
{ "csp-report": { "document-uri": "http://example.org/page.html", "referrer": "http://evil.example.com/", "blocked-uri": "http://evil.example.com/evil.js", "violated-directive": "script-src 'self' https://apis.google.com", "original-policy": "script-src 'self' https://apis.google.com; report-uri http://example.org/my_amazing_csp_report_parser" } }

ä¸ãContent-Security-Policy-Report-Only
é¤äºContent-Security-Policyï¼è¿æä¸ä¸ªContent-Security-Policy-Report-Onlyåæ®µï¼è¡¨ç¤ºä¸æ§è¡éå¶é项ï¼åªæ¯è®°å½è¿åéå¶çè¡ä¸ºã
å®å¿
é¡»ä¸report-urié项é
å使ç¨ã
Content-Security-Policy-Report-Only: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;
åãé项å¼
æ¯ä¸ªéå¶é项å¯ä»¥è®¾ç½®ä»¥ä¸å ç§å¼ï¼è¿äºå¼å°±ææäºç½ååã
- 主æºåï¼
example.orgï¼https://example.com:443- è·¯å¾åï¼
example.org/resources/js/- éé 符ï¼
*.example.orgï¼*://*.example.com:*ï¼è¡¨ç¤ºä»»æåè®®ãä»»æåååãä»»æç«¯å£ï¼- åè®®åï¼
https:ãdata:- å ³é®å
'self'ï¼å½åååï¼éè¦å å¼å·- å ³é®å
'none'ï¼ç¦æ¢å 载任ä½å¤é¨èµæºï¼éè¦å å¼å·
å¤ä¸ªå¼ä¹å¯ä»¥å¹¶åï¼ç¨ç©ºæ ¼åéã
Content-Security-Policy: script-src 'self' https://apis.google.com
妿åä¸ä¸ªéå¶é项使ç¨å¤æ¬¡ï¼åªæç¬¬ä¸æ¬¡ä¼çæã
# é误çåæ³ script-src https://host1.com; script-src https://host2.com # æ£ç¡®çåæ³ script-src https://host1.com https://host2.com
妿ä¸è®¾ç½®æä¸ªéå¶é项ï¼å°±æ¯é»è®¤å 许任ä½å¼ã
äºãscript-src çç¹æ®å¼
é¤äºå¸¸è§å¼ï¼script-srcè¿å¯ä»¥è®¾ç½®ä¸äºç¹æ®å¼ã注æï¼ä¸é¢è¿äºå¼é½å¿
é¡»æ¾å¨åå¼å·éé¢ã
'unsafe-inline'ï¼å 许æ§è¡é¡µé¢å åµç<script>æ ç¾åäºä»¶çå¬å½æ°unsafe-evalï¼å 许å°å符串å½ä½ä»£ç æ§è¡ï¼æ¯å¦ä½¿ç¨evalãsetTimeoutãsetIntervalåFunctionç彿°ã- nonceå¼ï¼æ¯æ¬¡HTTPååºç»åºä¸ä¸ªæætokenï¼é¡µé¢å åµèæ¬å¿ é¡»æè¿ä¸ªtokenï¼æä¼æ§è¡
- hashå¼ï¼ååºå 许æ§è¡çèæ¬ä»£ç çHashå¼ï¼é¡µé¢å åµèæ¬çåå¸å¼åªæå»åçæ åµä¸ï¼æè½æ§è¡ã
nonceå¼çä¾åå¦ä¸ï¼æå¡å¨åéç½é¡µçæ¶åï¼åè¯æµè§å¨ä¸ä¸ªéæºçæçtokenã
Content-Security-Policy: script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa'
页é¢å åµèæ¬ï¼å¿ é¡»æè¿ä¸ªtokenæè½æ§è¡ã
<script nonce=EDNnf03nceIOfn39fn3e9h3sdfa> // some code </script>
hashå¼çä¾åå¦ä¸ï¼æå¡å¨ç»åºä¸ä¸ªå 许æ§è¡ç代ç çhashå¼ã
Content-Security-Policy: script-src 'sha256-qznLcsROx4GACP2dm0UCKCzCG-HiZ1guq6ZZDob_Tng='
ä¸é¢ç代ç å°±ä¼å 许æ§è¡ï¼å 为hashå¼ç¸ç¬¦ã
<script>alert('Hello, world.');</script>
注æï¼è®¡ç®hashå¼çæ¶åï¼<script>æ ç¾ä¸ç®å¨å ã
é¤äºscript-srcé项ï¼nonceå¼åhashå¼è¿å¯ä»¥ç¨å¨style-srcéé¡¹ï¼æ§å¶é¡µé¢å
åµçæ ·å¼è¡¨ã
å ãæ³¨æç¹
ï¼1ï¼script-srcåobject-srcæ¯å¿
设çï¼é¤é设置äºdefault-srcã
å 为æ»å»è
åªè¦è½æ³¨å
¥èæ¬ï¼å
¶ä»éå¶é½å¯ä»¥è§é¿ãèobject-srcå¿
设æ¯å 为 Flash éé¢å¯ä»¥æ§è¡å¤é¨èæ¬ã
ï¼2ï¼script-srcä¸è½ä½¿ç¨unsafe-inlineå
³é®åï¼é¤éä¼´éä¸ä¸ªnonceå¼ï¼ï¼ä¹ä¸è½å
许设置data:URLã
ä¸é¢æ¯ä¸¤ä¸ªæ¶ææ»å»çä¾åã
<img src="x" onerror="evil()"> <script src="data:text/javascript,evil()"></script>
ï¼3ï¼å¿ é¡»ç¹å«æ³¨æ JSONP çåè°å½æ°ã
<script src="/path/jsonp?callback=alert(document.domain)//"> </script>
ä¸é¢ç代ç ä¸ï¼è½ç¶å è½½çèæ¬æ¥èªå½åååï¼ä½æ¯éè¿æ¹ååè°å½æ°ï¼æ»å»è ä¾ç¶å¯ä»¥æ§è¡æ¶æä»£ç ã
ä¸ãåè龿¥
- CSP Is Dead, Long Live CSP! , by Lukas Weichselbaum
- An Introduction to Content Security Policy, by Mike West
ï¼å®ï¼

straying 说ï¼
æè°¢æå¦ã
2016å¹´9æ13æ¥ 09:41 | # | å¼ç¨
zhoukekestar 说ï¼
å ³äºwebå®å ¨ï¼è¿ä¸ªrepoä¹å¯ä»¥çä¸ä¸ï¼https://github.com/FallibleInc/security-guide-for-developers
2016å¹´9æ13æ¥ 09:48 | # | å¼ç¨
jon 说ï¼
ææ¶è·ï¼httpä¿¡æ¯å¤´çä½ç¨è¿æ¯å¾å¤§ç~~~
2016å¹´9æ13æ¥ 10:27 | # | å¼ç¨
Alex 说ï¼
å³°å¥ï¼
ç½ç»ä¸ä¼ æçä½ ä»¬é¿éå®å ¨é¨é¨çåå·¥å 为使ç¨èæ¬çå·æé¥¼è¢«å¼é¤çäºä»¶ï¼æ¯ççåï¼
2016å¹´9æ13æ¥ 21:47 | # | å¼ç¨
æ 说ï¼
å¦ä¹ äºï¼è¿ä¸ªä½çæ¬çæµè§å¨ä¸ä¸å®æ¯æçå§
2016å¹´9æ13æ¥ 22:17 | # | å¼ç¨
Loyalsoldier 说ï¼
请é®çæ£ç¨å° Web å¼åä¸ï¼éè¦æä¹åï¼è¿æ¯è¯´ï¼å¤§é¨å Web æ¡æ¶å·²ç»å ç½®äºè¿äºåè½ï¼ä¸éè¦å¼åè æ å¿ï¼å¦æå¯ä»¥çè¯ï¼éº»ç¦è®²ä¸è®²å大 Web æ¡æ¶é½æ¯æä¹å¤çè¿äºé®é¢çï¼
2016å¹´9æ15æ¥ 15:02 | # | å¼ç¨
墿¾æ¾å客 说ï¼
ä»ç¾åº¦ç¹è¿æ¥çï¼æ¯æä¸ä¸ï¼å¸æç«é¿æ¨å¤åºä¸äºå¥½æç« ã
2016å¹´9æ19æ¥ 20:26 | # | å¼ç¨
å°åªä½ 说ï¼
æä»¬ä¹ç¨å°äºç§»å¨ç«¯ å±è½è¿è¥åå¹¿åæ³¨å ¥ï¼è¿æ¯å¾èµçã
2016å¹´9æ23æ¥ 13:59 | # | å¼ç¨
å°åªä½ 说ï¼
æä»¬ä¹ç¨å°äºç§»å¨ç«¯ å±è½è¿è¥åå¹¿åæ³¨å ¥ï¼è¿æ¯å¾èµçã
2016å¹´9æ23æ¥ 14:12 | # | å¼ç¨
AbnerChou 说ï¼
æä¸ç¹çæï¼æéçãå¦æè®¾ç½®äºHSTSï¼è¿æå¿ è¦CSPä¹ï¼
2016å¹´9æ23æ¥ 22:47 | # | å¼ç¨
xgqfrms 说ï¼
å 容å®å ¨çç¥ !== ç½é¡µå®å ¨æ¿ç
2016å¹´10æ14æ¥ 14:04 | # | å¼ç¨
é¾ è¯´ï¼
IE10 å IE11 æ ¹æ¬å°±ä¸æ¯æï¼éåå°±æ¯åå¥èå·²
2016å¹´10æ18æ¥ 17:33 | # | å¼ç¨
anonymous 说ï¼
æè°¢é®èå¸ååºå¹²è´§äº
2016å¹´10æ19æ¥ 10:09 | # | å¼ç¨
fedor 说ï¼
æç« éä¿ææï¼æè°¢é®èå¸ã
2016å¹´11æ21æ¥ 11:19 | # | å¼ç¨
è½»å¦çº¸å¼ 说ï¼
ã2.1 èµæºå è½½éå¶ãé¨åç frame-ancestors åºè¯¥æ¯ frame-src å§ã
2017å¹´1æ 5æ¥ 03:57 | # | å¼ç¨
ç½è²é£è½¦ 说ï¼
ææä¸ªçé®å¦æweb serveré ç½®äºcspï¼htmlæä»¶ä¸ä¹ç¨metaé ç½®äºcspï¼ä½æ¯é ç½®çvalueæ¯ä¸åçï¼è¿ä¼æ¯ä»ä¹ç»æ
2017å¹´2æ16æ¥ 22:10 | # | å¼ç¨
éµé 说ï¼
åäºä¸ªå°å®éªï¼å¨ChromeåSafariä¸ï¼æç»çæçCSPå®å ¨çç¥æ¯æéèå´æå°çé£ä¸ªï¼ä¸CSPæ¥èªHTTP response headerè¿æ¯meta http-equivæ å ³ã
2017å¹´3æ15æ¥ 16:18 | # | å¼ç¨
å¼ å¸ è¯´ï¼
å 容å®å ¨çç¥æ¯ç½é¡µå®å ¨çç¥çåé
2017å¹´5æ12æ¥ 15:50 | # | å¼ç¨
éªéªçæ 说ï¼
"ï¼2ï¼script-srcä¸è½ä½¿ç¨unsafe-inlineå ³é®åï¼é¤éä¼´éä¸ä¸ªnonceå¼ï¼ï¼ä¹ä¸è½å 许设置data:URLã"
è¿ä¸ç¹å¥½åæ¯éçãæ ¹æ®âhttps://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Content-Security-Policy/script-srcâçèµæï¼æ¯è¯´å¦æè®¾ç½®äº 'nonce' å°±ä¼å¿½ç¥ 'unsafe-inline'ï¼å¹¶ä¸æ¯ 'unsafe-inline' éè¦ä¼´éç 'nonce'ã
2018å¹´9æ 3æ¥ 19:27 | # | å¼ç¨
æ´æ 说ï¼
å¤§ä½¬ï¼æè¢«ä¸ä¸ªCSPçé®é¢å°ä½äºï¼æ±å¸®å©ï¼
å®¢æ·æåºè¦ä¿®å¤CSPçé®é¢ï¼æå°±è®¾å®äºï¼script-src 'self' 'unsafe-eval' 'unsafe-inline';
客æ·è¯´ä¸è½ç¨'unsafe-inline'ï¼è¦ç¨nonceï¼
æå°±ä¿®æ¹ä¸ºscript-src 'self' 'unsafe-eval' 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa'ï¼
è¿æ ·OKï¼ä½æ¯åºç°ä¸ä¸ªæ°çé®é¢ï¼JSPä¸é¢ççå¬äºä»¶å ¨é¨é½æ¥éï¼ä¾å¦ï¼onloadï¼onchangeï¼onblur.....ï¼
é¤äºä»¥ä¸2ç§åæ³å¤ï¼ææ²¡æå ¶ä»åæ³æ¥è§£å³ï¼
1. æ·»å å'unsafe-inline'
2. document.getElementById("userId").addEventListener('focus', chgOnFocusBgColor(this)); -- > è¿ä¸ªä¿®æ¹é太大äº
2018å¹´11æ 7æ¥ 15:39 | # | å¼ç¨
æ´æ 说ï¼
没éï¼chrome æµè¯ï¼æ·»å äºnonce, ä¼å¿½ç¥'unsafe-inline'
2018å¹´11æ 7æ¥ 15:42 | # | å¼ç¨
kevin_chen 说ï¼
httpæ¯éæçï¼ææ¯ä¸è¥è¿å䏿¯å¯ä»¥å°è¿ä¸ªhttp头é¨å段å é¤åï¼
2018å¹´11æ15æ¥ 09:46 | # | å¼ç¨
alamo 说ï¼
妿æ¯NGINXæå¡è®¾ç½®äºcsp头ï¼httpçmetaæ ç¾ä¹è®¾ç½®äºcsp,两个å 容ä¸ä¸æ ·ï¼ä»¥åªä¸ªä¸ºåå
2019å¹´8æ21æ¥ 10:52 | # | å¼ç¨
seekei 说ï¼
å¨httpsä¸çiframeéï¼å¦æå è½½httpï¼æµè§å¨ä¼æ¥å ³äºâæ··åå 容âçé误ãå¦æè®¾ç½®csp default-src '*'ï¼é£å¯ä»¥ç»è¿è¿ä¸ªéå¶åï¼
2019å¹´10æ 9æ¥ 15:44 | # | å¼ç¨
yoghurt 说ï¼
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CSP
CSPç¿»è¯æå 容å®å ¨çç¥ä¼æ´åç¡®ç¹ã
2021å¹´10æ19æ¥ 11:14 | # | å¼ç¨
éå ç 说ï¼
ææ³æ¾å¼å¯¹é³è§é¢çhttpséå¶ï¼meta æä¹åå¢
2021å¹´10æ26æ¥ 15:15 | # | å¼ç¨
å¿åçç« è¯´ï¼
nonceä½ç¨äºå«ænonceå¼ç>script>>/script>代ç åï¼ä¸å«ä¸nonceåçscriptä¼è¢«blockï¼ unsafe-inline ä½ç¨äºè¡å jsï¼è¿ä¸¤è æ¯å¯ä»¥åæ¶è®¾ç½®ï¼ä¸ä¼è°è¦çè°ã
2022å¹´6æ 9æ¥ 11:56 | # | å¼ç¨
crk 说ï¼
ä»å¤©å好æéæ±è®¾ç½®æµè§å¨å®å ¨çç¥ï¼è°¢è°¢
2022å¹´11æ18æ¥ 17:37 | # | å¼ç¨