จะเก็บ JWT ในเบราว์เซอร์ได้ที่ไหน จะป้องกัน CSRF ได้อย่างไร


159

ฉันรู้ว่าการตรวจสอบตามคุกกี้ สามารถใช้การตั้งค่า SSL และ HttpOnly เพื่อป้องกันการตรวจสอบตามคุกกี้จาก MITM และ XSS อย่างไรก็ตามจำเป็นต้องใช้มาตรการพิเศษเพิ่มเติมเพื่อป้องกันจาก CSRF พวกมันซับซ้อนเล็กน้อย ( อ้างอิง )

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

  1. หาก JWT ถูกเก็บไว้ในคุกกี้ฉันคิดว่าเป็นเช่นเดียวกับการรับรองความถูกต้องที่อิงกับคุกกี้ยกเว้นว่าเซิร์ฟเวอร์ไม่จำเป็นต้องมีเซสชันเพื่อตรวจสอบคุกกี้ / โทเค็น ยังมีความเสี่ยงเกี่ยวกับ CSRF หากไม่มีมาตรการพิเศษดำเนินการ JWT ไม่ถูกจัดเก็บในคุกกี้หรือไม่?

  2. หาก JWT ถูกเก็บไว้ใน localStorage / sessionStorage ดังนั้นไม่จำเป็นต้องป้องกันคุกกี้จาก CRSF คำถามคือวิธีการส่ง JWT ไปยังเซิร์ฟเวอร์ ฉันพบที่นี่แนะนำให้ใช้ jQuery เพื่อส่ง JWT โดยส่วนหัว HTTP ของคำขอ ajax ดังนั้นเฉพาะคำขอ ajax เท่านั้นที่สามารถทำการตรวจสอบได้

  3. นอกจากนี้ฉันพบบล็อกอีกหนึ่งรายการเพื่อใช้ "ส่วนหัวการอนุญาต" และ "ผู้ถือ" เพื่อส่ง JWT ฉันไม่เข้าใจวิธีการที่บล็อกพูดถึง ใครช่วยอธิบายเพิ่มเติมเกี่ยวกับ "ส่วนหัวการอนุญาต" และ "ผู้ถือ" สิ่งนี้ทำให้ JWT ส่งโดยส่วนหัว HTTP ของคำขอทั้งหมดหรือไม่ ถ้าใช่แล้ว CSRF เป็นอย่างไร

คำตอบ:


70

ราชสกุล JWT เป็นที่นิยมเนื่องจากพวกเขาจะนำมาใช้เป็นรูปแบบโทเค็นการเริ่มต้นในการอนุมัติและการตรวจสอบใหม่โปรโตคอลเช่นOAuth 2.0และOpenID Connect

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

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

แบบแผนผู้ถือมักใช้เพื่อปกป้องเว็บ API (บริการ REST) ​​ที่ใช้ผ่านการโทร AJAX หรือจากไคลเอนต์มือถือ


1
@ Timespace7 ไม่โทเค็น JWT ก็มักจะใช้จากไคลเอนต์ดั้งเดิม OAuth 2.0 มีโฟลว์ที่กำหนดเป้าหมายเฉพาะลูกค้า (มือถือ) โดยเฉพาะ สิ่งที่พวกเขาไม่ทำคือการรับรองความถูกต้องของเบราว์เซอร์โดยนัย (เช่นคุกกี้หรือการตรวจสอบขั้นพื้นฐาน)
MvdD

5
ฉันกำลังบอกว่าถ้า API ของคุณดึงโทเค็น JWT จากส่วนหัวการอนุญาตเท่านั้นก็จะไม่เสี่ยงต่อ CSRF ไซต์หรือ API ใด ๆ ที่ได้รับโทเค็นจากคุกกี้ต้องมีการลด CSRF
MvdD

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

10
@cameronjroe คุณสามารถเก็บไว้ในคุกกี้ของคุณ แต่ถ้าคุณไม่ได้ใช้คุกกี้ของคุณสำหรับการตรวจสอบ (คุณใช้ส่วนหัวของคุณในกรณีนี้)
แจค

1
การโทร AJAX ยังมาจากเบราว์เซอร์ โทเค็น JWT ส่วนใหญ่จะใช้ในการตรวจสอบสิทธิ์ API ของเว็บ (แสดงข้อมูล) และคุกกี้ที่ใช้ในการตรวจสอบสิทธิ์แอปพลิเคชันเว็บ (ให้บริการมาร์กอัป, รูปภาพ, CSS และ JavaScript)
MvdD

