ทำไมการใส่โทเค็นการป้องกัน CSRF ลงในคุกกี้จึงเป็นเรื่องปกติ


284

ฉันพยายามเข้าใจปัญหาทั้งหมดด้วย CSRF และวิธีที่เหมาะสมในการป้องกัน (ทรัพยากรที่ฉันได้อ่านทำความเข้าใจและเห็นด้วยกับ: OWASP CSRF ป้องกันแผ่นโกง , คำถามเกี่ยวกับ CSRF .)

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

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

ตามคำถามของฉันซึ่งเกี่ยวกับวิธีการขนส่งเฉพาะที่ใช้สำหรับโทเค็น CSRF นั้นในการไปกลับนั้น

ดูเหมือนเป็นเรื่องธรรมดา (เช่นในAngularJS , Django , Rails ) เพื่อส่งโทเค็น CSRF จากเซิร์ฟเวอร์ไปยังไคลเอนต์เป็นคุกกี้ (เช่นในส่วนหัว Set-Cookie) จากนั้นให้ Javascript ในไคลเอนต์หลุดออกจากคุกกี้และแนบ เป็นส่วนหัว XSRF-TOKEN ที่แยกต่างหากเพื่อส่งกลับไปยังเซิร์ฟเวอร์

(วิธีอื่นเป็นวิธีที่แนะนำโดยเช่นExpressซึ่งโทเค็น CSRF ที่สร้างโดยเซิร์ฟเวอร์จะรวมอยู่ในเนื้อหาการตอบสนองผ่านการขยายเทมเพลตฝั่งเซิร์ฟเวอร์แนบโดยตรงกับโค้ด / มาร์กอัปที่จะส่งกลับไปยังเซิร์ฟเวอร์เช่น เป็นรูปแบบการป้อนข้อมูลที่ซ่อนอยู่ตัวอย่างนั้นเป็นอีกวิธีหนึ่งในการทำสิ่งต่าง ๆ บนเว็บ 1.0-ish แต่จะพูดคุยกับลูกค้า JS-heavy มากขึ้น)

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

ฉันตระหนักว่ากรอบการทำงานข้างต้นไม่ได้ใช้คุกกี้ตลอดการเดินทางไปสู่โทเค็น CSRF พวกเขาใช้ Set-Cookie ดาวน์สตรีมแล้วอย่างอื่น (เช่นส่วนหัว X-CSRF-Token) อัปสตรีมและสิ่งนี้จะปิดช่องโหว่ แต่ถึงกระนั้นการใช้ Set-Cookie เป็นการนำส่งข้อมูลแบบดาวน์สตรีมอาจทำให้เข้าใจผิดและเป็นอันตราย เบราว์เซอร์จะแนบโทเค็น CSRF กับทุกคำขอรวมถึงคำขอ XSRF ที่เป็นอันตรายของแท้ อย่างดีที่สุดที่ทำให้คำขอมีขนาดใหญ่เกินกว่าที่จะเป็นและที่เลวร้ายที่สุดมีความหมายดี แต่ชิ้นส่วนของรหัสเซิร์ฟเวอร์ที่เข้าใจผิดอาจลองใช้งานจริงซึ่งอาจจะแย่มาก และยิ่งไปกว่านั้นเนื่องจากผู้รับเป้าหมายที่แท้จริงของโทเค็น CSRF คือ Javascript ฝั่งไคลเอ็นต์นั่นหมายความว่าคุกกี้นี้ไม่สามารถป้องกันด้วย http เท่านั้น


มันเป็นคำถามที่ยอดเยี่ยมที่พูดถึงจุดที่ถูกต้อง
kta

คำตอบ:


263

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

พิจารณาสถานการณ์และกระบวนการต่อไปนี้ในแอปพลิเคชันทั่วไปสำหรับข้อดีข้อเสียของแต่ละวิธีที่คุณอธิบาย เหล่านี้จะขึ้นอยู่กับรูปแบบ Synchronizer Token

