เรากำลังเปิดเผย API ที่พันธมิตรสามารถใช้ได้เฉพาะกับโดเมนที่พวกเขาได้ลงทะเบียนกับเรา เนื้อหาบางส่วนเป็นแบบสาธารณะ (แต่ควรแสดงเฉพาะในโดเมนที่เรารู้จัก) แต่ส่วนใหญ่เป็นแบบส่วนตัวสำหรับผู้ใช้ของเรา ดังนั้น:
ในการตรวจสอบสิ่งที่แสดงผู้ใช้ของเราต้องเข้าสู่ระบบกับเรา แต่จะได้รับการจัดการแยกต่างหาก
เพื่อตรวจสอบที่ข้อมูลจะถูกแสดงคีย์ประชาชน API จะใช้ในการ จำกัด การเข้าถึงโดเมนที่เรารู้และเหนือสิ่งอื่นเพื่อให้แน่ใจว่าข้อมูลส่วนตัวของผู้ใช้ไม่ได้เป็นความเสี่ยงที่จะCSRF
ทุกคนสามารถมองเห็นคีย์ API นี้ได้เราไม่ได้รับรองความถูกต้องของคู่ค้าของเราด้วยวิธีอื่นใดและเราไม่ต้องการผู้อ้างอิง ถึงกระนั้นก็ปลอดภัย:
เมื่อเราget-csrf-token.js?apiKey=abc123
ถูกร้องขอ:
ค้นหาคีย์abc123
ในฐานข้อมูลและรับรายการโดเมนที่ถูกต้องสำหรับคีย์นั้น
มองหาคุกกี้การตรวจสอบความถูกต้อง CSRF หากไม่มีอยู่ให้สร้างค่าสุ่มที่ปลอดภัยและใส่ไว้ในคุกกี้เซสชันHTTP เท่านั้น หากมีคุกกี้อยู่ให้รับค่าสุ่มที่มีอยู่
สร้าง CSRF โทเค็นจากคีย์ API และมูลค่าการสุ่มจากคุกกี้และลงนาม (แทนที่จะเก็บรายการโทเค็นไว้บนเซิร์ฟเวอร์เรากำลังเซ็นชื่อค่าทั้งสองค่าจะอ่านได้ในโทเค็นที่เซ็นชื่อไม่เป็นไร)
ตั้งค่าการตอบกลับไม่ให้แคชเพิ่มคุกกี้และส่งคืนสคริปต์เช่น:
var apiConfig = apiConfig || {};
if(document.domain === 'expected-domain.com'
|| document.domain === 'www.expected-domain.com') {
apiConfig.csrfToken = 'API key, random value, signature';
if(typeof apiConfig.fnInit !== 'undefined') {
apiConfig.fnInit();
}
} else {
alert('This site is not authorised for this API key.');
}
หมายเหตุ:
ดังกล่าวข้างต้นไม่ได้ป้องกันสคริปต์ฝั่งเซิร์ฟเวอร์จากแกล้งขอ แต่เพียงเพื่อให้แน่ใจว่าตรงกับโดเมนถ้าการร้องขอจากเบราว์เซอร์
เดียวกันต้นทางนโยบายสำหรับ JavaScriptเพื่อให้แน่ใจว่าเบราว์เซอร์ไม่สามารถใช้ XHR (อาแจ็กซ์) ในการโหลดและจากนั้นตรวจสอบแหล่งที่มาของ JavaScript แต่เบราว์เซอร์ทั่วไปสามารถโหลดได้โดยใช้<script src="https://our-api.com/get-csrf-token.js?apiKey=abc123">
(หรือเทียบเท่าแบบไดนามิก) จากนั้นจะเรียกใช้โค้ด แน่นอนว่าเซิร์ฟเวอร์ของคุณไม่ควรรองรับCross-Origin Resource Sharingหรือ JSONP สำหรับ JavaScript ที่สร้างขึ้น
สคริปต์ของเบราว์เซอร์สามารถเปลี่ยนค่าของdocument.domain
ก่อนโหลดสคริปต์ด้านบน แต่นโยบายกำเนิดเดียวกันเพียง แต่ช่วยให้การตัดทอนโดเมนโดยการเอาคำนำหน้าเช่นการเขียนใหม่subdomain.example.com
เพียงexample.com
หรือmyblog.wordpress.com
ไปwordpress.com
หรือในเบราว์เซอร์บางคนไปbbc.co.uk
co.uk
หากไฟล์ JavaScript ถูกดึงโดยใช้สคริปต์ฝั่งเซิร์ฟเวอร์เซิร์ฟเวอร์จะได้รับคุกกี้ด้วย อย่างไรก็ตามเซิร์ฟเวอร์ของบุคคลที่สามไม่สามารถทำให้เบราว์เซอร์ของผู้ใช้เชื่อมโยงคุกกี้นั้นกับโดเมนของเราได้ ดังนั้นโทเค็น CSRF และคุกกี้การตรวจสอบความถูกต้องที่ดึงมาโดยใช้สคริปต์ฝั่งเซิร์ฟเวอร์สามารถใช้ได้โดยการเรียกฝั่งเซิร์ฟเวอร์ที่ตามมาเท่านั้นไม่ใช่ในเบราว์เซอร์ อย่างไรก็ตามการเรียกฝั่งเซิร์ฟเวอร์ดังกล่าวจะไม่รวมคุกกี้ของผู้ใช้และด้วยเหตุนี้จึงสามารถดึงข้อมูลสาธารณะได้เท่านั้น นี่เป็นข้อมูลเดียวกับที่สคริปต์ฝั่งเซิร์ฟเวอร์สามารถดึงมาจากเว็บไซต์ของพันธมิตรได้โดยตรง
เมื่อผู้ใช้เข้าสู่ระบบให้ตั้งค่าคุกกี้ของผู้ใช้ตามที่คุณต้องการ (ผู้ใช้อาจลงชื่อเข้าใช้ก่อนที่จะมีการร้องขอ JavaScript)
คำขอ API ที่ตามมาทั้งหมดไปยังเซิร์ฟเวอร์ (รวมถึงคำขอ GET และ JSONP) ต้องมีโทเค็น CSRF คุกกี้ตรวจสอบความถูกต้อง CSRF และคุกกี้ผู้ใช้ (หากล็อกออน) ขณะนี้เซิร์ฟเวอร์สามารถระบุได้ว่าคำขอนั้นเชื่อถือได้หรือไม่:
การมีโทเค็น CSRF ที่ถูกต้องช่วยให้มั่นใจได้ว่า JavaScript ถูกโหลดจากโดเมนที่คาดหวังหากเบราว์เซอร์โหลด
การมีโทเค็น CSRF โดยไม่มีคุกกี้ตรวจสอบแสดงว่ามีการปลอมแปลง
การมีอยู่ของทั้งโทเค็น CSRF และคุกกี้การตรวจสอบความถูกต้องของ CSRF ไม่ทำให้มั่นใจได้ว่าสิ่งใดอาจเป็นคำขอฝั่งเซิร์ฟเวอร์ที่ปลอมแปลงหรือคำขอที่ถูกต้องจากเบราว์เซอร์ (ไม่สามารถเป็นคำขอจากเบราว์เซอร์ที่สร้างจากโดเมนที่ไม่รองรับ)
การมีอยู่ของคุกกี้ผู้ใช้ทำให้แน่ใจว่าผู้ใช้เข้าสู่ระบบ แต่ไม่แน่ใจว่าผู้ใช้เป็นสมาชิกของพันธมิตรที่กำหนดหรือผู้ใช้กำลังดูเว็บไซต์ที่ถูกต้อง
การมีคุกกี้ของผู้ใช้โดยไม่มีคุกกี้ตรวจสอบความถูกต้อง CSRF บ่งชี้ว่ามีการปลอมแปลง
การมีอยู่ของคุกกี้ของผู้ใช้ช่วยให้มั่นใจได้ว่าคำขอปัจจุบันทำผ่านเบราว์เซอร์ (สมมติว่าผู้ใช้จะไม่ได้ป้อนข้อมูลประจำตัวของพวกเขาในเว็บไซต์ที่ไม่รู้จักและสมมติว่าเราไม่ดูแลเกี่ยวกับผู้ใช้โดยใช้ข้อมูลประจำตัวของตัวเองที่จะทำให้คำขอฝั่งเซิร์ฟเวอร์บาง.) หากเรายังมีการตรวจสอบคุกกี้ CSRF แล้วว่าคุกกี้ตรวจสอบ CSRF เป็น ยังได้รับโดยใช้เบราว์เซอร์ ต่อไปถ้าเรายังมี CSRF โทเค็นด้วยลายเซ็นที่ถูกต้องและหมายเลขสุ่มในคุกกี้ตรวจสอบความถูกต้อง CSRF ตรงกับหมายเลขในโทเค็น CSRF นั้นจากนั้น JavaScript สำหรับโทเค็นนั้นจะได้รับในระหว่างการร้องขอก่อนหน้านี้ที่เหมือนกันมากในระหว่างที่มีการตั้งค่าคุกกี้ CSRF ดังนั้นจึงใช้เบราว์เซอร์ด้วย จากนั้นหมายความว่าโค้ด JavaScript ด้านบนถูกเรียกใช้ก่อนที่จะมีการตั้งค่าโทเค็นและในเวลานั้นโดเมนนั้นถูกต้องสำหรับคีย์ API ที่กำหนด
ดังนั้น: ตอนนี้เซิร์ฟเวอร์สามารถใช้คีย์ API จากโทเค็นที่ลงชื่อได้อย่างปลอดภัย
หาก ณ จุดใดเซิร์ฟเวอร์ไม่เชื่อถือคำขอ 403 Forbidden จะถูกส่งกลับ วิดเจ็ตสามารถตอบสนองต่อสิ่งนั้นได้โดยแสดงคำเตือนต่อผู้ใช้
ไม่จำเป็นต้องลงนามในคุกกี้การตรวจสอบความถูกต้อง CSRF เนื่องจากเรากำลังเปรียบเทียบกับโทเค็น CSRF ที่ลงนามแล้ว การไม่ลงนามในคุกกี้จะทำให้คำขอ HTTP แต่ละรายการสั้นลงและการตรวจสอบความถูกต้องของเซิร์ฟเวอร์เร็วขึ้นเล็กน้อย
โทเค็น CSRF ที่สร้างขึ้นจะใช้ได้อย่างไม่มีกำหนด แต่จะใช้ร่วมกับคุกกี้ตรวจสอบความถูกต้องเท่านั้นจึงจะมีประสิทธิภาพจนกว่าจะปิดเบราว์เซอร์
เราสามารถ จำกัด อายุการใช้งานของลายเซ็นของโทเค็นได้ เราสามารถลบคุกกี้ตรวจสอบ CSRF เมื่อผู้ใช้ล็อกออกมาเพื่อตอบสนองข้อเสนอแนะ OWASP และเพื่อไม่แบ่งปันหมายเลขสุ่มต่อผู้ใช้ระหว่างคู่ค้าหลายรายสามารถเพิ่มคีย์ API ให้กับชื่อคุกกี้ได้ แต่ถึงอย่างนั้นก็ไม่สามารถรีเฟรชคุกกี้ตรวจสอบความถูกต้อง CSRF ได้อย่างง่ายดายเมื่อมีการร้องขอโทเค็นใหม่เนื่องจากผู้ใช้อาจเรียกดูไซต์เดียวกันในหลายหน้าต่างแชร์คุกกี้เดียว (ซึ่งเมื่อรีเฟรชจะได้รับการอัปเดตในทุกหน้าต่างหลังจากนั้น โทเค็น JavaScript ในหน้าต่างอื่นจะไม่ตรงกับคุกกี้เดียวอีกต่อไป)
สำหรับผู้ที่ใช้ OAuth โปรดดูOAuth และ Client-Side Widgetsด้วยซึ่งฉันได้แนวคิดเกี่ยวกับ JavaScript สำหรับการใช้ API ฝั่งเซิร์ฟเวอร์ซึ่งเราไม่สามารถพึ่งพาโค้ด JavaScript เพื่อ จำกัด โดเมนได้เรากำลังใช้คีย์ลับแทนคีย์ API สาธารณะ