144

เราจำเป็นต้องจัดเก็บ JWT ไว้ในคอมพิวเตอร์ไคลเอนต์ หากเราเก็บไว้ใน LocalStorage / SessionStorage มันสามารถถูกโจมตีได้อย่างง่ายดายด้วยการโจมตี XSS หากเราเก็บไว้ในคุกกี้แฮ็กเกอร์สามารถใช้งานได้ (โดยไม่ต้องอ่าน) ในการโจมตี CSRF และปลอมตัวเป็นผู้ใช้และติดต่อ API ของเราและส่งคำขอเพื่อดำเนินการหรือรับข้อมูลในนามของผู้ใช้

แต่มีหลายวิธีในการรักษาความปลอดภัย JWT ในคุกกี้เพื่อไม่ให้ถูกขโมยได้ง่าย (แต่ยังมีเทคนิคขั้นสูงบางอย่างในการขโมย) แต่ถ้าคุณต้องการพึ่ง LocalStorage / SessionStorage คุณสามารถเข้าถึง XSS ได้ง่ายๆ

ดังนั้นเพื่อแก้ปัญหา CSRF ฉันใช้ Double ส่งคุกกี้ในแอปพลิเคชันของฉัน

วิธีส่งคุกกี้สองครั้ง

  1. เก็บ JWT ในคุกกี้ HttpOnly และใช้ในโหมดปลอดภัยเพื่อถ่ายโอนผ่าน HTTPS

  2. การโจมตี CSRF ส่วนใหญ่มีต้นกำเนิดหรือส่วนหัวผู้อ้างอิงที่แตกต่างกับโฮสต์ดั้งเดิมของคุณในคำขอของพวกเขา ดังนั้นตรวจสอบว่าคุณมีส่วนใดส่วนหนึ่งในส่วนหัวหรือไม่พวกเขามาจากโดเมนของคุณหรือไม่! ถ้าไม่ปฏิเสธพวกเขา หากทั้งแหล่งกำเนิดและผู้อ้างอิงไม่สามารถใช้ได้ในคำขอก็ไม่ต้องกังวล คุณสามารถพึ่งพาผลลัพธ์ของการตรวจสอบความถูกต้องของส่วนหัว X-XSRF-TOKEN ซึ่งฉันได้อธิบายไว้ในขั้นตอนถัดไป

  3. ในขณะที่เบราว์เซอร์จะจัดหาคุกกี้ของคุณโดยอัตโนมัติสำหรับโดเมนของคำขอนั้นมีข้อ จำกัด ที่มีประโยชน์: รหัส JavaScript ที่ทำงานบนเว็บไซต์ไม่สามารถอ่านคุกกี้ของเว็บไซต์อื่น ๆ ได้ เราสามารถใช้ประโยชน์จากสิ่งนี้เพื่อสร้างโซลูชัน CSRF ของเรา เพื่อป้องกันการโจมตีของ CSRF เราต้องสร้างคุกกี้ Javascript ที่อ่านได้พิเศษซึ่งเรียกว่า: XSRF-TOKEN คุกกี้นี้จะต้องสร้างขึ้นเมื่อผู้ใช้เข้าสู่ระบบและควรมีสตริงสุ่มและไม่สามารถคาดเดาได้ นอกจากนี้เรายังบันทึกหมายเลขนี้ใน JWT เองเพื่อเป็นการอ้างสิทธิ์ส่วนตัว ทุกครั้งที่แอปพลิเคชัน JavaScript ต้องการที่จะขอมันจะต้องอ่านโทเค็นนี้และส่งไปในส่วนหัว HTTP ที่กำหนดเอง เนื่องจากการดำเนินการเหล่านี้ (อ่านคุกกี้การตั้งค่าส่วนหัว) สามารถทำได้ในโดเมนเดียวกันของแอปพลิเคชัน JavaScript เท่านั้น

Angular JS ทำให้ชีวิตของคุณง่ายขึ้น

โชคดีที่ฉันใช้ Angular JS ในแพลตฟอร์มของเราและจัดทำแพ็คเกจโทเค็น CSRF โทเค็นทำให้มันง่ายขึ้นสำหรับเราที่จะใช้ สำหรับทุกคำขอที่แอปพลิเคชันของเราทำกับเซิร์ฟเวอร์$httpบริการAngular จะทำสิ่งเหล่านี้โดยอัตโนมัติ:

  • ค้นหาคุกกี้ชื่อ XSRF-TOKEN บนโดเมนปัจจุบัน
  • หากพบคุกกี้นั้นจะอ่านค่าและเพิ่มลงในคำขอเป็นส่วนหัว X-XSRF-TOKEN

