นโยบายรักษาความปลอดภัยเนื้อหา

นโยบายรักษาความปลอดภัยเนื้อหาสามารถลดความเสี่ยงและผลกระทบจากการโจมตีแบบ Cross-site Scripting ในเบราว์เซอร์สมัยใหม่ได้อย่างมาก

การรองรับเบราว์เซอร์

  • Chrome: 25.
  • Edge: 14.
  • Firefox: 23.
  • Safari: 7.

แหล่งที่มา

โมเดลความปลอดภัยของเว็บอิงตามนโยบายต้นทางเดียวกัน ตัวอย่างเช่น รหัสจาก 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 รวมถึงจากต้นทางของหน้าปัจจุบัน แต่จะเรียกใช้จากต้นทางอื่นไม่ได้ หากผู้โจมตีแทรกโค้ดลงในเว็บไซต์ เบราว์เซอร์จะแสดงข้อผิดพลาดและไม่เรียกใช้สคริปต์ที่แทรก

ข้อผิดพลาดในคอนโซล: ปฏิเสธที่จะโหลดสคริปต์ "http://evil.example.com/evil.js" เนื่องจากละเมิดคําสั่งนโยบายรักษาความปลอดภัยเนื้อหาต่อไปนี้ script-src 'self' https://apis.google.com
คอนโซลแสดงข้อผิดพลาดเมื่อสคริปต์พยายามเรียกใช้จากต้นทางที่ไม่ได้อยู่ในรายการที่อนุญาต

นโยบายมีผลกับแหล่งข้อมูลที่หลากหลาย

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 ที่โหลดเป็น 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 ให้กับแท็กสคริปต์ ค่าของ URL ต้องตรงกับ แหล่งที่มาในรายการแหล่งที่มาที่เชื่อถือได้ เช่น

<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 การดำเนินการ Safe 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 ให้ส่งส่วนหัว 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

หากต้องการติดตามการพูดคุยเกี่ยวกับฟีเจอร์ต่างๆ ที่กำลังจะมีขึ้นนี้ โปรดดูที่เก็บถาวรของรายชื่ออีเมลแบบสาธารณะ-webappsec@