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

โมเดลความปลอดภัยของเว็บมีการนำมาใช้ใน นโยบายต้นทางเดียวกัน โค้ด จาก https://mybank.com ควรมีสิทธิ์เข้าถึงเฉพาะข้อมูลของ https://mybank.com และ https://evil.example.com ก็ไม่ควรได้รับอนุญาตเป็นอันขาด ต้นทางแต่ละรายการจะแยกออกจากส่วนอื่นๆ ในเว็บ ทำให้นักพัฒนาแอปปลอดภัย สำหรับสร้างและเล่น ในทางทฤษฎี สิ่งนี้สุดยอดจริงๆ ใน ผู้โจมตีพบวิธีการที่ชาญฉลาดในการโค่นล้มระบบ

Cross-site Scripting (XSS) ให้ข้ามนโยบายต้นทางเดียวกันโดยการหลอกให้เว็บไซต์ การส่งโค้ดที่เป็นอันตรายพร้อมกับเนื้อหาที่ต้องการ ข้อมูลนี้ยิ่งใหญ่ เนื่องจากเบราว์เซอร์เชื่อถือโค้ดทั้งหมดที่ปรากฏในหน้าเว็บ ของต้นทางการรักษาความปลอดภัยของหน้านั้นโดยชอบธรรม ข้อมูลสรุปของ XSS เป็นวิธีการเก่าแต่เป็นตัวแทนของวิธีการที่ผู้โจมตีอาจใช้ เพื่อละเมิดความไว้วางใจนี้โดยการแทรกโค้ดที่เป็นอันตราย หากผู้โจมตีดำเนินการสำเร็จ จะแทรกโค้ดใดๆ ลงไปเลย ทุกอย่างก็ถือว่าจบแล้ว ข้อมูลเซสชันของผู้ใช้ ถูกบุกรุกและข้อมูลที่ควรเก็บไว้เป็นความลับถูกปล้นไปใน The Bad สวัสดีทุกคน ซึ่งแน่นอนว่าเราต้องป้องกันหากทำได้

ภาพรวมนี้จะไฮไลต์การป้องกันที่สามารถลดความเสี่ยงได้อย่างมากและ ผลกระทบจากการโจมตี XSS ในเบราว์เซอร์รุ่นใหม่: นโยบายรักษาความปลอดภัยเนื้อหา (CSP)

TL;DR

  • ใช้รายการที่อนุญาตเพื่อบอกลูกค้าว่าสินค้าใดได้รับอนุญาตให้ขาย และสินค้าใดที่ไม่ได้รับอนุญาต
  • ดูคำสั่งที่ใช้ได้
  • เรียนรู้เกี่ยวกับคีย์เวิร์ดที่พวกเขาใช้
  • โค้ดในบรรทัดและ eval() ถือว่าเป็นอันตราย
  • รายงานการละเมิดนโยบายให้เซิร์ฟเวอร์ทราบก่อนที่จะบังคับใช้

รายการที่อนุญาตสำหรับแหล่งที่มา

ปัญหาที่ถูกโจมตีจากการโจมตี XSS คือเบราว์เซอร์ไม่สามารถแยกแยะความแตกต่าง ระหว่างสคริปต์ที่เป็นส่วนหนึ่งของแอปพลิเคชัน และสคริปต์ที่ ถูกแทรกด้วยอันตรายจากบุคคลที่สาม ตัวอย่างเช่น ปุ่ม Google +1 ที่ ด้านล่างของหน้านี้จะโหลดและเรียกใช้โค้ดจาก https://apis.google.com/js/plusone.js ในบริบทของต้นทางของหน้านี้ พ เชื่อถือรหัสนั้นได้ แต่เราไม่สามารถคาดหวังได้ว่าเบราว์เซอร์ จะตรวจพบโค้ดดังกล่าวด้วยตัวเอง จาก apis.google.com นั้นยอดเยี่ยม ส่วนโค้ดจาก apis.evil.example.com อาจจะไม่เป็นเช่นนั้น เบราว์เซอร์สามารถดาวน์โหลดและเรียกใช้โค้ดบนหน้าเว็บได้อย่างมีความสุข คำขอโดยไม่คำนึงถึงแหล่งที่มา