ขอวิธีร่างกาย

  1. ผู้ใช้เข้าสู่ระบบเรียบร้อยแล้ว
  2. เซิร์ฟเวอร์ออกคุกกี้รับรองความถูกต้อง
  3. ผู้ใช้คลิกเพื่อนำทางไปยังแบบฟอร์ม
  4. หากยังไม่ได้สร้างขึ้นสำหรับเซสชันนี้เซิร์ฟเวอร์จะสร้างโทเค็น CSRF เก็บไว้กับเซสชันผู้ใช้และส่งออกไปยังเขตข้อมูลที่ซ่อนอยู่
  5. ผู้ใช้ส่งแบบฟอร์ม
  6. เซิร์ฟเวอร์ตรวจสอบข้อมูลที่ซ่อนอยู่ตรงกับเซสชันที่เก็บโทเค็น

ข้อดี:

  • ใช้งานง่าย
  • ทำงานร่วมกับ AJAX
  • ทำงานร่วมกับรูปแบบ
  • คุกกี้สามารถจริงจะHTTP เท่านั้น

ข้อเสีย:

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

ส่วนหัว HTTP ที่กำหนดเอง (ดาวน์สตรีม)

  1. ผู้ใช้เข้าสู่ระบบเรียบร้อยแล้ว
  2. เซิร์ฟเวอร์ออกคุกกี้รับรองความถูกต้อง
  3. ผู้ใช้คลิกเพื่อนำทางไปยังแบบฟอร์ม
  4. เพจโหลดในเบราว์เซอร์จากนั้นจะทำการร้องขอ AJAX เพื่อดึงโทเค็น CSRF
  5. เซิร์ฟเวอร์สร้างโทเค็น CSRF (หากยังไม่ได้สร้างขึ้นสำหรับเซสชัน) เก็บไว้กับเซสชันผู้ใช้และส่งออกไปยังส่วนหัว
  6. ผู้ใช้ส่งแบบฟอร์ม (โทเค็นถูกส่งผ่านช่องที่ซ่อนอยู่)
  7. เซิร์ฟเวอร์ตรวจสอบข้อมูลที่ซ่อนอยู่ตรงกับเซสชันที่เก็บโทเค็น

ข้อดี:

  • ทำงานร่วมกับ AJAX
  • คุกกี้สามารถHTTP เท่านั้น

ข้อเสีย:

  • ไม่ทำงานหากไม่มีคำขอ AJAX เพื่อรับค่าส่วนหัว
  • แบบฟอร์มทั้งหมดต้องมีค่าเพิ่มใน HTML แบบไดนามิก
  • AJAX POST ใด ๆ จะต้องมีค่าด้วย
  • หน้านั้นจะต้องทำการร้องขอ AJAX ก่อนจึงจะได้รับโทเค็น CSRF ดังนั้นมันจะหมายถึงการเดินทางไปกลับพิเศษในแต่ละครั้ง
  • อาจมีเพียงแค่ส่งโทเค็นไปยังหน้าซึ่งจะบันทึกคำขอพิเศษ

ส่วนหัว HTTP ที่กำหนดเอง (อัปสตรีม)

  1. ผู้ใช้เข้าสู่ระบบเรียบร้อยแล้ว
  2. เซิร์ฟเวอร์ออกคุกกี้รับรองความถูกต้อง
  3. ผู้ใช้คลิกเพื่อนำทางไปยังแบบฟอร์ม
  4. หากยังไม่ได้สร้างขึ้นสำหรับเซสชันนี้เซิร์ฟเวอร์จะสร้างโทเค็น CSRF เก็บไว้กับเซสชันของผู้ใช้และส่งออกในเนื้อหาของหน้าบางแห่ง
  5. ผู้ใช้ส่งแบบฟอร์มผ่าน AJAX (โทเค็นถูกส่งผ่านส่วนหัว)
  6. เซิร์ฟเวอร์ตรวจสอบส่วนหัวที่กำหนดเองตรงกับเซสชันที่เก็บโทเค็น

