CORS - แรงจูงใจเบื้องหลังการแนะนำคำขอ preflight คืออะไร?


366

การแบ่งปันทรัพยากรข้ามแหล่งกำเนิดเป็นกลไกที่อนุญาตให้เว็บเพจสร้าง XMLHttpRequests ไปยังโดเมนอื่น (จากวิกิพีเดีย )

ฉันเล่นซอกับ CORS ในสองสามวันที่ผ่านมาและฉันคิดว่าฉันมีความเข้าใจที่ดีเกี่ยวกับการทำงานทุกอย่าง

ดังนั้นคำถามของฉันไม่ได้เกี่ยวกับวิธีการที่ล ธ / ทำงาน preflight มันเป็นเรื่องของเหตุผลที่อยู่เบื้องหลังขึ้นมาพร้อมกับ preflights เป็นชนิดคำขอใหม่ ฉันไม่เห็นเหตุผลใด ๆ ว่าทำไมเซิร์ฟเวอร์ A ต้องส่ง preflight (PR) ไปยังเซิร์ฟเวอร์ B เพื่อตรวจสอบว่าคำขอจริง (RR) จะได้รับการยอมรับหรือไม่ - แน่นอนว่า B จะยอมรับ / ปฏิเสธ RR ได้โดยไม่ต้อง PR ก่อนหน้าใด ๆ

หลังจากค้นหาค่อนข้างน้อยฉันพบข้อมูลชิ้นนี้ที่ www.w3.org (7.1.5):

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

ฉันคิดว่านี่เป็นประโยคที่เข้าใจยากที่สุดเท่าที่เคยมีมา การตีความของฉัน (ควรเรียกว่า 'เดาได้ดีที่สุด') คือการปกป้องเซิร์ฟเวอร์ B จากการร้องขอจากเซิร์ฟเวอร์ C ที่ไม่ทราบรายละเอียด

ใครช่วยอธิบายสถานการณ์ / แสดงปัญหาที่ PR + RR แก้ได้ดีกว่า RR เพียงอย่างเดียวได้ไหม

คำตอบ:


323

ฉันใช้เวลาสับสนกับวัตถุประสงค์ของคำขอ preflight แต่ฉันคิดว่าฉันได้รับแล้ว

ความเข้าใจที่สำคัญคือคำขอ preflight ไม่ได้เป็นสิ่งที่ปลอดภัย แต่พวกเขากำลังไม่เปลี่ยนแปลงที่กฎสิ่ง

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

มีสามสถานการณ์ที่นี่:

  1. เซิร์ฟเวอร์เก่าไม่อยู่ระหว่างการพัฒนาและพัฒนาต่อหน้า CORS เซิร์ฟเวอร์เหล่านี้อาจตั้งสมมติฐานว่าจะไม่ได้รับเช่นคำขอลบข้ามโดเมน สถานการณ์นี้เป็นผลประโยชน์หลักของกลไก preflight ใช่บริการเหล่านี้อาจถูกใช้งานโดยตัวแทนผู้ใช้ที่เป็นอันตรายหรือไม่สอดคล้อง (และ CORS ไม่ทำอะไรเพื่อเปลี่ยนแปลงสิ่งนี้) แต่ในโลกที่มี CORS กลไก preflight จะให้การตรวจสุขภาพแบบพิเศษเพื่อให้ลูกค้าและเซิร์ฟเวอร์ไม่ทำงาน ทำลายเนื่องจากกฎพื้นฐานของเว็บเปลี่ยนไป

  2. เซิร์ฟเวอร์ที่ยังอยู่ระหว่างการพัฒนา แต่มีรหัสเก่าจำนวนมากและไม่สามารถตรวจสอบรหัสเก่าทั้งหมดได้เพื่อตรวจสอบให้แน่ใจว่าทำงานได้อย่างถูกต้องในโลกข้ามโดเมน สถานการณ์นี้อนุญาตให้เซิร์ฟเวอร์เลือกใช้ CORS อย่างต่อเนื่องเช่นโดยพูดว่า "ตอนนี้ฉันจะอนุญาตหัวข้อนี้โดยเฉพาะ", "ตอนนี้ฉันจะอนุญาตคำกริยา HTTP เฉพาะนี้", "ตอนนี้ฉันจะอนุญาตให้คุกกี้ / ข้อมูลรับรองความถูกต้อง ส่ง "ฯลฯสถานการณ์นี้ได้รับประโยชน์จากกลไก preflight

  3. เซิร์ฟเวอร์ใหม่ที่เขียนด้วยความตระหนักถึง CORS ตามแนวทางการรักษาความปลอดภัยมาตรฐานเซิร์ฟเวอร์จะต้องปกป้องทรัพยากรของตนในหน้าคำขอที่เข้ามาใด ๆ - เซิร์ฟเวอร์ไม่สามารถเชื่อถือลูกค้าไม่ให้ทำสิ่งที่เป็นอันตราย สถานการณ์นี้ไม่ได้รับประโยชน์จากกลไก preflight : กลไก preflight ไม่นำความปลอดภัยเพิ่มเติมไปยังเซิร์ฟเวอร์ที่ได้รับการปกป้องทรัพยากรอย่างเหมาะสม


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