ดังนั้นการใช้งานฝั่งไคลเอ็นต์จึงได้รับการจัดการโดยอัตโนมัติ! เราเพียงแค่ต้องตั้งชื่อคุกกี้XSRF-TOKENในโดเมนปัจจุบันในฝั่งเซิร์ฟเวอร์และเมื่อ API ของเราได้รับการเรียกจากลูกค้านั้นจะต้องตรวจสอบX-XSRF-TOKENส่วนหัวและเปรียบเทียบกับXSRF-TOKENใน JWT หากพวกเขาตรงกันผู้ใช้จะเป็นจริง มิฉะนั้นจะเป็นคำขอปลอมและคุณสามารถเพิกเฉยได้ วิธีนี้ได้รับแรงบันดาลใจจากวิธี "ส่งคุกกี้คู่"

ความระมัดระวัง

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

ไม่ว่าคุณจะจัดเก็บ JWT ของคุณในlocalStorageหรือคุณเก็บ XSRF-token ของคุณไว้ในไม่ใช่คุกกี้ HttpOnly ทั้งคู่สามารถคว้า XSS ได้อย่างง่ายดาย แม้ JWT ของคุณใน HttpOnly คุกกี้สามารถคว้าโดยการโจมตี XSS ขั้นสูงเช่นวิธี XST

ดังนั้นนอกเหนือจากวิธีการส่งคุกกี้คู่คุณต้องปฏิบัติตามแนวทางปฏิบัติที่ดีที่สุดกับ XSS รวมถึงการหลบหนีเนื้อหา นี่หมายถึงการลบรหัสที่ใช้งานได้ซึ่งจะทำให้เบราว์เซอร์ทำสิ่งที่คุณไม่ต้องการ โดยทั่วไปหมายถึงการลบ// <![CDATA[แท็กและแอตทริบิวต์ HTML ที่ทำให้ JavaScript ได้รับการประเมิน

อ่านเพิ่มเติมได้ที่นี่:


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

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

3
@shusson คุณต้องดูแลการโจมตี XSS และ XSRF เพื่อปกป้อง JWT ของคุณ ฉันไม่ยอมรับว่าคุณกำลังแลกเปลี่ยนความซับซ้อนที่สำคัญเพื่อความปลอดภัยที่เพิ่มขึ้นเล็กน้อย หากเรื่องความปลอดภัยคุณต้องพยายามทุกวิถีทางเพื่อไม่ให้มีช่องโหว่ XSS วิธีนี้ออกแบบมาเพื่อปกป้องโทเค็นของคุณจากการโจมตี XSRF แต่นั่นไม่ได้หมายความว่าคุณสามารถละเว้นช่องโหว่ XSS ได้
Iman Sedighi

5
@ImanSedighi ฉันไม่ชัดเจนโดยการจัดเก็บ jwt ในคุกกี้คุณกำลังเพิ่มความซับซ้อนและตอนนี้คุณต้องป้องกัน XSRF เหตุใดจึงไม่เพียงใช้ที่เก็บข้อมูลภายในด้วยโทเค็นอายุสั้นและมีสมาธิในการป้องกัน XSS
shusson

2
@Royi Namir: การปลอมแปลงโดย Wireshark ไม่ควรกังวลหากคุณใช้ใบรับรอง SSL $ 10! หากความปลอดภัยของเว็บไซต์มีความสำคัญคุณควรเข้ารหัสข้อมูลและใช้โปรโตคอล HTTPS
Iman Sedighi

2

อีกมุมหนึ่งของปัญหาทั้งหมดของการจัดเก็บ JWT:

  1. ไม่ควรจัดเก็บ JWT ใน localStorage ของคุณ
  2. ในความเป็นจริงพวกเขาไม่ควรแม้แต่จะเก็บไว้ในคุกกี้ของคุณ , นอกจากคุณจะสามารถที่จะใช้ป้องกัน CSRF ที่เข้มงวดมาก

ชำระเงินสำหรับแรงจูงใจ

  • JWT ในฐานะ id_token เปรียบเสมือนข้อมูลรับรองผู้ใช้ของคุณ
  • JWT ในฐานะ access_token เปรียบเสมือนโทเค็นเซสชันของคุณ

ตัวเลือกที่เชื่อถือได้มากที่สุดคือในหน่วยความจำ ชำระเงินนี้สำหรับการดำน้ำลึก

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