ข้อดี:

  • ทำงานร่วมกับ AJAX
  • คุกกี้สามารถHTTP เท่านั้น

ข้อเสีย:

  • ไม่ทำงานกับแบบฟอร์ม
  • AJAX POST ทั้งหมดจะต้องมีส่วนหัว

ส่วนหัว HTTP ที่กำหนดเอง (upstream & downstream)

  1. ผู้ใช้เข้าสู่ระบบเรียบร้อยแล้ว
  2. เซิร์ฟเวอร์ออกคุกกี้รับรองความถูกต้อง
  3. ผู้ใช้คลิกเพื่อนำทางไปยังแบบฟอร์ม
  4. เพจโหลดในเบราว์เซอร์จากนั้นจะทำการร้องขอ AJAX เพื่อดึงโทเค็น CSRF
  5. เซิร์ฟเวอร์สร้างโทเค็น CSRF (หากยังไม่ได้สร้างขึ้นสำหรับเซสชัน) เก็บไว้กับเซสชันผู้ใช้และส่งออกไปยังส่วนหัว
  6. ผู้ใช้ส่งแบบฟอร์มผ่าน AJAX (โทเค็นถูกส่งผ่านส่วนหัว)
  7. เซิร์ฟเวอร์ตรวจสอบส่วนหัวที่กำหนดเองตรงกับเซสชันที่เก็บโทเค็น

ข้อดี:

  • ทำงานร่วมกับ AJAX
  • คุกกี้สามารถHTTP เท่านั้น

ข้อเสีย:

  • ไม่ทำงานกับแบบฟอร์ม
  • AJAX POST ทั้งหมดต้องมีค่าด้วย
  • หน้าจะต้องทำการร้องขอ AJAX ก่อนเพื่อรับโทเค็น CRSF ดังนั้นมันจะหมายถึงการเดินทางไปกลับพิเศษในแต่ละครั้ง

คุกกี้ชุด

  1. ผู้ใช้เข้าสู่ระบบเรียบร้อยแล้ว
  2. เซิร์ฟเวอร์ออกคุกกี้รับรองความถูกต้อง
  3. ผู้ใช้คลิกเพื่อนำทางไปยังแบบฟอร์ม
  4. เซิร์ฟเวอร์สร้างโทเค็น CSRF จัดเก็บกับเซสชันผู้ใช้และส่งออกไปยังคุกกี้
  5. ผู้ใช้ส่งแบบฟอร์มผ่าน AJAX หรือผ่านทางแบบฟอร์ม HTML
  6. เซิร์ฟเวอร์ตรวจสอบส่วนหัวที่กำหนดเอง (หรือเขตข้อมูลฟอร์มที่ซ่อนอยู่) ตรงกับโทเค็นของเซสชันที่เก็บไว้
  7. คุกกี้มีอยู่ในเบราว์เซอร์สำหรับใช้ใน AJAX เพิ่มเติมและคำขอแบบฟอร์มโดยไม่มีการร้องขอเพิ่มเติมไปยังเซิร์ฟเวอร์เพื่อดึงโทเค็น CSRF

ข้อดี:

  • ใช้งานง่าย
  • ทำงานร่วมกับ AJAX
  • ทำงานร่วมกับรูปแบบ
  • ไม่จำเป็นต้องมีคำขอ AJAX เพื่อรับค่าคุกกี้ คำร้องขอ HTTP ใด ๆ สามารถเรียกคืนได้และสามารถผนวกเข้ากับฟอร์ม / AJAX ทั้งหมดผ่านทาง JavaScript
  • เมื่อเรียกโทเค็น CSRF แล้วจะถูกเก็บไว้ในคุกกี้ค่าสามารถนำกลับมาใช้ใหม่ได้โดยไม่ต้องมีการร้องขอเพิ่มเติม