3
ข้อมูลจำเพาะรวมถึงpreflight-result-cacheในเบราว์เซอร์ ดังนั้นในขณะที่มันยังรู้สึกปลอดภัยและไร้ประสิทธิภาพดูเหมือนว่าเป็นไปได้ที่จะกำหนดค่าเซิร์ฟเวอร์ใหม่เพื่อให้แคช preflight ไม่สิ้นสุด
Michael Cole

7
ฉันยอมรับว่าคำขอ preflight ไม่ได้เกี่ยวข้องกับความปลอดภัยโดยเนื้อแท้ แต่ดูเหมือนว่าการใช้คำขอ preflight ใน CORS นั้นแน่นอนด้วยเหตุผลด้านความปลอดภัย มันเป็นมากกว่าการตรวจสอบสติเพื่อป้องกันสถานการณ์ข้อผิดพลาดที่ค่อนข้างอันตราย หากเอเจนต์ผู้ใช้ส่งการร้องขอไปยังเซิร์ฟเวอร์โดยไม่ตั้งใจสมมติว่าเซิร์ฟเวอร์นำ CORS มาใช้อย่างไม่น่าจะเป็นไปได้มากที่สุดที่จะยอมรับการปลอมแปลงข้ามไซต์ แม้ว่า javascript จะไม่สามารถอ่านการตอบสนองได้ แต่เซิร์ฟเวอร์อาจมีการกระทำที่ไม่พึงประสงค์เช่นลบบัญชีหรือโอนเงินผ่านธนาคาร
Alexander Taylor

5
ปัญหาคือ preflight-result-cache นั้นไร้ประโยชน์เพราะ 1. มันใช้เฉพาะกับการร้องขอที่แน่นอนไม่ใช่ทั้งโดเมนดังนั้นการร้องขอทั้งหมดจะเป็นการ preflight ในครั้งแรกอย่างไรก็ตาม และตามที่ได้ดำเนินการไปแล้วนั้นจะถูก จำกัด ไว้ที่ 10 นาทีในเบราว์เซอร์ส่วนใหญ่ดังนั้นอย่าเข้าใกล้เบราว์เซอร์
davidgoli

2
@VikasBansal เซิร์ฟเวอร์ที่มีอยู่จะต้อง "เข้าร่วม" และตกลงที่จะแบ่งปันทรัพยากรของพวกเขาข้ามจุดกำเนิดโดยกำหนดค่าวิธีที่พวกเขาตอบกลับคำขอตัวเลือก preflight หากพวกเขาไม่ตอบคำขอ preflight อย่างชัดเจนเบราว์เซอร์จะไม่ออกคำขอจริง เซิร์ฟเวอร์บางตัวอาจไม่ต้องการรับการร้องขอข้ามทาง
เควินลี

215

แรงจูงใจเบื้องหลังการแนะนำคำขอ preflight คืออะไร

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

นั่นคือความหมายของส่วนหนึ่งของข้อมูลจำเพาะ : "เพื่อปกป้องทรัพยากรจากการร้องขอข้ามแหล่งที่ไม่สามารถเกิดจากตัวแทนผู้ใช้บางรายก่อนที่ข้อกำหนดนี้จะมีการร้องขอ preflight ถูกสร้างขึ้นเพื่อให้แน่ใจว่าทรัพยากรตระหนักถึงข้อกำหนดนี้"

คุณยกตัวอย่างให้ฉันได้ไหม

A.comลองจินตนาการว่าผู้ใช้เบราว์เซอร์จะเข้าสู่เว็บไซต์ธนาคารของพวกเขาที่ เมื่อพวกเขาไปที่ที่เป็นอันตรายB.com, หน้าที่มี Javascript บางอย่างที่พยายามที่จะส่งคำขอไปยังDELETE A.com/accountเนื่องจากผู้ใช้เข้าสู่ระบบA.comคำขอนั้นถ้าส่งจะรวมถึงคุกกี้ที่ระบุผู้ใช้

ก่อน CORS นโยบายแหล่งกำเนิดเดียวกันของเบราว์เซอร์จะบล็อกไม่ให้ส่งคำขอนี้ แต่เนื่องจากจุดประสงค์ของ CORS คือการทำให้การสื่อสารข้ามจุดประสงค์นี้เป็นไปได้จึงไม่เหมาะสมอีกต่อไป