CSP จะกำหนดสิ่งต่อไปนี้ แทนการเชื่อถือทุกอย่างที่เซิร์ฟเวอร์มอบให้ ส่วนหัว HTTP ของ Content-Security-Policy ซึ่งจะช่วยให้คุณสร้างรายการที่อนุญาตของ แหล่งที่มาของเนื้อหาที่เชื่อถือได้ และสั่งให้เบราว์เซอร์เรียกใช้หรือแสดงผลเท่านั้น จากแหล่งที่มาเหล่านั้น แม้ว่าผู้โจมตีจะเจอช่องโหว่ที่ เพื่อแทรกสคริปต์ สคริปต์จะไม่ตรงกับรายการที่อนุญาต และไม่เช่นนั้น ดำเนินการแล้ว

เนื่องจากเราไว้วางใจให้ apis.google.com นำส่งโค้ดที่ถูกต้องและเราเชื่อมั่นในตัวเรา ให้กำหนดค่านโยบายที่อนุญาตให้สคริปต์ทำงานเฉพาะเมื่อสคริปต์ทำงาน มาจากแหล่งข้อมูล 1 ใน 2 แหล่งที่มาต่อไปนี้

Content-Security-Policy: script-src 'self' https://apis.google.com

ง่ายใช่ไหม คุณคงเดาได้ว่า script-src เป็นคำสั่งที่ ควบคุมชุดของสิทธิ์ที่เกี่ยวข้องกับสคริปต์สำหรับหน้าเว็บหนึ่งๆ เราได้ระบุ 'self' เป็นแหล่งที่มาที่ถูกต้อง 1 แห่งของสคริปต์ และ 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 เป็นคู่ของ script-src สำหรับสไตล์ชีต
  • upgrade-insecure-requests จะสั่งให้ User Agent เขียนรูปแบบ URL ใหม่ การเปลี่ยน HTTP เป็น HTTPS คำสั่งนี้มีไว้สำหรับเว็บไซต์ที่มีแท็ก URL เดิมที่ต้องเขียนใหม่
  • worker-src เป็นคำสั่ง CSP ระดับ 3 ที่จำกัด URL ที่อาจ โหลดในฐานะผู้ปฏิบัติงาน ผู้ปฏิบัติงานที่แชร์ หรือผู้ปฏิบัติงานบริการ ในเดือนกรกฎาคม 2017 นี้ มีคำสั่ง การติดตั้งใช้งานแบบจำกัด

คำสั่งจะเปิดอยู่โดยค่าเริ่มต้น หากคุณไม่ได้กำหนดนโยบายเฉพาะสำหรับ สมมติว่าเป็น font-src คำสั่งนั้นจะทำงานโดยค่าเริ่มต้นเป็น แม้ว่าคุณจะระบุ * เป็นแหล่งที่มาที่ถูกต้อง (เช่น คุณสามารถโหลดแบบอักษรจาก ทุกที่ โดยไม่มีข้อจำกัด)

คุณลบล้างลักษณะการทำงานเริ่มต้นนี้ได้โดยระบุ default-src คำสั่ง คำสั่งนี้กำหนดค่าเริ่มต้นสำหรับ ที่คุณไม่ได้ระบุไว้ โดยทั่วไป การตั้งค่านี้จะมีผลกับคำสั่งที่ ลงท้ายด้วย -src หากตั้งค่า default-src เป็น https://example.com และทำไม่สำเร็จ เพื่อระบุคำสั่ง font-src คุณจะสามารถโหลดแบบอักษรจาก https://example.com และไม่มีที่อื่น เราระบุเพียง script-src ใน ตัวอย่างก่อนหน้านี้ ซึ่งหมายความว่าคุณสามารถโหลดรูปภาพ แบบอักษร และอื่นๆ ได้จาก ต้นกำเนิดใดก็ได้

คำสั่งต่อไปนี้ไม่ได้ใช้ default-src เป็นคำสั่งสำรอง อย่าลืมว่า การไม่ตั้งค่าก็เท่ากับการอนุญาตให้ทำอะไรสักอย่าง

  • base-uri
  • form-action
  • frame-ancestors
  • plugin-types
  • report-uri
  • sandbox