ข้อเสีย:

  • แบบฟอร์มทั้งหมดต้องมีค่าเพิ่มใน HTML แบบไดนามิก
  • AJAX POST ใด ๆ จะต้องมีค่าด้วย
  • คุกกี้จะถูกส่งไปสำหรับทุกคำขอ (เช่น GETs ทั้งหมดสำหรับรูปภาพ, CSS, JS, ฯลฯ ที่ไม่เกี่ยวข้องกับกระบวนการ CSRF) เพิ่มขนาดคำขอ
  • คุกกี้ไม่สามารถHTTP เท่านั้น

ดังนั้นวิธีการของคุกกี้จึงเป็นวิธีที่ค่อนข้างพลวัตเสนอวิธีที่ง่ายในการเรียกคืนค่าคุกกี้ (คำขอ HTTP ใด ๆ ) และใช้ (JS สามารถเพิ่มมูลค่าให้กับฟอร์มใด ๆ โดยอัตโนมัติและสามารถใช้ในคำขอ AJAX ไม่ว่าจะเป็นส่วนหัวหรือเป็น ค่าแบบฟอร์ม) เมื่อได้รับโทเค็น CSRF สำหรับเซสชันแล้วไม่จำเป็นต้องสร้างใหม่ในฐานะผู้โจมตีที่ใช้ประโยชน์จาก CSRF ไม่มีวิธีเรียกโทเค็นนี้ ถ้าเป็นอันตรายพยายามใช้การอ่าน CSRF ของผู้ใช้โทเค็นในใด ๆ ของวิธีการดังกล่าวแล้วนี้จะได้รับการป้องกันโดยเดียวกันนโยบายแหล่งกำเนิดสินค้า หากผู้ใช้ที่เป็นอันตรายพยายามที่จะดึงด้านโทเค็นเซิร์ฟเวอร์ CSRF (เช่นผ่านcurl) จากนั้นโทเค็นนี้จะไม่เชื่อมโยงกับบัญชีผู้ใช้เดียวกันกับคุกกี้เซสชั่นรับรองความถูกต้องของเหยื่อจะหายไปจากคำขอ (จะเป็นผู้โจมตี - ดังนั้นจะไม่เชื่อมโยงฝั่งเซิร์ฟเวอร์กับเซสชันของเหยื่อ)

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


7
ฉันไม่แน่ใจว่าฉันเข้าใจว่า "คำขอ AJAX ถูกทำขึ้นเพื่อดึงโทเค็น CSRF" (ขั้นตอนที่ 4 ในทั้ง "ส่วนหัวที่กำหนดเอง: ส่วนปลายน้ำ") สามารถทำได้อย่างปลอดภัย เนื่องจากนี่เป็นคำขอแยกต่างหากเซิร์ฟเวอร์จึงไม่ทราบว่ามาจากใคร จะทราบได้อย่างไรว่าปลอดภัยที่จะเปิดเผยโทเค็น CSRF ดูเหมือนว่าฉันถ้าคุณไม่สามารถรับโทเค็นจากการโหลดหน้าเริ่มต้นคุณจะสูญเสีย (ซึ่งทำให้ส่วนหัวการตอบสนองแบบดาวน์สตรีมแบบกำหนดเองไม่ใช่แบบสตาร์ตน่าเสียดาย)
metamatt

6
เนื่องจากผู้ปลอมจะไม่มีคุกกี้เซสชัน พวกเขาอาจมีคุกกี้เซสชันของตัวเอง แต่เนื่องจากโทเค็น CSRF เชื่อมโยงกับเซสชันโทเค็น CSRF ของพวกเขาจะไม่ตรงกับของเหยื่อ
SilverlightFox

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

8
พวกเขามีความสามารถในการจัดหาคุกกี้รับรองความถูกต้อง แต่พวกเขาไม่สามารถอ่านการตอบสนองที่มีโทเค็น CSRF
SilverlightFox