เบราว์เซอร์สามารถส่งDELETEและแจ้งให้เซิร์ฟเวอร์ตัดสินใจว่าจะจัดการกับมันอย่างไร แต่ถ้าหากA.comไม่รู้เกี่ยวกับโปรโตคอล CORS ล่ะ DELETEมันอาจจะไปข้างหน้าและดำเนินการที่เป็นอันตราย อาจสันนิษฐานว่า - เนื่องจากนโยบายกำเนิดเดียวกันของเบราว์เซอร์ - ไม่สามารถรับคำขอดังกล่าวได้และดังนั้นจึงอาจไม่เคยถูกต่อต้านจากการโจมตีดังกล่าว

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

เหตุใดเรื่องทั้งหมดนี้เกี่ยวกับเบราว์เซอร์ผู้โจมตีเพียงแค่ส่งDELETEคำขอจากคอมพิวเตอร์ของตนเองไม่ได้?

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

เสียงที่เหมือนข้ามไซต์ปลอมขอที่แบบฟอร์มในเว็บไซต์B.comสามารถPOSTไปA.comกับคุกกี้ของผู้ใช้และจะเกิดความเสียหาย

ถูกตัอง. อีกวิธีหนึ่งในการทำเช่นนี้คือคำขอ preflight ถูกสร้างขึ้นเพื่อไม่เพิ่มพื้นผิวการโจมตี CSRF สำหรับเซิร์ฟเวอร์ที่ไม่ทราบ CORS

แต่เมื่อดูข้อกำหนดสำหรับคำขอ "เรียบง่าย" ที่ไม่ต้องใช้ไฟลต์ฉันเห็นว่าPOSTยังคงได้รับอนุญาต ที่สามารถเปลี่ยนสถานะและลบข้อมูลได้เหมือนDELETE!

นั่นเป็นความจริง! CORS ไม่ปกป้องไซต์ของคุณจากการโจมตี CSRF จากนั้นอีกครั้งหากไม่มี CORS คุณจะไม่ได้รับการปกป้องจากการโจมตี CSRF วัตถุประสงค์ของคำขอ preflight คือเพื่อ จำกัด การเปิดเผย CSRF ของคุณกับสิ่งที่มีอยู่แล้วในโลกก่อนยุค

ถอนหายใจ ตกลงฉันไม่เต็มใจยอมรับความต้องการคำขอ preflight แต่ทำไมเราต้องทำกับทุก ๆ ทรัพยากร (URL) บนเซิร์ฟเวอร์? เซิร์ฟเวอร์จัดการกับ CORS ไม่เช่นนั้น

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

ละเอียด. มาประนีประนอมกัน มาสร้างส่วนหัว CORS ใหม่ที่อนุญาตให้เซิร์ฟเวอร์ระบุทรัพยากรที่สามารถพูดได้อย่างแม่นยำเพื่อที่จะหลีกเลี่ยงคำขอ preflight เพิ่มเติมไปยัง URL เหล่านั้น

ความคิดที่ดี! ในความเป็นจริงส่วนหัวAccess-Control-Policy-Pathถูกเสนอเพื่อวัตถุประสงค์นี้เท่านั้น ในที่สุดแม้ว่ามันจะถูกปล่อยออกมาจากสเปคเห็นได้ชัดเพราะบางเซิร์ฟเวอร์ดำเนินเปค URI ในทางที่ไม่ถูกต้องดังกล่าวว่าการร้องขอไปยังเส้นทางที่ดูเหมือนจะปลอดภัยในการเบราว์เซอร์จะไม่ได้อยู่ในความเป็นจริงจะปลอดภัยบนเซิร์ฟเวอร์ของเสีย

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

ความคิดเห็นที่แตกต่าง

เบราว์เซอร์อย่างน้อยที่สุดจะแคช preflight สำหรับ URL เดียวหรือไม่

ใช่. แม้ว่าอาจจะไม่นานนัก ในเบราว์เซอร์ WebKit เวลาแคช preflight สูงสุดคือ10 นาทีในปัจจุบัน

ถอนหายใจ ถ้าฉันรู้ว่าเซิร์ฟเวอร์ของฉันทราบถึง CORS และดังนั้นจึงไม่ต้องการการปกป้องจากคำขอ preflight มีวิธีใดบ้างที่ฉันจะหลีกเลี่ยงได้

