นโยบายรักษาความปลอดภัยเนื้อหาช่วยลดความเสี่ยงและผลกระทบจากการโจมตีด้วยสคริปต์ข้ามเว็บไซต์ในเบราว์เซอร์สมัยใหม่ได้อย่างมาก
รูปแบบการรักษาความปลอดภัยของเว็บจะอิงตามนโยบายต้นทางเดียวกัน ตัวอย่างเช่น รหัสจาก https://mybank.com
ต้องมีสิทธิ์เข้าถึงเฉพาะข้อมูลของ https://mybank.com
และ https://evil.example.com
ต้องไม่ได้รับอนุญาตให้เข้าถึง
ตามหลักการแล้ว ต้นทางแต่ละแห่งจะแยกออกจากส่วนอื่นๆ ของเว็บ ซึ่งช่วยให้นักพัฒนาซอฟต์แวร์มีแซนด์บ็อกซ์ที่ปลอดภัยในการสร้าง อย่างไรก็ตาม ในทางปฏิบัติ ผู้โจมตีค้นพบวิธีต่างๆ ในการทำลายระบบ
การโจมตีด้วย Cross-site Scripting (XSS) เช่น การข้ามนโยบายต้นทางเดียวกันโดยการหลอกลวงเว็บไซต์ให้แสดงโค้ดที่เป็นอันตรายพร้อมกับเนื้อหาที่ต้องการ ปัญหานี้ถือเป็นปัญหาใหญ่ เนื่องจากเบราว์เซอร์จะเชื่อถือโค้ดทั้งหมดที่แสดงในหน้าเว็บว่าเป็นส่วนหนึ่งของแหล่งที่มาของความปลอดภัยของหน้าเว็บนั้นอย่างถูกต้อง ชีตเคล็ดลับ 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
จะส่งโค้ดที่ถูกต้อง และเราก็เชื่อมั่นว่าตัวเองจะทำเช่นนั้นเช่นกัน ต่อไปนี้คือตัวอย่างนโยบายที่อนุญาตให้สคริปต์ทำงานได้ก็ต่อเมื่อมาจากแหล่งที่มาแหล่งใดแหล่งหนึ่งต่อไปนี้
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, WebSocket และ 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 ที่โหลดเป็น Worker, Shared Worker หรือ Service Worker ได้ ในเดือนกรกฎาคม 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
" (และไม่ใช่จากโฮสต์ปัจจุบัน) ซึ่งอาจไม่ใช่สิ่งที่คุณตั้งใจ
ทดสอบหน้าเว็บในแท็บทดสอบ
คำสั่งอีกรายการหนึ่งที่ควรพูดถึงคือ 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 ให้ระบุแอตทริบิวต์ 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 ใหม่สำหรับคำขอหน้าเว็บแต่ละรายการ และ 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 เป็นตัวอย่างที่ดีในเรื่องนี้ อย่างไรก็ตาม เราขอแนะนำให้ใช้ภาษาเทมเพลตที่มีการคอมไพล์ล่วงหน้า เช่น Handlebars การคอมไพล์เทมเพลตล่วงหน้าจะช่วยให้ผู้ใช้ได้รับประสบการณ์การใช้งานที่เร็วกว่าการใช้งานรันไทม์ที่เร็วที่สุด และยังทําให้เว็บไซต์ปลอดภัยยิ่งขึ้นด้วย
หาก 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
ให้ส่งส่วนหัว Content-Security-Policy-Report-Only
ดังนี้
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
หากต้องการติดตามการพูดคุยเกี่ยวกับฟีเจอร์ที่กําลังจะเปิดตัวเหล่านี้ โปรดดูที่ที่เก็บอีเมลของรายชื่ออีเมล public-webappsec@