คุณจะใช้คำสั่งเหล่านี้กี่รายการก็ได้ตามความเหมาะสม แอปพลิเคชันเฉพาะ เพียงแสดงแต่ละรายการในส่วนหัวของ HTTP แยกต่างหาก ด้วยเครื่องหมายเซมิโคลอน โปรดระบุรายการทั้งหมด ทรัพยากรที่จำเป็นบางประเภทในคำสั่งเดียว ถ้าคุณเขียนว่า อย่างเช่น script-src https://host1.com; script-src https://host2.com คำสั่งที่สองจะถูกละเว้น ต่อไปนี้คือสิ่งที่ ระบุต้นทางทั้งสองให้ถูกต้อง ดังนี้

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'

รายละเอียดการใช้งาน

คุณจะเห็นส่วนหัว X-WebKit-CSP และ X-Content-Security-Policy ใน บทแนะนำบนเว็บ นับจากนี้เป็นต้นไป โปรดอย่าสนใจคํานําหน้าเหล่านี้ ส่วนหัว เบราว์เซอร์ที่ทันสมัย (ยกเว้น IE) จะสนับสนุนการทำงานที่ไม่มีคำนำหน้า ส่วนหัว Content-Security-Policy ซึ่งเป็นส่วนหัวที่คุณควรใช้

ไม่ว่าคุณจะใช้ส่วนหัวใด จะมีการกำหนดนโยบายแบบหน้าต่อหน้าดังนี้ คุณจะต้องส่งส่วนหัว HTTP ไปพร้อมกับทุกคำตอบที่คุณต้องการ ให้แน่ใจว่าได้รับการปกป้อง มีความยืดหยุ่นอย่างมากเนื่องจากคุณสามารถปรับแต่ง นโยบายสำหรับหน้าเว็บที่เฉพาะเจาะจงตามความต้องการที่เฉพาะเจาะจง อาจมี 1 ชุด หน้าเว็บในไซต์ของคุณมีปุ่ม +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 (เราจะสร้าง ได้ด้วย)

คีย์เวิร์ดเหล่านี้ต้องใช้เครื่องหมายคำพูดเดี่ยว เช่น 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 ใส่แท็กลงในไฟล์ภายนอก และแทนที่ javascript: URL และ <a ... onclick="[JAVASCRIPT]"> ด้วยการเรียก addEventListener() ที่เหมาะสม ตัวอย่างเช่น คุณอาจเขียนสคริปต์ต่อไปนี้ใหม่จาก

<script>
  function doAmazingThings() {
    alert('YOU AM AMAZING!');
  }
</script>
<button onclick="doAmazingThings();">Am I amazing?</button>

ไปเป็นแบบอื่นๆ เช่น

<!-- amazing.html -->
<script src="amazing.js"></script>
<button id="amazing">Am I amazing?</button>

<div style="clear:both;"></div>
// amazing.js
function doAmazingThings() {
  alert('YOU AM AMAZING!');
}
document.addEventListener('DOMContentLoaded', function () {
  document.getElementById('amazing').addEventListener('click', doAmazingThings);
});

โค้ดที่เขียนใหม่มีข้อดีเหนือกว่าและอีกมากมาย CSP; ซึ่งเป็นแนวทางปฏิบัติแนะนำอยู่แล้ว ไม่ว่าคุณจะใช้ CSP หรือไม่ก็ตาม แบบอินไลน์ JavaScript ผสมผสานโครงสร้างและลักษณะการทำงานในแบบที่คุณไม่ควรทำ เบราว์เซอร์สามารถแคชแหล่งข้อมูลภายนอกได้ง่ายขึ้น และเข้าใจได้ง่ายขึ้นสำหรับ และเอื้อต่อการรวบรวมและลดขนาด คุณจะเขียนได้ดีขึ้น ถ้าคุณทำงานเพื่อย้ายโค้ดไปยังทรัพยากรภายนอก

รูปแบบแทรกในบรรทัดจะได้รับการจัดการในลักษณะเดียวกันทั้งแอตทริบิวต์ style และ style ควรรวมแท็กไว้ในสไตล์ชีตภายนอกเพื่อป้องกัน ที่ฉลาดจนคาดไม่ถึง วิธีการขโมยข้อมูลที่ CSS เปิดใช้