ทางเลือกเดียวที่แท้จริงของคุณคือตรวจสอบให้แน่ใจว่าคุณปฏิบัติตามข้อกำหนดสำหรับคำขอ "เรียบง่าย" นั่นอาจหมายถึงการออกจากส่วนหัวที่กำหนดเองที่คุณจะใส่ (เช่นX-Requested-With) โกหกเกี่ยวกับContent-Typeหรือมากกว่านั้น

สิ่งที่คุณทำคุณต้องให้แน่ใจว่าคุณมีการป้องกัน CSRF เหมาะสมในสถานที่ตั้งแต่ข้อกำหนดล ธ ไม่อยู่ไม่ได้ปฏิเสธ "ง่าย" POSTการร้องขอรวมทั้งที่ไม่ปลอดภัย ตามข้อกำหนดที่ระบุไว้ : "ทรัพยากรที่คำของ่ายมีความสำคัญนอกเหนือจากการดึงข้อมูลต้องป้องกันตนเองจากการปลอมแปลงคำขอข้ามไซต์"


20
นี่คือบทนำเบื้องต้นที่ดีที่สุดที่ฉันได้อ่านบน CORS ขอบคุณ!
kiv

4
อธิบายอย่างสุดยอด
Pratz

4
นี่คือคำตอบที่ดีที่สุดที่ฉันได้เห็นในหัวข้อ อธิบายได้ดีมาก!
alaboudi

3
CORS เป็นวัสดุที่ยุ่งยากและโพสต์นี้หลั่งน้ำตาแสงในบางจุดที่ซ่อนอยู่
Stanislav Verjikovskiy

1
@Yos: เบราว์เซอร์จะรวมคุกกี้เหล่านั้นเพราะนั่นเป็นวิธีที่เบราว์เซอร์คาดว่าจะทำงาน (ตามประมวลในมาตรฐานเช่นRFC 6265 ) เบราว์เซอร์ใช้กระบวนการแยกแท็บเป็นรายละเอียดในการติดตั้งหรือไม่เบราว์เซอร์จะไม่ป้องกันการส่งคุกกี้
Kevin Christopher Henry

51

พิจารณาโลกของการร้องขอข้ามโดเมนก่อน CORS คุณสามารถทำแบบฟอร์ม POST มาตรฐานหรือใช้scriptหรือimageแท็กเพื่อออกคำขอ GET คุณไม่สามารถสร้างคำขอประเภทอื่นนอกเหนือจาก GET / POST และคุณไม่สามารถออกส่วนหัวที่กำหนดเองในคำขอเหล่านี้ได้

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

ดังนั้นคำขอ GET / POST ที่ไม่มีส่วนหัวที่กำหนดเองไม่จำเป็นต้องมี preflight เนื่องจากคำขอเหล่านี้เป็นไปได้ก่อน CORS แต่ร้องขอใด ๆ ที่มีส่วนหัวที่กำหนดเองหรือ PUT / คำขอลบไม่ต้อง preflight ตั้งแต่เหล่านี้ยังใหม่กับ ธ ข้อมูลจำเพาะ หากเซิร์ฟเวอร์ไม่รู้อะไรเกี่ยวกับ CORS เซิร์ฟเวอร์จะตอบกลับโดยไม่มีส่วนหัวเฉพาะของ CORS และคำขอจริงจะไม่ถูกสร้างขึ้น

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


คุณสร้างคำขอ POST ผ่านแท็กสคริปต์ / img ได้อย่างไร
ประหลาด

2
คุณทำไม่ได้ ฉันหมายความว่าคุณสามารถทำแบบฟอร์ม POST หรือทำ GET โดยใช้สคริปต์ / img ฉันแก้ไขโพสต์เพื่อหวังชี้แจงนี้
นาย

ฉันเห็น. นั่นทำให้รู้สึก
ประหลาด

5
ขอบคุณสำหรับคำตอบนั่นคือภาพของฉัน! น่าเสียดายที่ฉันยังไม่เห็นจุดศูนย์กลางด้านหลังพรีไลท์ เกี่ยวกับคำตอบของคุณ: ' คำขอที่ไม่คาดคิด ' จะเป็นอย่างไร มันจะปลอดภัยกว่าที่คาดไม่ถึงหรือปลอดภัยน้อยกว่าในโลกที่ไม่มี preflight มากกว่าในโลกที่มีแสงไฟ (เช่นเช่น preflight ที่หายไปหรือเบราว์เซอร์ที่เป็นอันตรายซึ่ง 'ลืม' เกี่ยวกับ preflighting) ได้อย่างไร
jan groth

