โดเมนย่อยของผู้ดูแลไม่ได้หยุด CSRF: สี่การตรวจสอบก่อนเปิดใช้งาน
ชื่อโฮสต์ใหม่คือต้นกำเนิดใหม่ มักเป็นไซต์เดียวกัน คุกกี้ same-site และฟอร์มง่าย ๆ จึงข้ามผ่านมันไป ตรวจสอบโทเค็น ประตู และการอนุญาต
การย้ายส่วนติดต่อผู้ดูแลไปที่ admin.example.com เป็นการปรับปรุงจริง: มันเก็บคุกกี้ของผู้ดูแลให้ห่างจากหน้าสาธารณะ ให้แคชแยกกับแอปพลิเคชันทั้งสอง และทำให้คุณกำหนดนโยบายเครือข่ายที่เข้มกว่าไปยังชื่อโฮสต์เดียวได้ แต่มันไม่ใช่การควบคุม CSRF และไม่ได้ทำให้โค้ดของไซต์สาธารณะปลอดภัยพอที่จะเปิดทิ้งไว้ต่อหน้าผู้ดูแลที่เข้าสู่ระบบแล้ว การแยกเปลี่ยนสิ่งที่เบราว์เซอร์ถือเป็นขอบเขต ไม่ใช่สิ่งที่เซิร์ฟเวอร์ตรวจสอบ ดังนั้นจงทำสี่การตรวจสอบนี้ก่อนบอกว่าเสร็จแล้ว
อ่านต้นกำเนิดและไซต์เป็นคำสองคำที่ต่างกัน
ต้นกำเนิดคือสคีมา โฮสต์ และพอร์ต ดังนั้น https://www.example.com และ https://admin.example.com จึงเป็นต้นกำเนิดที่ต่างกัน ไซต์ในความหมายของ SameSite คือสคีมาบวกโดเมนที่ลงทะเบียนได้ ดังนั้นชื่อโฮสต์สองชื่อนั้นมักเป็นไซต์เดียวกัน ความต่างนี้คือกับดักทั้งหมด: แอตทริบิวต์ SameSite จะไม่ช่วยคุณระหว่างโดเมนย่อยพี่น้อง เพราะเบราว์เซอร์ไม่ถือว่าคำขอเป็นแบบข้ามไซต์เลย ชี้ส่วนติดต่อผู้ดูแลไปยังโดเมนที่ลงทะเบียนได้ต่างจริง เช่น admin-example.net แล้วคำขอจะกลายเป็นข้ามไซต์จริง และตรงนั้นเองที่ SameSite=Lax หรือ Strict เริ่มทำงานที่คุณไว้วางใจได้
ทดสอบในเบราว์เซอร์แทนการให้เหตุผลเกี่ยวกับมัน
โหลดไซต์สาธารณะ เปิดเครื่องมือนักพัฒนา และดูว่าคุกกี้ใดที่เบราว์เซอร์แนบไปกับคำขอที่มุ่งไปยังโฮสต์ผู้ดูแล หากคุกกี้ไม่มีแอตทริบิวต์ Domain มันเป็นของโฮสต์เท่านั้นและอยู่บนชื่อของตัวเอง หากมี Domain=example.com มันจะเดินทางไปยังพี่น้องทุกตัว และโดเมนย่อยใหม่ไม่ได้ให้อะไรกับคุณสำหรับคุกกี้นั้น
แยกการอ่านคำตอบออกจากการส่งคำขอ
นโยบายต้นกำเนิดเดียวกันจำกัดการอ่านคำตอบข้ามต้นกำเนิด มันไม่หยุดการส่งคำขอ และไม่ขัดขวางฟอร์มจากการพา creds ที่เบราว์เซอร์มีอยู่แล้ว คำขออย่างง่าย ที่มีชนิดเนื้อหาของฟอร์มหรือ GET ธรรมดา จะถูกส่งโดยไม่มีการตรวจล่วงหน้า จากนั้น CORS ตัดสินว่าสคริปต์ที่เรียกอ่านคำตอบได้หรือไม่ CSRF อาศัยอยู่ฝั่งการส่งทั้งหมด
นั่นคือเหตุผลที่เซิร์ฟเวอร์ต้องการการตรวจสอบชัดเจนสำหรับการดำเนินการที่เปลี่ยนสถานะ โทเค็นซิงโครไนซ์ที่ผูกกับเซสชัน หรือคุกกี้ส่งสองครั้งที่เปรียบเทียบบนเซิร์ฟเวอร์ ครอบคลุมกรณีนั้น การเปรียบเทียบ Origin หรือ Referer คุ้มค่าที่จะเพิ่มเป็นประตูที่สอง แต่ไม่ใช่ประตูเดียว เพราะไม่ใช่ทุกคำขอที่พาเฮดเดอร์นั้นและไม่ใช่ทุกพร็อกซี่ที่เก็บรักษามัน แนวทางของ OWASP ในการป้องกัน CSRF มอง SameSite เป็นชั้นหนึ่งในหลายชั้นด้วยเหตุผลนี้เอง
ตัดสินว่าประตูเครือข่ายพิสูจน์อะไรจริง
รายการอนุญาตทางออก VPN หน้าชื่อโฮสต์ผู้ดูแลเป็นการควบคุมที่ดีและการอ้างสิทธิ์ตัวตนที่อ่อนแอ มันพิสูจน์ว่าคำขอมาจากที่อยู่ที่ VPN แจก ซึ่งทุกคนบนทางออกนั้นอาจใช้ร่วมกัน และไม่พูดอะไรเกี่ยวกับว่าบุคคลหรืออุปกรณ์ใดอยู่ข้างหลัง มองมันเป็นตัวกรองทางเข้า ไม่ใช่การพิสูจน์ตัวตน
รักษามันให้เป็นอิสระจากการตรวจสอบระดับคำขอ หากรายการเป็นสิ่งเดียวระหว่างผู้โจมตีกับปลายทางที่เปลี่ยนสถานะ เส้นทางที่กำหนดค่าผิดหนึ่งเส้น ไคลเอนต์ split-tunnel หนึ่งตัว หรือแล็ปท็อปที่ยืมมาหนึ่งเครื่องก็ลบการควบคุมทั้งหมด
บันทึกการปฏิเสธจากนอกช่วงที่คาดด้วย การพุ่งขึ้นของมันคือสัญญาณที่มีประโยชน์ที่สุดว่ามีคนกำลังสำรวจขอบเขตที่คุณเพิ่งสร้าง และความเงียบคือสัญญาณว่าตัวกรองไม่ถูกเข้าถึงเลย
รักษาคุกกี้ การเข้าสู่ระบบ และการอนุญาตให้ชัดเจน
ขอบเขตของคุกกี้ตัดสินผลลัพธ์ส่วนใหญ่ คุกกี้ของโดเมนแม่ถูกส่งไปยังโฮสต์ผู้ดูแล ดังนั้นการแทรกสคริปต์บนไซต์สาธารณะจึงสามารถกระทำด้วยเซสชันของผู้ดูแลได้ คุกกี้เฉพาะโฮสต์ทำไม่ได้ ให้เลือกแบบเฉพาะโฮสต์ เพิ่มแอตทริบิวต์ Secure และใช้คำนำหน้า __Host- ในที่ที่แพลตฟอร์มรองรับ เพราะคำนำหน้านั้นต้องการ Secure, Path=/ และไม่มีแอตทริบิวต์ Domain อ่านเฮดเดอร์คำตอบไม่ใช่ขวดคุกกี้: Set-Cookie: __Host-admin_session=...; Secure; Path=/; HttpOnly; SameSite=Lax โดยไม่มีแอตทริบิวต์ Domain เบราว์เซอร์ทิ้งคุกกี้ __Host- ที่มี Domain ดังนั้นคุกกี้ที่ยังเห็นบนโฮสต์พี่น้องคือหลักฐานว่าคำนำหน้าไม่เคยถูกใช้
จากนั้นรักษาการอนุญาตบนเซิร์ฟเวอร์ สำหรับทุกคำขอ ที่ทุกปลายทางของผู้ดูแล ไม่ใช่แค่ตอนเข้าสู่ระบบ คำขอจากเครือข่ายที่อนุญาตยังต้องได้รับการพิสูจน์ตัวตนและได้รับอนุญาตสำหรับการดำเนินการที่ขอ ชื่อโฮสต์ไม่ใช่ผู้กระทำ หากแอปพลิเคชันสาธารณะและแอปพลิเคชันผู้ดูแลใช้กระบวนการเข้าสู่ระบบหรือที่เก็บเซสชันร่วมกัน จงเขียนความสัมพันธ์นั้นไว้ เพราะมันเป็นเส้นทางที่สั้นที่สุดจากบั๊กบนไซต์สาธารณะไปสู่การกระทำของผู้ดูแล
ตรวจสอบขอบเขตอีกครั้งหลังการแยก
รันการทดสอบเชิงลบ ไม่ใช่แค่เส้นทางที่มีความสุข: ฟอร์มข้ามไซต์ที่ไม่มีโทเค็นต้องถูกปฏิเสธ โทเค็นจากเซสชันอื่นต้องถูกปฏิเสธ และไม่มี GET ใดเปลี่ยนสถานะได้ ตรวจสอบแอตทริบิวต์คุกกี้ในเครื่องมือนักพัฒนา ยืนยันว่าการตรวจ Origin ทำงานเมื่อคำขอไม่ตรงกัน และลองโฮสต์ผู้ดูแลจากนอกช่วง VPN เพื่อดูตัวกรองทำงาน
ไม่มีสิ่งใดในนี้ขจัดข้อบกพร่อง XSS ภายในแอปพลิเคชันผู้ดูแลเอง ชื่อโฮสต์แยกเป็นขอบเขตการแยกฝั่งเบราว์เซอร์ที่มีคุณค่าจริง และมันไม่ใช่สิ่งทดแทนการป้องกันการรันโค้ดที่ไม่ปลอดภัยหรือการปกป้องคำขอฝั่งเซิร์ฟเวอร์ หลังการแยกรายการสั้นกว่าที่เห็น: ต้นกำเนิดต่าง คุกกี้เฉพาะโฮสต์ โทเค็นทุกการเปลี่ยนแปลง ตัวกรองทางเข้าที่คุณไม่ไว้ใจในฐานะตัวตน และการอนุญาตที่ตัดสินสำหรับทุกคำขอ