หากคุณต้องมีสคริปต์และรูปแบบในหน้า คุณสามารถเปิดใช้สคริปต์ได้ โดยเพิ่ม 'unsafe-inline' เป็นแหล่งที่มาที่อนุญาตใน script-src หรือ style-src คำสั่ง คุณสามารถใช้ Nonce หรือแฮชก็ได้ (ดูด้านล่าง) แต่จริงๆ แล้วไม่ควรทำ การแบนสคริปต์ในบรรทัดเป็นการรักษาความปลอดภัยของ CSP ได้มากที่สุด และ การแบนรูปแบบในบรรทัดก็จะทำให้แอปพลิเคชันของคุณแข็งแกร่งขึ้นเช่นกัน คล้ายกัน ล่วงหน้าเพื่อให้แน่ใจว่าสิ่งต่างๆ ทำงานได้อย่างถูกต้องหลังจากย้ายโค้ดทั้งหมด อาจจะนอกกรอบ แต่ก็เป็นข้อดีที่คุ้มค่า

หากคุณจำเป็นต้องใช้

CSP ระดับ 2 มีความเข้ากันได้แบบย้อนหลังสำหรับสคริปต์แบบในหน้า โดยช่วยให้คุณทำสิ่งต่อไปนี้ได้ เพิ่มสคริปต์แบบในหน้าลงในรายการที่อนุญาต โดยใช้ค่า Nonce สำหรับการเข้ารหัส (ตัวเลข (เพียงครั้งเดียว) หรือแฮช แม้วิธีนี้อาจยุ่งยาก แต่ก็มีประโยชน์ ในการบีบนิ้วเข้าหากัน

หากต้องการใช้ค่า Nonce ให้ระบุแอตทริบิวต์ Nonce ให้แท็กสคริปต์ ค่าต้องตรงกับ 1 ในรายการแหล่งที่มาที่เชื่อถือได้ เช่น

<script nonce="EDNnf03nceIOfn39fn3e9h3sdfa">
  // Some inline code I can't remove yet, but need to asap.
</script>

ตอนนี้ ให้เพิ่ม Nonce ลงในคำสั่ง script-src ต่อท้ายคีย์เวิร์ด nonce-

Content-Security-Policy: script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa'

โปรดจำไว้ว่า nonces ต้องได้รับการสร้างใหม่สำหรับทุกคำขอหน้าเว็บและ คาดเดาไม่ได้

แฮชจะทำงานในลักษณะเดียวกัน แทนที่จะเพิ่มโค้ดลงในแท็กสคริปต์ สร้างแฮช SHA ของสคริปต์และเพิ่มลงในคำสั่ง script-src เช่น สมมติว่าหน้าเว็บมีเนื้อหาต่อไปนี้

<script>
  alert('Hello, world.');
</script>

นโยบายของคุณจะประกอบด้วย:

Content-Security-Policy: script-src 'sha256-qznLcsROx4GACP2dm0UCKCzCG-HiZ1guq6ZZDob_Tng='

มี 2-3 อย่างที่ควรทราบที่นี่ คำนำหน้า sha*- จะระบุอัลกอริทึม ที่สร้างแฮช ในตัวอย่างด้านบน ระบบใช้ sha256- CSP ด้วย รองรับ sha384- และ sha512- เมื่อสร้างแฮช ไม่ต้องใส่ แท็ก <script> รวมทั้งการใช้อักษรตัวพิมพ์ใหญ่และช่องว่าง ซึ่งรวมถึงเครื่องหมายนำหน้าหรือ ต่อท้ายด้วยช่องว่าง

การค้นหาของ Google เกี่ยวกับการสร้างแฮช SHA จะนำคุณไปยังโซลูชัน จำนวนภาษา เมื่อใช้ Chrome 40 ขึ้นไป คุณจะเปิดเครื่องมือสำหรับนักพัฒนาเว็บจากนั้น โหลดหน้าของคุณซ้ำ แท็บคอนโซลจะมีข้อความแสดงข้อผิดพลาดพร้อมข้อความ แฮช sha256 สำหรับสคริปต์ในหน้าแต่ละรายการ

ประเมินด้วย

แม้ผู้โจมตีจะแทรกสคริปต์โดยตรงไม่ได้ แต่ก็อาจหลอกล่อได้ แอปพลิเคชันของคุณให้เป็นการแปลงข้อความเฉื่อยเป็น JavaScript ที่สั่งการได้ และดำเนินการในนามของผู้ลงโฆษณา eval(), ใหม่ Function() , setTimeout([string], ...) และ setInterval([string], ...) คือเวกเตอร์ทั้งหมดที่แทรกผ่าน อาจลงเอยด้วยการดำเนินการบางอย่างที่เป็นอันตรายโดยไม่คาดคิด ค่าเริ่มต้นของ CSP การตอบสนองต่อความเสี่ยงนี้คือการบล็อกเวกเตอร์เหล่านี้ทั้งหมด

ซึ่งมีผลกระทบมากกว่า 2-3 อย่างเกี่ยวกับวิธีสร้างแอปพลิเคชัน ดังนี้

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

การรายงาน

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

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

การใช้งานในชีวิตจริง

CSP 1 ค่อนข้างใช้งานได้ใน Chrome, Safari และ Firefox แต่มีข้อจำกัดอย่างมาก ที่สนับสนุนใน IE 10 คุณสามารถ ดูข้อมูลที่เฉพาะเจาะจงได้ที่ caniuse.com CSP ระดับ 2 พร้อมใช้งานใน Chrome ตั้งแต่ เวอร์ชัน 40 เว็บไซต์ขนาดใหญ่อย่าง Twitter และ Facebook ได้นำส่วนหัวไปใช้ (กรณีศึกษาของ Twitter ก็คุ้มค่าแก่การอ่านเช่นกัน) และมาตรฐานนี้ก็พร้อมแล้ว เพื่อให้คุณเริ่มติดตั้งใช้งานในเว็บไซต์ของคุณเอง

ขั้นตอนแรกในการสร้างนโยบายสำหรับแอปพลิเคชันของคุณคือการประเมิน ทรัพยากรที่คุณกำลังโหลดจริงๆ เมื่อคุณคิดว่าคุณมีความเข้าใจ ของสิ่งต่างๆ มารวมไว้ในแอปของคุณ ให้กำหนดนโยบายตาม ลองมาดูกรณีการใช้งานที่พบบ่อยสองสามกรณี และดูว่าเราจะ จะสามารถสนับสนุนผู้ใช้ภายในขอบเขตการป้องกันของ CSP ได้ดีที่สุด

กรณีการใช้งานที่ 1: วิดเจ็ตโซเชียลมีเดีย

  • ปุ่ม +1 ของ Google มีสคริปต์จาก https://apis.google.com และฝัง <iframe> จาก https://plusone.google.com คุณต้องมีนโยบายที่มีทั้ง 2 อย่างนี้ ต้นทางในการฝังปุ่ม นโยบายขั้นต่ำคือ script-src https://apis.google.com; child-src https://plusone.google.com นอกจากนี้ คุณยังต้อง เพื่อให้แน่ใจว่ามีการดึงข้อมูลโค้ด JavaScript ที่ Google ให้มา ไฟล์ JavaScript ภายนอก หากคุณมีนโยบายระดับ 1 ซึ่งใช้ frame-src ระดับ 2 กำหนดให้คุณต้องเปลี่ยนเป็น child-src ไม่จำเป็นต้องดำเนินการแล้ว ใน CSP ระดับ 3

  • ปุ่มชอบของ Facebook มีตัวเลือกการใช้งานมากมาย เราขอแนะนำให้คุณใช้ <iframe> เนื่องจากเป็นแซนด์บ็อกซ์อย่างปลอดภัยจากส่วนอื่นๆ ในเว็บไซต์ ทั้งนี้ ต้องใช้คำสั่ง child-src https://facebook.com เพื่อให้ทำงานได้อย่างถูกต้อง หมายเหตุ ซึ่งโดยค่าเริ่มต้นแล้ว รหัส <iframe> ที่ Facebook มีให้จะโหลด URL, //facebook.com เปลี่ยนค่านี้เพื่อระบุ HTTPS อย่างชัดเจน https://facebook.com ไม่มีเหตุผลที่จะใช้ HTTP หากคุณไม่จำเป็น

  • ปุ่มทวีตของ Twitter ต้องอาศัยการเข้าถึงสคริปต์และเฟรม ทั้งโฮสต์ที่ https://platform.twitter.com (ในทำนองเดียวกัน Twitter ยังให้ URL สัมพัทธ์ด้วย default; แก้ไขโค้ดเพื่อระบุ HTTPS เมื่อคัดลอก/วางในเครื่อง) คุณจะใช้ script-src https://platform.twitter.com; child-src https://platform.twitter.com ได้ตราบใดที่ย้ายข้อมูลโค้ด JavaScript ที่ Twitter มอบให้ในไฟล์ JavaScript ภายนอก

  • แพลตฟอร์มอื่นๆ มีข้อกำหนดที่คล้ายกันและแก้ไขในลักษณะเดียวกันได้ เราขอแนะนำให้ตั้งค่า default-src เป็น 'none' และดูคอนโซลเพื่อ กำหนดว่าจะต้องเปิดใช้ทรัพยากรใดเพื่อให้วิดเจ็ตทำงานได้

การรวมวิดเจ็ตหลายรายการนั้นทำได้ง่าย เพียงรวมนโยบายเข้าด้วยกัน แทน การจดจำการรวมทรัพยากรทั้งหมดของประเภทเดียวให้เป็น คำสั่ง หากคุณต้องการวิดเจ็ตโซเชียลมีเดียทั้ง 3 แบบ นโยบายจะมีลักษณะ ดังนี้

script-src https://apis.google.com https://platform.twitter.com; child-src https://plusone.google.com https://facebook.com https://platform.twitter.com

กรณีการใช้งานที่ 2: การปิดล็อก

สมมติว่าคุณมีเว็บไซต์ธนาคารและต้องการตรวจสอบว่า เฉพาะแหล่งข้อมูลที่คุณเขียนเองเท่านั้นที่จะโหลดได้ ในสถานการณ์นี้ เริ่มต้นด้วยนโยบายเริ่มต้นที่บล็อกทุกสิ่งทุกอย่าง (default-src 'none') และต่อยอดจากจุดนั้น

สมมติว่าธนาคารโหลดรูปภาพ รูปแบบ และสคริปต์ทั้งหมดจาก CDN ที่ https://cdn.mybank.net และเชื่อมต่อผ่าน XHR ไปยัง https://api.mybank.com/ ไปยัง ดึงข้อมูลส่วนต่างๆ ได้ จะใช้เฟรม แต่เฉพาะสำหรับหน้าเว็บที่เชื่อมโยงกับ เว็บไซต์ (ไม่มีต้นทางของบุคคลที่สาม) ไม่มี 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'

กรณีการใช้งานที่ 3: SSL เท่านั้น

ผู้ดูแลระบบฟอรัมสนทนาเกี่ยวกับงานแต่งงานต้องการตรวจสอบว่าทรัพยากรทั้งหมด โหลดผ่านช่องทางที่ปลอดภัยเท่านั้น แต่ไม่ได้เขียนโค้ดมากนัก การเขียนใหม่ ซอฟต์แวร์ฟอรัมของบุคคลที่สามจำนวนมากซึ่งเต็มไปด้วย สคริปต์และสไตล์ของแทรกในบรรทัดเป็นมากกว่าความสามารถของเขา นโยบายต่อไปนี้จะเป็น มีผล:

Content-Security-Policy: default-src https:; script-src https: 'unsafe-inline'; style-src https: 'unsafe-inline'

แม้ว่าจะระบุ https: เป็น default-src แต่สคริปต์และรูปแบบ จะไม่สืบทอดแหล่งที่มานั้นโดยอัตโนมัติ คำสั่งแต่ละรายการ เขียนทับค่าเริ่มต้นสำหรับประเภททรัพยากรที่ระบุ

อนาคต

นโยบายรักษาความปลอดภัยเนื้อหาระดับ 2 คือ คำแนะนำสำหรับผู้สมัคร คณะทำงานด้านการรักษาความปลอดภัยสำหรับเว็บแอปพลิเคชันของ W3C ได้เริ่มทำการปรับปรุง ครั้งถัดไปของข้อกำหนดแล้ว นโยบายรักษาความปลอดภัยเนื้อหาระดับ 3

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

ความคิดเห็น