7
อาจมี APIs อยู่ที่นั่นซึ่งใช้นโยบายต้นกำเนิดเดียวกันของเบราว์เซอร์เพื่อปกป้องทรัพยากรของพวกเขา พวกเขาควรมีความปลอดภัยเพิ่มเติม แต่พวกเขาต้องพึ่งพานโยบายต้นทางเดียวกันแทน หากไม่มี preflight ผู้ใช้บนโดเมนอื่นจะสามารถส่งคำขอไปยัง API ได้ API จะถือว่าการร้องขอนั้นถูกต้อง (เนื่องจากไม่ทราบ CORS) และดำเนินการตามคำขอ เบราว์เซอร์สามารถบล็อกการตอบสนองจากการเข้าถึงผู้ใช้ แต่ ณ จุดนี้ความเสียหายอาจทำไปแล้ว หากคำขอเป็น PUT / DELETE ทรัพยากรอาจถูกอัปเดตหรือลบ
นาย

37

ล ธ ช่วยให้คุณระบุส่วนหัวมากขึ้นและวิธีการประเภทกว่าเป็นไปได้ก่อนหน้านี้กับข้ามกำเนิดหรือ<img src><form action>

เซิร์ฟเวอร์บางแห่งอาจได้รับการป้องกัน (ไม่ดี) โดยมีข้อสันนิษฐานที่เบราว์เซอร์ไม่สามารถทำได้เช่นDELETEคำขอข้ามต้นทางหรือคำขอข้ามต้นฉบับที่มีX-Requested-Withส่วนหัวดังนั้นคำขอดังกล่าวจึงเป็น "เชื่อถือได้"

เพื่อให้แน่ใจว่าเซิร์ฟเวอร์รองรับ CORS จริงๆและไม่เพียง แต่ตอบสนองต่อคำขอแบบสุ่มเท่านั้น


12
นี่ควรเป็นคำตอบที่ยอมรับได้ มันเป็นสิ่งที่ชัดเจนที่สุดและตรงประเด็นที่สุด ในสาระสำคัญจุดประสงค์เดียวของการร้องขอ preflight คือการรวมมาตรฐานเว็บ pre-CORS กับมาตรฐานเว็บ post-CORS
chopper วาด lion4

2
ฉันชอบคำตอบนี้ แต่ฉันรู้สึกว่ามันเป็นเหตุผลที่ไม่สมบูรณ์ ... "ข้อสันนิษฐานของความเชื่อมั่น" ต้องใช้กับสิ่งที่เบราว์เซอร์ทำได้เท่านั้น (โดยเฉพาะการส่งข้อมูลผู้ใช้ของเบราว์เซอร์ที่ จำกัด โดเมนของพวกเขา - นั่นคือคุกกี้) หากนั่นไม่ใช่ส่วนหนึ่งของข้อสันนิษฐานดังนั้นคำขอของเบราว์เซอร์ข้ามแหล่งใดที่สามารถทำได้โดยตัวแทนบุคคลที่สามที่ไม่ใช่เบราว์เซอร์ใช่ไหม
Fabio Beltramini

2
@FabioBeltramini ใช่ไม่ใช่เบราว์เซอร์สามารถส่งสิ่งที่พวกเขาต้องการ อย่างไรก็ตามการโจมตีผ่านเบราว์เซอร์นั้นมีความพิเศษเพราะคุณสามารถทำให้เบราว์เซอร์ของผู้อื่นทำสิ่งต่าง ๆ จาก IP ของตัวเองด้วยคุกกี้ของตัวเองและอื่น ๆ
Kornel

ฉันเริ่มเห็นปัญหาที่แท้จริง ขอบคุณสำหรับความคิดเห็นและการตอบกลับของ @FabioBeltramini และ Kronel หากไม่มีการตรวจสอบเที่ยวบินล่วงหน้าผู้โจมตีจะสามารถวางโค้ด JavaScript บนเว็บไซต์ของเขาได้ แต่ถูกสั่งจากคอมพิวเตอร์ของคนอื่น ลูกค้าอื่น ๆ ทั้งหมดเป็นเรื่องยากที่จะ "จ้าง" ผู้อื่นให้ทำเช่นนี้รวมถึงแอพมือถือ
Xiao Peng - ZenUML.com

16

นี่เป็นอีกวิธีหนึ่งในการดูโดยใช้รหัส:

<!-- hypothetical exploit on evil.com -->
<!-- Targeting banking-website.example.com, which authenticates with a cookie -->
<script>
jQuery.ajax({
  method: "POST",
  url: "https://banking-website.example.com",
  data: JSON.stringify({
    sendMoneyTo: "Dr Evil",
    amount: 1000000
  }),
  contentType: "application/json",
  dataType: "json"
});
</script>

