นโยบายรักษาความปลอดภัยเนื้อหาสามารถลดความเสี่ยงและผลกระทบของการโจมตี Cross-site Scripting ในเบราว์เซอร์รุ่นใหม่ได้อย่างมาก
โมเดลความปลอดภัยของเว็บจะอิงตามนโยบายต้นทางเดียวกัน ตัวอย่างเช่น
โค้ดจาก https://mybank.com
ต้องมีสิทธิ์เข้าถึงเฉพาะข้อมูลของ https://mybank.com
และhttps://evil.example.com
ต้องไม่เคยได้รับอนุญาตให้เข้าถึง
ตามทฤษฎีแล้ว แต่ละต้นทางนั้นแยกออกจากเว็บอื่นๆ เพื่อให้นักพัฒนาซอฟต์แวร์มีแซนด์บ็อกซ์ที่ปลอดภัย แต่ในทางปฏิบัติ ผู้โจมตีค้นพบวิธี
มากมายที่จะโค่นระบบ
ตัวอย่างเช่น การโจมตีแบบ cross-site Scripting (XSS) หลีกเลี่ยงนโยบายต้นทางเดียวกันโดยการหลอกให้เว็บไซต์ส่งโค้ดที่เป็นอันตรายไปพร้อมกับเนื้อหาที่ต้องการ ซึ่งเป็นปัญหาใหญ่เนื่องจากเบราว์เซอร์จะเชื่อถือโค้ดทั้งหมดที่ปรากฏในหน้าเว็บว่าเป็นส่วนหนึ่งของต้นทางการรักษาความปลอดภัยของหน้านั้นโดยชอบตามกฎหมาย Cheat Sheet ของ XSS เป็นวิธีการที่เก่าแล้วซึ่งนำมาจากวิธีการต่างๆ ที่ผู้โจมตีอาจใช้เพื่อละเมิดความเชื่อมั่นนี้โดยการแทรกโค้ดที่เป็นอันตราย หากผู้โจมตีแทรกโค้ดใดก็ตามได้สำเร็จ ผู้โจมตีจะบุกรุกเซสชันของผู้ใช้และเข้าถึงข้อมูลส่วนตัวได้
หน้านี้สรุปนโยบายรักษาความปลอดภัยเนื้อหา (CSP) ว่าเป็นกลยุทธ์ในการลดความเสี่ยงและผลกระทบของการโจมตี XSS ในเบราว์เซอร์สมัยใหม่
องค์ประกอบของ CSP
หากต้องการใช้ CSP ที่มีประสิทธิภาพ ให้ทำตามขั้นตอนต่อไปนี้
- ใช้รายการที่อนุญาตเพื่อแจ้งลูกค้าว่าผลิตภัณฑ์ใดได้รับอนุญาตและไม่อนุญาต
- ดูคำสั่งที่ใช้ได้
- เรียนรู้เกี่ยวกับคำหลักที่ใช้
- จำกัดการใช้โค้ดในบรรทัดและ
eval()
- รายงานการละเมิดนโยบายในเซิร์ฟเวอร์ก่อนที่จะบังคับใช้
รายการที่อนุญาตของแหล่งที่มา
การโจมตี XSS ใช้ประโยชน์จากการที่เบราว์เซอร์ไม่สามารถแยกความแตกต่างระหว่างสคริปต์ที่เป็นส่วนหนึ่งของแอปพลิเคชันของคุณกับสคริปต์ที่มีการแทรกโดยบุคคลที่สามอย่างมุ่งร้าย ตัวอย่างเช่น ปุ่ม Google +1 ที่ด้านล่างของหน้านี้จะโหลดและเรียกใช้โค้ดจาก https://apis.google.com/js/plusone.js
ในบริบทของที่มาของหน้านี้
เราเชื่อถือโค้ดดังกล่าว แต่ไม่คาดคิดว่าเบราว์เซอร์จะทราบด้วยตนเองว่าโค้ดจาก apis.google.com
นั้นปลอดภัยที่จะเรียกใช้ ในขณะที่โค้ดจาก apis.evil.example.com
อาจไม่ใช่โค้ดที่ถูกต้อง เบราว์เซอร์จะดาวน์โหลดและเรียกใช้โค้ดที่หน้าเว็บร้องขอได้อย่างมีความสุขโดยไม่คำนึงถึงแหล่งที่มา
ส่วนหัว HTTP Content-Security-Policy
ของ CSP ช่วยให้คุณสร้างรายการที่อนุญาตของแหล่งที่มาของเนื้อหาที่เชื่อถือได้ และบอกให้เบราว์เซอร์เรียกใช้หรือแสดงผลเฉพาะทรัพยากรจากแหล่งที่มาเหล่านั้น แม้ว่าผู้โจมตีจะพบช่องโหว่เพื่อแทรกสคริปต์ แต่สคริปต์จะไม่ตรงกับรายการที่อนุญาต ทำให้ไม่สามารถเรียกใช้สคริปต์ได้
เราเชื่อมั่นว่า apis.google.com
จะส่งโค้ดที่ถูกต้องและเชื่อมั่นในการดำเนินการนี้ ต่อไปนี้เป็นนโยบายตัวอย่างที่อนุญาตให้สคริปต์ทำงานได้เฉพาะเมื่อมาจากแหล่งที่มา 1 ใน 2 แหล่งดังกล่าวเท่านั้น
Content-Security-Policy: script-src 'self' https://apis.google.com
script-src
คือคำสั่งที่ควบคุมชุดสิทธิ์ที่เกี่ยวข้องกับสคริปต์สำหรับหน้าเว็บ ส่วนหัว 'self'
นี้เป็นแหล่งที่มาของสคริปต์ที่ถูกต้องประเภทหนึ่ง และ https://apis.google.com
เป็นอีกแหล่งที่มาหนึ่ง ตอนนี้เบราว์เซอร์จะดาวน์โหลดและเรียกใช้ JavaScript จาก apis.google.com
ผ่าน HTTPS ได้ รวมถึงจากต้นทางของหน้าเว็บปัจจุบัน แต่จะดาวน์โหลดจากต้นทางอื่นๆ ไม่ได้ หากผู้โจมตีแทรกโค้ดลงในเว็บไซต์ เบราว์เซอร์จะแสดงข้อผิดพลาดและไม่เรียกใช้สคริปต์ที่แทรกไว้
นโยบายมีผลกับทรัพยากรที่หลากหลาย
CSP มีชุดคำสั่งนโยบายที่ช่วยให้ควบคุมทรัพยากรที่หน้าเว็บโหลดได้อย่างละเอียด ซึ่งรวมถึง script-src
จากตัวอย่างก่อนหน้านี้
รายการต่อไปนี้สรุปคำสั่งทรัพยากรส่วนที่เหลือในระดับ 2 ข้อกำหนดระดับ 3 มีการร่างไว้แล้ว แต่ยังไม่มีการใช้งานส่วนใหญ่ในเบราว์เซอร์หลัก
base-uri
- จำกัด URL ที่ปรากฏในองค์ประกอบ
<base>
ของหน้าได้ child-src
- ระบุ URL สำหรับผู้ปฏิบัติงานและเนื้อหาเฟรมที่ฝัง ตัวอย่างเช่น
child-src https://youtube.com
จะเปิดใช้การฝังวิดีโอจาก YouTube แต่ไม่ได้เปิดใช้จากต้นทางอื่นๆ connect-src
- จำกัดต้นทางที่เชื่อมต่อได้โดยใช้ XHR, WebSockets และ EventSource
font-src
- ระบุต้นทางที่แสดงแบบอักษรสำหรับเว็บได้ ตัวอย่างเช่น คุณจะอนุญาตแบบอักษรเว็บของ Google โดยใช้
font-src https://themes.googleusercontent.com
ได้ form-action
- แสดงรายการปลายทางที่ถูกต้องสำหรับการส่งจาก
<form>
แท็ก frame-ancestors
- ระบุแหล่งที่มาที่ฝังหน้าปัจจุบันได้ คำสั่งนี้มีผลกับแท็ก
<frame>
,<iframe>
,<embed>
และ<applet>
โดยจะใช้ในแท็ก<meta>
หรือทรัพยากร HTML ไม่ได้ frame-src
- คำสั่งนี้เลิกใช้งานแล้วในระดับ 2 แต่ได้รับการกู้คืนในระดับ 3 หากไม่ปรากฏ เบราว์เซอร์จะกลับไปใช้
child-src
img-src
- กำหนดต้นทางที่โหลดรูปภาพได้
media-src
- จำกัดต้นทางที่ได้รับอนุญาตให้แสดงวิดีโอและเสียง
object-src
- ช่วยให้ควบคุม Flash และปลั๊กอินอื่นๆ ได้
plugin-types
- จำกัดประเภทปลั๊กอินที่หน้าเว็บสามารถเรียกใช้ได้
report-uri
- ระบุ URL ที่เบราว์เซอร์จะส่งรายงานเมื่อมีการละเมิดนโยบายความปลอดภัยของเนื้อหา ใช้คำสั่งนี้ใน
<meta>
แท็กไม่ได้ style-src
- จำกัดต้นทางที่หน้าเว็บใช้สไตล์ชีตได้
upgrade-insecure-requests
- สั่งให้ User Agent เขียนรูปแบบ URL ใหม่โดยการเปลี่ยน HTTP เป็น HTTPS คำสั่งนี้มีไว้สำหรับเว็บไซต์ที่มี URL เก่าจำนวนมากซึ่งจำเป็นต้องเขียนใหม่
worker-src
- คำสั่งของ CSP ระดับ 3 ที่จำกัด URL ที่โหลดในฐานะผู้ปฏิบัติงาน ผู้ปฏิบัติงานที่แชร์ หรือโปรแกรมทำงานของบริการได้ ตั้งแต่เดือนกรกฎาคม 2017 คำสั่งนี้มีการติดตั้งใช้งานที่จำกัด
โดยค่าเริ่มต้น เบราว์เซอร์จะโหลดทรัพยากรที่เกี่ยวข้องจากต้นทางทั้งหมดโดยไม่มีข้อจำกัด เว้นแต่คุณจะตั้งค่านโยบายด้วยคำสั่งเฉพาะ หากต้องการลบล้างค่าเริ่มต้น ให้ระบุคำสั่ง default-src
คำสั่งนี้จะกำหนดค่าเริ่มต้นสำหรับคำสั่งที่ไม่ได้ระบุที่ลงท้ายด้วย -src
เช่น หากตั้งค่า default-src
เป็น https://example.com
และไม่ได้ระบุคำสั่ง font-src
คุณจะโหลดแบบอักษรได้จาก https://example.com
เท่านั้น
คำสั่งต่อไปนี้ไม่ได้ใช้ default-src
เป็นรายการสำรอง โปรดทราบว่าการไม่ตั้งค่าก็เหมือนกับการอนุญาตให้ทำสิ่งต่างๆ ดังนี้
base-uri
form-action
frame-ancestors
plugin-types
report-uri
sandbox
ไวยากรณ์พื้นฐานของ CSP
หากต้องการใช้คำสั่ง CSP ให้ระบุคำสั่งในส่วนหัว HTTP พร้อมคำสั่งที่คั่นด้วยโคลอน อย่าลืมระบุทรัพยากรที่จำเป็นทั้งหมดของประเภทหนึ่งๆ ในคำสั่งเดียว ดังนี้
script-src https://host1.com https://host2.com
ต่อไปนี้คือตัวอย่างของคำสั่งหลายคำสั่ง ในกรณีนี้สำหรับเว็บแอปที่โหลดทรัพยากรทั้งหมดจากเครือข่ายนำส่งข้อมูลเนื้อหาที่ https://cdn.example.net
และไม่ได้ใช้เนื้อหาหรือปลั๊กอินที่เฟรม
Content-Security-Policy: default-src https://cdn.example.net; child-src 'none'; object-src 'none'
รายละเอียดการใช้งาน
เบราว์เซอร์ที่ทันสมัยรองรับส่วนหัว Content-Security-Policy
ที่ไม่มีคำนำหน้า
นี่เป็นส่วนหัวที่แนะนำ เราเลิกใช้งานส่วนหัว X-WebKit-CSP
และ X-Content-Security-Policy
ที่คุณอาจเห็นในบทแนะนำออนไลน์แล้ว
มีการกำหนด CSP แบบหน้าต่อหน้า คุณจะต้องส่งส่วนหัว HTTP ที่มีการตอบกลับทุกรายการที่ต้องการปกป้อง วิธีนี้จะช่วยให้คุณปรับแต่งนโยบายสำหรับ หน้าเว็บหนึ่งๆ ได้ตามความต้องการที่เฉพาะเจาะจง ตัวอย่างเช่น หากชุดหน้าเว็บหนึ่งในเว็บไซต์ของคุณมีปุ่ม +1 ในขณะที่หน้าอื่นๆ ไม่มี คุณสามารถอนุญาตให้โค้ดปุ่มโหลดได้เมื่อจำเป็นเท่านั้น
รายการแหล่งที่มาสำหรับแต่ละคำสั่งจะมีความยืดหยุ่น คุณสามารถระบุแหล่งที่มาตามรูปแบบ (data:
, https:
) หรือช่วงที่เจาะจงจากชื่อโฮสต์เท่านั้น (example.com
ซึ่งจับคู่ต้นทางใดๆ ในโฮสต์นั้น เช่น สคีม พอร์ตใดก็ได้) กับ URI ที่มีคุณสมบัติครบถ้วน (https://example.com:443
ซึ่งจับคู่เฉพาะ HTTPS เท่านั้น example.com
และเฉพาะพอร์ต 443) ระบบยอมรับไวลด์การ์ด แต่จะอยู่ในรูปแบบสคีม พอร์ต หรือในตำแหน่งด้านซ้ายสุดของชื่อโฮสต์เท่านั้น *://*.example.com:*
จะตรงกับโดเมนย่อยทั้งหมดของ example.com
(แต่ไม่ใช่ example.com
) โดยใช้รูปแบบใดก็ได้ในพอร์ตใดก็ได้
รายการแหล่งที่มายอมรับคีย์เวิร์ด 4 คำดังนี้
'none'
ไม่ตรงกับข้อมูลใดๆ'self'
ตรงกับต้นทางปัจจุบัน แต่ไม่ตรงกับโดเมนย่อย'unsafe-inline'
อนุญาตให้ใช้ JavaScript และ CSS แบบอินไลน์ ดูข้อมูลเพิ่มเติมได้ที่หลีกเลี่ยงการใช้โค้ดในหน้า'unsafe-eval'
อนุญาตให้ใช้กลไกที่แปลงข้อความเป็น JavaScript เช่นeval
ดูข้อมูลเพิ่มเติมได้ที่หลีกเลี่ยงeval()
คีย์เวิร์ดเหล่านี้ต้องใช้เครื่องหมายคำพูดเดี่ยว ตัวอย่างเช่น script-src 'self'
(ที่มีเครื่องหมายคำพูด) ให้สิทธิ์การดำเนินการของ JavaScript จากโฮสต์ปัจจุบัน script-src self
(ไม่มีเครื่องหมายคำพูด) อนุญาตให้ใช้ JavaScript จากเซิร์ฟเวอร์ชื่อ "self
" (และไม่ใช่จากโฮสต์ปัจจุบัน) ซึ่งอาจไม่ใช่สิ่งที่คุณหมายถึง
แซนด์บ็อกซ์หน้าเว็บของคุณ
มีคำสั่งอีก 1 รายการที่ควรพูดถึงคือ sandbox
แอปนี้จะแตกต่างจากเวอร์ชันอื่นๆ ที่เราพิจารณามาเล็กน้อย เนื่องจากมีข้อจำกัดเกี่ยวกับการดำเนินการที่หน้าเว็บสามารถทำได้แทนที่จะใช้ทรัพยากรที่หน้าเว็บสามารถโหลดได้ หากมีคำสั่ง sandbox
อยู่ ระบบจะปฏิบัติต่อหน้าเว็บเหมือนว่าโหลดภายใน <iframe>
ที่มีแอตทริบิวต์ sandbox
การทำเช่นนี้จะมีผลหลากหลายต่อหน้าเว็บ เช่น การบังคับให้หน้าเว็บทำงานในต้นทางที่ไม่ซ้ำกัน การป้องกันไม่ให้ส่งแบบฟอร์ม และอื่นๆ ซึ่งอาจอยู่นอกเหนือขอบเขตของหน้านี้เล็กน้อย แต่คุณดูรายละเอียดทั้งหมดเกี่ยวกับแอตทริบิวต์แซนด์บ็อกซ์ที่ถูกต้องได้ในส่วน "แซนด์บ็อกซ์" ของข้อกำหนด HTML5
เมตาแท็ก
กลไกการนำส่งที่ต้องการของ CSP คือส่วนหัว HTTP อย่างไรก็ตาม การกำหนดนโยบายในหน้าเว็บในมาร์กอัปโดยตรงก็อาจเป็นประโยชน์ โดยใช้แท็ก <meta>
ที่มี
แอตทริบิวต์ http-equiv
ดังนี้
<meta http-equiv="Content-Security-Policy" content="default-src https://cdn.example.net; child-src 'none'; object-src 'none'">
ใช้กับ frame-ancestors
, report-uri
หรือ sandbox
ไม่ได้
หลีกเลี่ยงโค้ดในบรรทัด
รายการที่อนุญาตมีประสิทธิภาพเท่ากับรายการที่อนุญาตจากต้นทางที่ใช้ในคำสั่ง CSP แต่จะแก้ไขภัยคุกคามที่ใหญ่ที่สุดที่เกิดจากการโจมตี XSS ไม่ได้ ซึ่งก็คือการแทรกสคริปต์ในบรรทัด
หากผู้โจมตีสามารถแทรกแท็กสคริปต์ที่มีเพย์โหลดที่เป็นอันตรายโดยตรง (เช่น <script>sendMyDataToEvilDotCom()</script>
) เบราว์เซอร์จะไม่มีวิธีแยกความแตกต่างระหว่างแท็กดังกล่าวกับแท็กสคริปต์ในหน้าที่ถูกต้อง CSP แก้ปัญหานี้โดยการแบนสคริปต์ในหน้าโดยสิ้นเชิง
การแบนนี้ไม่ได้มีเพียงสคริปต์ที่ฝังในแท็ก script
โดยตรง แต่ยังรวมถึงเครื่องจัดการเหตุการณ์แบบอินไลน์และ URL javascript:
ด้วย คุณจะต้องย้ายเนื้อหาของแท็ก script
ไปยังไฟล์ภายนอก แล้วแทนที่ URL จำนวน javascript:
รายการและ <a ...
onclick="[JAVASCRIPT]">
ด้วยการเรียก addEventListener()
ที่เหมาะสม ตัวอย่างเช่น คุณอาจเขียนค่าต่อไปนี้ใหม่จาก
<script>
function doAmazingThings() {
alert('YOU ARE AMAZING!');
}
</script>
<button onclick='doAmazingThings();'>Am I amazing?</button>
เป็นอย่างอื่น เช่น
<!-- amazing.html -->
<script src='amazing.js'></script>
<button id='amazing'>Am I amazing?</button>
// amazing.js
function doAmazingThings() {
alert('YOU ARE AMAZING!');
}
document.addEventListener('DOMContentLoaded', function () {
document.getElementById('amazing')
.addEventListener('click', doAmazingThings);
});
โค้ดที่เขียนขึ้นใหม่นี้ไม่เพียงแต่เข้ากันได้กับ CSP เท่านั้น แต่ยังสอดคล้องกับแนวทางปฏิบัติแนะนำในการออกแบบเว็บอีกด้วย JavaScript แบบอินไลน์จะผสมผสานโครงสร้างและลักษณะการทำงาน ในรูปแบบที่ทำให้โค้ดสับสน การแคชและคอมไพล์มีความซับซ้อนมากกว่า การย้ายโค้ดไปยังทรัพยากรภายนอกทำให้หน้าเว็บทำงานได้ดีขึ้น
เราขอแนะนำอย่างยิ่งให้ย้ายแท็ก style
ในหน้าและแอตทริบิวต์ไปยังสไตล์ชีตภายนอกเพื่อปกป้องเว็บไซต์ของคุณจากการโจมตีการขโมยข้อมูลที่ใช้ CSS
วิธีอนุญาตสคริปต์และสไตล์ในบรรทัดชั่วคราว
คุณเปิดใช้สคริปต์และสไตล์ในบรรทัดได้โดยการเพิ่ม 'unsafe-inline'
เป็นแหล่งที่มาที่ได้รับอนุญาตในคำสั่ง script-src
หรือ style-src
CSP ระดับที่ 2 ยังให้คุณเพิ่มสคริปต์ในหน้าที่ต้องการไปยังรายการที่อนุญาตโดยใช้ค่าที่ได้จากการเข้ารหัส (ใช้ครั้งเดียว) หรือแฮชดังต่อไปนี้
หากต้องการใช้ Nonce ให้กำหนดแท็กสคริปต์เป็นแอตทริบิวต์ nonce ค่าต้องตรงกับหนึ่งใน รายการแหล่งที่มาที่เชื่อถือได้ เช่น
<script nonce="EDNnf03nceIOfn39fn3e9h3sdfa">
// Some inline code I can't remove yet, but need to as soon as possible.
</script>
เพิ่ม Nonce ลงในคำสั่ง script-src
ตามหลังคีย์เวิร์ด nonce-
Content-Security-Policy: script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa'
ต้องสร้าง Nonce ใหม่สำหรับทุกคำขอของหน้า และต้องเข้าใจได้
แฮชทำงานในลักษณะเดียวกัน สร้างแฮช SHA ของสคริปต์แล้วเพิ่มลงในคำสั่ง script-src
แทนการเพิ่มโค้ดลงในแท็กสคริปต์
ตัวอย่างเช่น หากหน้าเว็บของคุณมีสิ่งต่อไปนี้
<script>alert('Hello, world.');</script>
นโยบายของคุณต้องมีข้อมูลต่อไปนี้
Content-Security-Policy: script-src 'sha256-qznLcsROx4GACP2dm0UCKCzCG-HiZ1guq6ZZDob_Tng='
คำนำหน้า sha*-
จะระบุอัลกอริทึมที่สร้างแฮช ตัวอย่างก่อนหน้านี้ใช้ sha256-
แต่ CSP ยังรองรับ sha384-
และ sha512-
ด้วย เมื่อสร้างแฮช ให้ละเว้นแท็ก <script>
การใช้อักษรตัวพิมพ์ใหญ่และช่องว่าง
รวมถึงช่องว่างขึ้นต้นและต่อท้าย
โซลูชันสำหรับการสร้างแฮช SHA มีให้บริการในภาษาต่างๆ เมื่อใช้ Chrome 40 ขึ้นไป คุณจะเปิดเครื่องมือสำหรับนักพัฒนาเว็บแล้วโหลดหน้าเว็บซ้ำได้ แท็บคอนโซลจะแสดงข้อความแสดงข้อผิดพลาดพร้อมแฮช SHA-256 ที่ถูกต้องสำหรับสคริปต์ในบรรทัดแต่ละรายการ
หลีกเลี่ยงeval()
แม้ผู้โจมตีจะแทรกสคริปต์โดยตรงไม่ได้ แต่ก็อาจหลอกให้แอปพลิเคชันแปลงข้อความอินพุตเป็น JavaScript ปฏิบัติการได้ และจะดำเนินการแทนพวกเขาได้ eval()
, new Function()
,
setTimeout([string], …)
และ setInterval([string], ...)
เป็นเวกเตอร์ที่ผู้โจมตีอาจใช้เพื่อเรียกใช้โค้ดที่เป็นอันตรายผ่านข้อความที่แทรก การตอบสนองเริ่มต้นของ CSP ต่อความเสี่ยงนี้คือการบล็อกเวกเตอร์เหล่านี้ทั้งหมดโดยสมบูรณ์
การดำเนินการดังกล่าวมีผลกระทบดังต่อไปนี้ต่อวิธีสร้างแอปพลิเคชัน
- คุณต้องแยกวิเคราะห์ JSON โดยใช้
JSON.parse
ในตัวแทนการใช้eval
การดำเนินการ JSON ที่ปลอดภัยพร้อมใช้งานในทุกเบราว์เซอร์ตั้งแต่ IE8 คุณต้องเขียนการเรียก
setTimeout
หรือsetInterval
ใหม่ที่คุณใช้ฟังก์ชันอินไลน์แทนสตริง เช่น หากหน้าเว็บมีสิ่งต่อไปนี้setTimeout("document.querySelector('a').style.display = 'none';", 10);
เขียนใหม่เป็น:
setTimeout(function () { document.querySelector('a').style.display = 'none'; }, 10); ```
หลีกเลี่ยงการใช้เทมเพลตแบบอินไลน์ระหว่างรันไทม์ ไลบรารีที่มีเทมเพลตจำนวนมากมักจะใช้
new Function()
เพื่อเร่งการสร้างเทมเพลตให้เร็วขึ้นขณะรันไทม์ ซึ่งทำให้ประเมินข้อความที่เป็นอันตรายได้ บางเฟรมเวิร์กรองรับ CSP ตั้งแต่เริ่มใช้งาน และกลับไปใช้โปรแกรมแยกวิเคราะห์ที่มีประสิทธิภาพในกรณีที่ไม่มีeval
ตัวอย่างที่ดีคือคำสั่ง ng-csp ของ AngularJS อย่างไรก็ตาม เราขอแนะนำให้ใช้ภาษาที่มีเทมเพลตไว้ให้แล้ว เช่น แฮนเดิล การคอมไพล์เทมเพลตล่วงหน้าอาจทำให้ผู้ใช้ได้รับประสบการณ์เร็วกว่าการใช้รันไทม์ที่รวดเร็วที่สุด และยังช่วยให้เว็บไซต์ปลอดภัยยิ่งขึ้นอีกด้วย
หากแอปพลิเคชันของคุณจำเป็นต้องใช้ eval()
หรือฟังก์ชันการแปลงข้อความเป็น JavaScript ก็เปิดใช้ได้โดยเพิ่ม 'unsafe-eval'
เป็นแหล่งที่มาที่อนุญาตในคำสั่ง script-src
เราไม่แนะนำอย่างยิ่งเนื่องจากมีความเสี่ยง
ที่เกิดจากการแทรกโค้ด
รายงานการละเมิดนโยบาย
หากต้องการแจ้งเซิร์ฟเวอร์เกี่ยวกับข้อบกพร่องที่อาจอนุญาตให้มีการแทรกที่เป็นอันตราย โปรดแจ้งเบราว์เซอร์ให้POST
รายงานการละเมิดในรูปแบบ JSON ไปยังตำแหน่งที่ระบุในคำสั่ง report-uri
ดังนี้
Content-Security-Policy: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;
รายงานเหล่านี้จะมีลักษณะดังนี้
{
"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"
}
}
รายงานนี้มีข้อมูลที่เป็นประโยชน์ในการหาสาเหตุของการละเมิดนโยบาย ซึ่งรวมถึงหน้าเว็บที่เกิดขึ้น (document-uri
), referrer
ของหน้านั้น, ทรัพยากรที่ละเมิดนโยบายของหน้า (blocked-uri
), คำสั่งเฉพาะเจาะจงที่หน้าเว็บละเมิด (violated-directive
) และนโยบายทั้งหมดของหน้านั้น (original-policy
)
รายงานเท่านั้น
หากคุณเพิ่งเริ่มต้นใช้ CSP เราขอแนะนำให้ใช้โหมดรายงานเท่านั้นเพื่อประเมินสถานะของแอปก่อนที่จะเปลี่ยนนโยบาย หากต้องการทำแบบนี้ ให้ส่งส่วนหัว Content-Security-Policy-Report-Only
แทนการส่งส่วนหัว Content-Security-Policy
Content-Security-Policy-Report-Only: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;
นโยบายที่ระบุในโหมดรายงานเท่านั้นจะไม่บล็อกทรัพยากรที่ถูกจำกัด แต่จะส่งรายงานการละเมิดไปยังตำแหน่งที่คุณระบุ หรือคุณจะส่งส่วนหัวทั้ง 2 แบบเพื่อบังคับใช้นโยบายหนึ่งไปพร้อมๆ กับตรวจสอบอีกนโยบายก็ได้ นี่เป็นวิธีที่ยอดเยี่ยมในการทดสอบการเปลี่ยนแปลงของ CSP ไปพร้อมๆ กับบังคับใช้นโยบายปัจจุบัน เช่น เปิดใช้การรายงานสำหรับนโยบายใหม่ ตรวจสอบรายงานการละเมิดและแก้ไขข้อบกพร่อง แล้วเริ่มบังคับใช้นโยบายนั้นเมื่อพึงพอใจกับนโยบายใหม่แล้ว
การใช้งานจริง
ขั้นตอนแรกในการกำหนดนโยบายสำหรับแอปคือการประเมินทรัพยากรที่โหลด เมื่อเข้าใจโครงสร้างของแอปแล้ว ให้สร้างนโยบายตามข้อกำหนดของแอป ส่วนต่อไปนี้จะอธิบายกรณีการใช้งานทั่วไปและกระบวนการตัดสินใจสำหรับการรองรับการใช้งานดังกล่าวตามหลักเกณฑ์ของ CSP
วิดเจ็ตโซเชียลมีเดีย
- ปุ่มชอบของ Facebook
มีตัวเลือกการใช้งานมากมาย เราขอแนะนำให้ใช้เวอร์ชัน
<iframe>
เพื่อคงแซนด์บ็อกซ์ไว้จากส่วนอื่นๆ ในเว็บไซต์ จำเป็นต้องมีคำสั่งchild-src https://facebook.com
เพื่อให้ทำงานได้อย่างถูกต้อง - ปุ่มทวีตของ X ต้องใช้การเข้าถึงสคริปต์
ย้ายสคริปต์ที่สคริปต์ให้ไว้ไปยังไฟล์ JavaScript ภายนอก แล้วใช้คำสั่ง
script-src https://platform.twitter.com; child-src https://platform.twitter.com
- แพลตฟอร์มอื่นๆ มีข้อกำหนดที่คล้ายกันและสามารถแก้ไขได้ในลักษณะเดียวกัน
หากต้องการทดสอบทรัพยากรเหล่านี้ เราขอแนะนำให้ตั้งค่า
default-src
เป็น'none'
และดูคอนโซลของคุณเพื่อดูว่าจะต้องเปิดใช้ทรัพยากรใด
หากต้องการใช้วิดเจ็ตหลายรายการ ให้รวมคำสั่งดังนี้
script-src https://apis.google.com https://platform.twitter.com; child-src https://plusone.google.com https://facebook.com https://platform.twitter.com
การล็อกดาวน์
สำหรับบางเว็บไซต์ คุณควรตรวจสอบว่าสามารถโหลดได้เฉพาะทรัพยากรในเครื่องเท่านั้น ตัวอย่างต่อไปนี้พัฒนา CSP สำหรับเว็บไซต์ธนาคาร โดยเริ่มต้นด้วยนโยบายเริ่มต้นที่บล็อกทุกอย่าง (default-src 'none'
)
เว็บไซต์จะโหลดรูปภาพ รูปแบบ และสคริปต์ทั้งหมดจาก CDN ในเวลา https://cdn.mybank.net
และเชื่อมต่อกับ https://api.mybank.com/
โดยใช้ XHR เพื่อดึงข้อมูล ใช้เฟรม แต่ใช้สำหรับหน้าเว็บในเครื่องของเว็บไซต์เท่านั้น (ไม่มีต้นทางของบุคคลที่สาม) ไซต์ไม่มี Flash, ไม่มีแบบอักษร, ไม่มีส่วนเพิ่มเติม ส่วนหัว CSP ที่เข้มงวดที่สุดที่ส่งได้มีดังนี้
Content-Security-Policy: default-src 'none'; script-src https://cdn.mybank.net; style-src https://cdn.mybank.net; img-src https://cdn.mybank.net; connect-src https://api.mybank.com; child-src 'self'
SSL เท่านั้น
ต่อไปนี้คือตัวอย่าง CSP สำหรับผู้ดูแลระบบฟอรัมที่ต้องการตรวจสอบว่าทรัพยากรทั้งหมดในฟอรัมจะโหลดโดยใช้ช่องทางที่ปลอดภัยเท่านั้น แต่ไม่มีประสบการณ์ในการเขียนโค้ดและไม่มีทรัพยากรในการเขียนซอฟต์แวร์ฟอรัมของบุคคลที่สามใหม่ซึ่งเต็มไปด้วยสคริปต์และรูปแบบในหน้า
Content-Security-Policy: default-src https:; script-src https: 'unsafe-inline'; style-src https: 'unsafe-inline'
แม้ว่าจะระบุ https:
ใน default-src
แต่คำสั่งของสคริปต์และสไตล์จะไม่รับค่าแหล่งที่มานั้นโดยอัตโนมัติ คำสั่งแต่ละรายการจะแทนที่ค่าเริ่มต้นของทรัพยากรประเภทนั้นๆ
การพัฒนามาตรฐาน CSP
นโยบายรักษาความปลอดภัยเนื้อหาระดับ 2 เป็นมาตรฐานที่แนะนำของ W3C คณะทำงานด้านความปลอดภัยของเว็บแอปพลิเคชันของ W3C กำลังพัฒนาข้อกำหนดฉบับถัดไป ซึ่งก็คือนโยบายรักษาความปลอดภัยเนื้อหาระดับ 3
หากต้องการติดตามการสนทนาเกี่ยวกับฟีเจอร์ที่กำลังจะมีขึ้นเหล่านี้ โปรดดูที่เก็บถาวรของรายชื่ออีเมลสาธารณะ@