8
@metamatt ขออภัยสำหรับ necro แต่ฉันจะทำเพื่อคนที่หลงทางในความเข้าใจของฉันผู้โจมตีมักไม่สามารถเข้าถึงการตอบสนองได้ CSRF ใช้เป็นหลักในการทำให้เกิดผลข้างเคียงมากกว่าการรวบรวมข้อมูลโดยตรง ตัวอย่างเช่นสคริปต์โจมตีของ CSRF อาจบังคับให้ผู้ใช้ที่ได้รับสิทธิให้เลื่อนระดับสิทธิ์ของผู้โจมตีปิดการใช้งานการตั้งค่าความปลอดภัยหรือบังคับให้ผู้ใช้ paypal ลงชื่อเข้าใช้เพื่อส่งการถ่ายโอนไปยังที่อยู่อีเมลเฉพาะ ในกรณีเหล่านี้ผู้โจมตีไม่สนใจเกี่ยวกับการตอบสนองซึ่งยังคงถูกส่งไปยังเบราว์เซอร์ของเหยื่อ เฉพาะผลลัพธ์ของการโจมตี
jonathanbruder

61

การใช้คุกกี้เพื่อจัดทำโทเค็น CSRF ให้กับลูกค้าไม่อนุญาตให้มีการโจมตีที่ประสบความสำเร็จเนื่องจากผู้โจมตีไม่สามารถอ่านค่าของคุกกี้ได้

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

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


แน่นอนว่าผู้โจมตีไม่จำเป็นต้องอ่านคุกกี้ตั้งแต่แรก พวกเขาสามารถแทรกรูปภาพบนไซต์ที่แฮ็กsrc='bank.com/transfer?to=hacker&amount=1000ซึ่งเบราว์เซอร์จะร้องขอพร้อมด้วยคุกกี้ที่เกี่ยวข้องสำหรับไซต์นั้น ( bank.com)
developius

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

2
@developius การส่งคุกกี้ไม่เพียงพอสำหรับการปกป้อง CSRF คุกกี้มีโทเค็น csrf ตามที่ส่งโดยเซิร์ฟเวอร์ ลูกค้าที่ถูกกฎหมายจะต้องอ่านโทเค็น csrf จากคุกกี้จากนั้นส่งผ่านไปยังคำขอบางแห่งเช่นส่วนหัวหรือในส่วนของข้อมูล การป้องกัน CSRF ตรวจสอบว่าค่าในคุกกี้ตรงกับค่าในคำขอไม่เช่นนั้นคำขอจะถูกปฏิเสธ ดังนั้นผู้โจมตีจึงจำเป็นต้องอ่านคุกกี้
Will M.

1
คำตอบนี้ตรงประเด็นกับคำถามต้นฉบับของโปสเตอร์และชัดเจนมาก +1 ขอบคุณ
java-addict301

@ ตงฟ่า - ขอบคุณสิ่งนี้ช่วยให้ฉันเข้าใจได้ดีขึ้น ฉันถูกต้องหรือไม่ที่จะถือว่า CSRF Token ไม่ควรอยู่ในส่วนหัว? มันจะต้องอยู่ที่ไหนสักแห่งในร่างกาย?
zerohedge

10

ที่ดีที่สุดของฉันเดาคำตอบ: พิจารณาตัวเลือกเหล่านี้ 3 วิธีรับโทเค็น CSRF ลงจากเซิร์ฟเวอร์เบราว์เซอร์

  1. ในส่วนคำขอ (ไม่ใช่ส่วนหัว HTTP)
  2. ในส่วนหัว HTTP ที่กำหนดเองไม่ใช่ Set-Cookie
  3. เป็นคุกกี้ในส่วนหัว Set-Cookie

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

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

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


7
ฉันอาจระบุชัดเจนว่านี่หมายความว่าคุกกี้ไม่สามารถแก้ไขได้อย่างถูกต้องหรือไม่
โฟตอน