Pre-CORS ความพยายามในการหาช่องโหว่ด้านบนจะล้มเหลวเนื่องจากละเมิดนโยบายที่มาดั้งเดิม API ที่ออกแบบมาด้วยวิธีนี้ไม่ต้องการการป้องกัน XSRF เพราะได้รับการคุ้มครองโดยรูปแบบความปลอดภัยดั้งเดิมของเบราว์เซอร์ มันเป็นไปไม่ได้ที่เบราว์เซอร์ก่อนหน้า CORS จะสร้าง JSON POST ไขว้

ตอนนี้ CORS เข้ามาในสถานที่เกิดเหตุ - หากไม่จำเป็นต้องเข้าร่วม CORS ผ่านทางเที่ยวบินล่วงหน้าเว็บไซต์นี้ก็จะมีช่องโหว่ขนาดใหญ่โดยไม่มีข้อบกพร่องของตนเอง

เพื่ออธิบายว่าทำไมบางคำขอได้รับอนุญาตให้ข้าม pre-flight นี่คือคำตอบโดย spec:

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

หากต้องการแก้ให้หายยุ่ง GET จะไม่ทำการบินล่วงหน้าเนื่องจากเป็น "วิธีการง่าย" ตามที่กำหนดโดย 7.1.5 (ส่วนหัวจะต้องเป็น "วิ" เพื่อหลีกเลี่ยงก่อนการบิน) เหตุผลสำหรับสิ่งนี้คือการร้องขอ GET แบบ "ข้าม" แบบง่ายสามารถดำเนินการได้แล้วโดยเช่น<script src="">(นี่คือวิธีที่ JSONP ทำงาน) เนื่องจากองค์ประกอบใด ๆ ที่มีแอsrcททริบิวต์สามารถเรียกใช้ GET แบบข้ามจุดกำเนิดโดยไม่มีการบินล่วงหน้าดังนั้นจึงไม่มีประโยชน์ด้านความปลอดภัยที่ต้องมีการต่อสู้ล่วงหน้ากับ XHR แบบ "ง่าย"


1
@MilesRout: Telnet ไม่ได้เป็นส่วนหนึ่งของรูปแบบการคุกคามที่ preflights มุ่งหวังที่จะบรรเทา preflight เกี่ยวข้องกับเบราว์เซอร์ที่ 1) การจัดเก็บ "ผู้มีอำนาจโดยรอบ" (เช่นคุกกี้) และ 2) สามารถถูกหลอกในการใช้อำนาจในทางที่ผิดโดยบุคคลที่สาม (เช่นการปลอมแปลงคำขอข้ามไซต์) รุ่นทั่วไปเป็นที่รู้จักกันเป็นปัญหารองสับสน
Dylan Tack

นั่นเป็นปัญหาของผู้มีอำนาจโดยรอบคุณสามารถใช้ในทางที่ผิดได้
Miles Rout

13

ฉันรู้สึกว่าคำตอบอื่น ๆ ไม่ได้เน้นไปที่เหตุผลก่อนการต่อสู้เพื่อเพิ่มความปลอดภัย

สถานการณ์:

1) ด้วยการบินล่วงหน้า ผู้โจมตีปลอมคำขอจากเว็บไซต์ dummy-forums.com ในขณะที่ผู้ใช้รับรองความถูกต้องไปที่ safe-bank.com
หากเซิร์ฟเวอร์ไม่ได้ตรวจสอบที่มาและมีข้อบกพร่องเบราว์เซอร์จะออกคำขอเที่ยวบินล่วงหน้าตัวเลือก วิธี. เซิร์ฟเวอร์ไม่รู้ว่า CORS ใดที่เบราว์เซอร์คาดหวังว่าเป็นการตอบสนองดังนั้นเบราว์เซอร์จะไม่ดำเนินการต่อ (ไม่เป็นอันตรายใด ๆ )

2) โดยไม่ต้องทำการบินล่วงหน้า ผู้โจมตีปลอมคำขอภายใต้สถานการณ์เดียวกันข้างบนเบราว์เซอร์จะออกคำขอ POST หรือ PUT ทันทีเซิร์ฟเวอร์ยอมรับและอาจประมวลผลซึ่งอาจทำให้เกิดอันตรายได้

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

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


เห็นด้วยกับปัญหาการโจมตี CSRF ที่ยังคงเป็นไปได้กับ "เซิร์ฟเวอร์ใหม่" ที่กล่าวถึงในการตอบกลับของ @ michael-iles
ปลาไหล gEEE

นี่เป็นคำอธิบายที่มีประโยชน์ซึ่งอาจคุ้มค่าที่จะบันทึกที่อื่น อาจลองเพิ่มไปยังหน้า MDN หน้าใดหน้าหนึ่ง
sideshowbarker