1
สำหรับคำร้องขอ ajax เท่านั้น (โดยที่ JS ต้องการทราบค่าของ csrf cookie เพื่อส่งคำร้องขอครั้งถัดไปในช่องที่สอง (เป็นข้อมูลแบบฟอร์มหรือส่วนหัว) ไม่มีเหตุผลที่จะต้องใช้โทเค็น csrf เป็น HttpOnly หากคุกกี้เซสชันนั้น HttpOnly (เพื่อป้องกัน XSS) อยู่แล้วเนื่องจากโทเค็น csrf ไม่ได้มีค่าด้วยตัวเองโดยไม่มีเซสชันที่เกี่ยวข้อง
cowbert

2

นอกจากคุกกี้เซสชัน (ซึ่งเป็นมาตรฐาน) ฉันไม่ต้องการใช้คุกกี้พิเศษ

ฉันพบโซลูชันที่เหมาะกับฉันเมื่อสร้าง Single Page Web Application (SPA) พร้อมคำขอ AJAX จำนวนมาก หมายเหตุ: ฉันกำลังใช้ Java ฝั่งเซิร์ฟเวอร์และ JQuery ฝั่งไคลเอ็นต์ แต่ไม่มีสิ่งมหัศจรรย์ดังนั้นฉันคิดว่าหลักการนี้สามารถนำไปใช้กับภาษาการเขียนโปรแกรมยอดนิยมทั้งหมดได้

โซลูชันของฉันที่ไม่มีคุกกี้พิเศษนั้นง่ายมาก:

ด้านลูกค้า

เก็บโทเค็น CSRF ซึ่งส่งคืนโดยเซิร์ฟเวอร์หลังจากเข้าสู่ระบบที่ประสบความสำเร็จในตัวแปรทั่วโลก (ถ้าคุณต้องการใช้ที่เก็บข้อมูลบนเว็บแทนการใช้งานโกลบอล สั่งให้ JQuery จัดหาส่วนหัว X-CSRF-TOKEN ในการโทร AJAX แต่ละครั้ง

หน้า "ดัชนี" หลักมีข้อมูลโค้ด JavaScript นี้:

// Intialize global variable CSRF_TOKEN to empty sting. 
// This variable is set after a succesful login
window.CSRF_TOKEN = '';

// the supplied callback to .ajaxSend() is called before an Ajax request is sent
$( document ).ajaxSend( function( event, jqXHR ) {
    jqXHR.setRequestHeader('X-CSRF-TOKEN', window.CSRF_TOKEN);
}); 

ฝั่งเซิร์ฟเวอร์

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

การเรียก AJAX ที่ละเอียดอ่อน (POST form-data และ GET JSON-data) และตัวกรองฝั่งเซิร์ฟเวอร์ที่จับพวกมันอยู่ภายใต้พา ธ / dataservice / * คำขอเข้าสู่ระบบจะต้องไม่ไปที่ตัวกรองดังนั้นสิ่งเหล่านี้จึงอยู่ในเส้นทางอื่น การร้องขอทรัพยากร HTML, CSS, JS และอิมเมจนั้นไม่ได้อยู่บนพา ธ / dataservice / * ดังนั้นจึงไม่ถูกกรอง สิ่งเหล่านี้ไม่มีความลับและไม่สามารถทำอันตรายได้ดังนั้นนี่เป็นเรื่องปกติ

@WebFilter(urlPatterns = {"/dataservice/*"})
...
String sessionCSRFToken = req.getSession().getAttribute("CSRFToken") != null ? (String) req.getSession().getAttribute("CSRFToken") : null;
if (sessionCSRFToken == null || req.getHeader("X-CSRF-TOKEN") == null || !req.getHeader("X-CSRF-TOKEN").equals(sessionCSRFToken)) {
    resp.sendError(401);
} else
    chain.doFilter(request, response);
}   

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