แต่ทำไมคำขอบางอย่างเช่น POST ที่มีข้อความประเภทเนื้อหา / ธรรมดาไม่ทำการร้องขอล่วงหน้า ในหัวของฉันคำขอ 'เขียน' ทุกครั้ง (POST, PUT, DELETE) ควรมีคำขอล่วงหน้าก่อนเที่ยวบินนี้หากความปลอดภัยเป็นปัญหา
Israel Fonseca

POST with text / plain ถือเป็นการร้องของ่ายๆ - โปรดทราบว่าเบราว์เซอร์จะไม่แสดงการตอบสนองหากต้นกำเนิดไม่ตรง (ซึ่งอาจเป็นกรณีที่เซิร์ฟเวอร์ไม่ได้กำหนดค่าสำหรับ CORS)
Hirako

ในด้านการโจมตีมีสิ่งที่น่าสนใจที่สามารถทำได้การใช้ประโยชน์จากข้อเท็จจริงที่ว่าคำของ่าย ๆ นั้นยอมรับได้และจะถูกส่งโดยเบราว์เซอร์ส่วนใหญ่ เช่นนี้
Hirako

3

นอกจากนี้สำหรับวิธีการร้องขอ HTTP ที่อาจทำให้เกิด ข้างเคียงกับข้อมูลผู้ใช้ (โดยเฉพาะอย่างยิ่งสำหรับวิธี HTTP อื่น ๆ นอกเหนือจาก GET หรือสำหรับการใช้งาน POST ที่มีประเภท MIME บางประเภท)

แหล่ง


2

คำขอก่อนการบินจำเป็นสำหรับคำขอที่สามารถเปลี่ยนสถานะบนเซิร์ฟเวอร์ คำขอมี 2 ประเภท -

1) การโทรที่ไม่สามารถเปลี่ยนสถานะบนเซิร์ฟเวอร์ (เช่น GET) - ผู้ใช้อาจได้รับการตอบสนองสำหรับการร้องขอ (หากเซิร์ฟเวอร์ไม่ได้ตรวจสอบที่มา) แต่ถ้าโดเมนที่ร้องขอไม่ได้ถูกเพิ่มในส่วนหัวการตอบสนอง Access-Control- Allow-Origin เบราว์เซอร์ไม่แสดงข้อมูลต่อผู้ใช้เช่นคำขอถูกส่งจากเบราว์เซอร์ แต่ผู้ใช้ไม่สามารถดู / ใช้ประโยชน์จากการตอบกลับได้

2) การโทรที่สามารถเปลี่ยนสถานะบนเซิร์ฟเวอร์ (เช่น POST, DELETE) - ตั้งแต่ใน 1) เราจะเห็นว่าเบราว์เซอร์ไม่ได้ปิดกั้นการร้องขอ แต่การตอบสนองการเปลี่ยนสถานะการโทรไม่ควรได้รับอนุญาตโดยไม่ตรวจสอบล่วงหน้า . การเรียกดังกล่าวอาจทำการเปลี่ยนแปลงกับเซิร์ฟเวอร์ที่ไว้วางใจซึ่งไม่ได้ตรวจสอบที่มาของการโทร (เรียกว่าการข้ามคำขอไซต์ข้าม) แม้ว่าการตอบสนองต่อเบราว์เซอร์อาจล้มเหลว ด้วยเหตุนี้เราจึงมีแนวคิดของคำขอล่วงหน้าก่อนการบินที่จะทำการโทรแบบ OPTIONS ก่อนที่จะส่งการเปลี่ยนแปลงสถานะใด ๆ ไปยังเซิร์ฟเวอร์


1

คำขอที่ไม่ได้แสดงล่วงหน้าเกี่ยวกับประสิทธิภาพหรือไม่ ด้วยการร้องขอ preflighted ลูกค้าสามารถทราบได้อย่างรวดเร็วว่าการดำเนินการได้รับอนุญาตก่อนที่จะส่งข้อมูลจำนวนมากเช่นในวิธี JSON ด้วย PUT หรือก่อนที่จะเดินทางข้อมูลที่สำคัญในการตรวจสอบส่วนหัวลวด

ความจริงของ PUT, DELETE และวิธีอื่น ๆ นอกเหนือจากส่วนหัวที่กำหนดเองไม่ได้รับอนุญาตตามค่าเริ่มต้น (พวกเขาต้องการสิทธิ์ที่ชัดเจนกับ "Access-Control-Request-Methods-Methods" และ "Access-Control-Request-Headers") เช่นเดียวกับการตรวจสอบอีกครั้งเนื่องจากการดำเนินการเหล่านี้อาจมีความเกี่ยวข้องกับข้อมูลผู้ใช้มากกว่าขอ GET แทน ดังนั้นดูเหมือนว่า:

"ฉันเห็นว่าคุณอนุญาตคำขอข้ามไซต์จากhttp: //foo.exampleแต่คุณแน่ใจหรือไม่ว่าคุณจะอนุญาตคำขอ DELETE คุณพิจารณาถึงผลกระทบที่คำขอเหล่านี้อาจทำให้เกิดขึ้นในข้อมูลผู้ใช้หรือไม่"

ฉันไม่เข้าใจความสัมพันธ์ที่อ้างถึงระหว่างคำขอ preflighted และประโยชน์เซิร์ฟเวอร์เก่า บริการบนเว็บที่นำมาใช้ก่อน CORS หรือไม่มีการรับรู้ CORS จะไม่ได้รับการร้องขอข้ามไซต์ใด ๆ เพราะก่อนอื่นการตอบสนองจะไม่มีส่วนหัว "Access-Control-Allow-Origin"


4
คุณเข้าใจผิดว่า Access-Control-Allow-Origin การไม่มีส่วนหัวนั้นไม่ได้ป้องกันเบราว์เซอร์ไม่ให้ส่งคำขอ แต่จะป้องกันไม่ให้ JS สามารถอ่านข้อมูลในการตอบสนองได้
Dylan Tack

คุณช่วยอธิบายได้ไหมว่า 'การขาดงานของส่วนหัวนั้นไม่ได้ป้องกันเบราว์เซอร์จากการส่งคำขอ แต่ก็ป้องกันไม่ให้ JS สามารถอ่านข้อมูลในการตอบสนองได้' อีกครั้งฉันไม่ได้รับอย่างสมบูรณ์
SiddharthBhagwan

@ DylanTack จุดที่ดี นี่ทำให้ฉันสงสัยว่าทำไม GET xhr ถึงไม่เป็น preflight เช่นกัน? แม้ว่าจะไม่ได้รับคำขอ GET อาจเป็นอันตราย / การกลายพันธุ์ของข้อมูลเช่นกัน นอกจากนี้เนื่องจากทั้งหมดนี้สามารถแก้ไขได้ด้วย CSRF สิ่งนี้ดูเหมือนว่าสำหรับฉันแล้วเบราว์เซอร์กำลังปกป้องเซิร์ฟเวอร์ที่ประมาทเกินกว่าที่จะใช้แนวทางการรักษาความปลอดภัยทั่วไป
Peleg

คำตอบที่ได้รับการยอมรับอธิบายได้ดีว่าเป็น "สิ่งที่ไม่เปลี่ยนแปลง - กฎ" (เข้ากันได้ย้อนหลังกับเว็บไซต์ที่สร้างขึ้นก่อนที่ CORS จะมีอยู่) ยังคงเป็นที่น่าสนใจที่จะเห็นรหัสดังนั้นฉันโพสต์คำตอบอีกตัวอย่างรหัส
Dylan Tack

1

ในเบราว์เซอร์ที่รองรับ CORS คำขอการอ่าน (เช่น GET) ได้รับการคุ้มครองโดยนโยบายต้นทางเดียวกัน: เว็บไซต์ที่เป็นอันตรายที่พยายามส่งคำขอข้ามโดเมนที่ผ่านการรับรองความถูกต้อง (ตัวอย่างเช่นเว็บไซต์ธนาคารทางอินเทอร์เน็ตของเหยื่อหรืออินเตอร์เฟสการกำหนดค่าเราเตอร์) สามารถอ่านข้อมูลที่ส่งคืนได้เนื่องจากธนาคารหรือเราเตอร์ไม่ได้ตั้งค่าAccess-Control-Allow-Originส่วนหัว

อย่างไรก็ตามด้วยการร้องขอการเขียน (เช่น POST) ความเสียหายจะเกิดขึ้นเมื่อคำขอมาถึงที่เว็บเซิร์ฟเวอร์ * เว็บเซิร์ฟเวอร์สามารถตรวจสอบOriginส่วนหัวเพื่อตรวจสอบว่าคำขอนั้นถูกต้องหรือไม่ แต่การตรวจสอบนี้มักไม่ได้รับการดำเนินการ สำหรับ CORS หรือเว็บเซิร์ฟเวอร์เก่ากว่า CORS ดังนั้นจึงถือว่าสมมติว่า POST ข้ามโดเมนนั้นถูกห้ามอย่างสมบูรณ์โดยนโยบายแหล่งกำเนิดเดียวกัน

นั่นคือเหตุผลที่เว็บเซิร์ฟเวอร์จะได้รับโอกาสที่จะเลือกในการเข้ารับการร้องขอเขียนข้ามโดเมน

* เป็นหลักในเวอร์ชัน AJAX ของ CSRF

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.