ฉันกำลังสร้างแอปพลิเคชันหน้าเดียวโดยใช้ reactjs ฉันอ่านว่าสาเหตุหลายประการที่ไม่ได้ใช้ localStorage เป็นเพราะช่องโหว่ XSS เนื่องจาก React หนีอินพุตทั้งหมดของผู้ใช้ตอนนี้จะปลอดภัยหรือไม่ที่จะใช้ localStorage
ฉันกำลังสร้างแอปพลิเคชันหน้าเดียวโดยใช้ reactjs ฉันอ่านว่าสาเหตุหลายประการที่ไม่ได้ใช้ localStorage เป็นเพราะช่องโหว่ XSS เนื่องจาก React หนีอินพุตทั้งหมดของผู้ใช้ตอนนี้จะปลอดภัยหรือไม่ที่จะใช้ localStorage
คำตอบ:
ในแอปพลิเคชันหน้าเดียวที่ทันสมัยส่วนใหญ่เราต้องเก็บโทเค็นไว้ที่ฝั่งไคลเอ็นต์ (กรณีการใช้งานบ่อยที่สุด - เพื่อให้ผู้ใช้เข้าสู่ระบบหลังจากรีเฟรชหน้า)
มีตัวเลือกทั้งหมด 2 ตัวเลือก: ที่เก็บข้อมูลเว็บ (ที่เก็บเซสชัน, ที่จัดเก็บในตัวเครื่อง) และคุกกี้ฝั่งไคลเอ็นต์ ตัวเลือกทั้งสองใช้กันอย่างแพร่หลาย แต่นี่ไม่ได้หมายความว่าพวกเขาจะปลอดภัยมาก
Tom Abbott สรุปความปลอดภัย JWT sessionStorage และ localStorage ได้ดี :
Web Storage (localStorage / sessionStorage) สามารถเข้าถึงได้ผ่าน JavaScript ในโดเมนเดียวกัน ซึ่งหมายความว่าการทำงาน JavaScript ใด ๆ บนเว็บไซต์ของคุณจะมีการเข้าถึงที่จัดเก็บข้อมูลเว็บและเพราะเรื่องนี้อาจจะเป็นความเสี่ยงที่จะสคริปต์ข้ามไซต์โจมตี (XSS) สั้น ๆ XSS เป็นประเภทของช่องโหว่ที่ผู้โจมตีสามารถฉีด JavaScript ที่จะทำงานบนหน้าของคุณ การโจมตี XSS พื้นฐานพยายามฉีด JavaScript ผ่านอินพุตแบบฟอร์มโดยที่ผู้โจมตีใส่
<script>alert('You are Hacked');</script>
ลงในแบบฟอร์มเพื่อดูว่าเบราว์เซอร์นั้นรันโดยผู้ใช้รายอื่นหรือไม่
เพื่อป้องกัน XSS การตอบสนองทั่วไปคือการหลบหนีและเข้ารหัสข้อมูลที่ไม่น่าเชื่อถือทั้งหมด ตอบสนอง (ส่วนใหญ่) ทำเพื่อคุณ! นี่เป็นโอกาสอันดีที่การอภิปรายเกี่ยวกับการป้องกันช่องโหว่ XSS เท่าใดจะตอบสนองความรับผิดชอบในการ
แต่นั่นไม่ครอบคลุมถึงช่องโหว่ทั้งหมด! อีกภัยคุกคามที่อาจเกิดขึ้นคือการใช้งานของ JavaScript โฮสต์บน CDNs หรือโครงสร้างพื้นฐานนอก
นี่คือทอมอีกครั้ง:
เว็บแอพที่ทันสมัยประกอบด้วยห้องสมุด JavaScript ของบุคคลที่สามสำหรับการทดสอบ A / B การวิเคราะห์ช่องทาง / การตลาดและโฆษณา เราใช้ตัวจัดการแพคเกจเช่น Bower เพื่อนำเข้ารหัสของผู้อื่นในแอพของเรา
จะเกิดอะไรขึ้นถ้าสคริปต์ใดสคริปต์หนึ่งที่คุณใช้ถูกบุกรุก? มัลแวร์ที่เป็นอันตรายสามารถฝังลงในหน้าเว็บและที่เก็บข้อมูลบนเว็บถูกบุกรุก การโจมตี XSS ประเภทนี้สามารถรับที่เก็บข้อมูลเว็บของทุกคนที่เข้าชมไซต์ของคุณโดยที่พวกเขาไม่รู้ตัว นี่อาจเป็นสาเหตุที่หลายองค์กรแนะนำไม่ให้เก็บของมีค่าหรือไว้วางใจข้อมูลใด ๆ ในที่เก็บข้อมูลบนเว็บ ซึ่งรวมถึงตัวระบุเซสชันและโทเค็น
ดังนั้นข้อสรุปของฉันคือเป็นกลไกการจัดเก็บ, Web Storage ไม่ได้บังคับใช้มาตรฐานการรักษาความปลอดภัยใด ๆ ระหว่างการถ่ายโอน ใครก็ตามที่อ่านที่เก็บข้อมูลบนเว็บและใช้งานนั้นจะต้องดำเนินการตรวจสอบสถานะของตนเองเพื่อให้แน่ใจว่าพวกเขาส่ง JWT ผ่าน HTTPS และไม่ใช้ HTTP
ฉันรู้ว่านี่เป็นคำถามเก่า แต่ตามสิ่งที่ @ mikejones1477 พูดว่า front front front ที่ทันสมัยและกรอบการทำงานช่วยให้คุณป้องกัน XSS ได้ เหตุผลที่คุกกี้ไม่ปลอดภัยโดยใช้ข้อมูลรับรองคือคุกกี้ไม่ป้องกัน CSRF เมื่อ localStorage ทำเช่นกัน (โปรดจำไว้ว่าจาวาสคริปต์สามารถเข้าถึงคุกกี้ได้เช่นกันดังนั้น XSS ไม่ใช่ปัญหาใหญ่ที่นี่) คำตอบนี้จะกลับมาทำงานอีกครั้ง
เหตุผลที่จัดเก็บโทเค็นการตรวจสอบความถูกต้องในที่จัดเก็บในตัวเครื่องและเพิ่มไปยังแต่ละคำขอด้วยตนเองเพื่อป้องกัน CSRF คือคำสำคัญ: คู่มือ เนื่องจากเบราว์เซอร์ไม่ได้ส่งโทเค็นการตรวจสอบความถูกต้องนั้นโดยอัตโนมัติหากฉันไปที่ evil.com และจัดการเพื่อส่ง POST http://example.com/delete-my-accountมันจะไม่สามารถส่งโทเค็น authn ของฉันได้ดังนั้น คำขอจะถูกละเว้น
แน่นอน httpOnly เป็นจอกศักดิ์สิทธิ์ แต่คุณไม่สามารถเข้าถึงได้จาก reactjs หรือกรอบ js ใด ๆ ข้างคุณยังมีช่องโหว่ CSRF แนะนำของฉันจะ localStorage หรือถ้าคุณต้องการที่จะใช้คุกกี้ให้แน่ใจว่า implemeting วิธีการแก้ปัญหาบางอย่างที่คุณปัญหา CSRF เช่น Django ไม่
เกี่ยวกับ CDN ตรวจสอบให้แน่ใจว่าคุณไม่ได้ใช้ CDN แปลก ๆ เช่น CDN เช่น google หรือ bootstrap ที่เตรียมไว้ได้รับการดูแลโดยชุมชนและไม่มีรหัสที่เป็นอันตรายหากคุณไม่แน่ใจคุณสามารถตรวจสอบได้ฟรี
HttpOnly
SameSite=strict
และsecure
จะเก็บข้อมูลที่คุณตั้งไว้ในคุกกี้อย่างปลอดภัย จาก XSS คุณต้องแน่ใจว่า JavaScript ของคุณไม่ทราบข้อมูลที่เกี่ยวข้องกับการตรวจสอบสิทธิ์เช่นโทเค็นและรหัสผ่าน (หมายถึงไม่เก็บไว้ในที่เก็บข้อมูลเว็บ) - หากคุณนำเข้าสคริปต์ที่เป็นอันตรายสคริปต์นั้นจะไม่สามารถเข้าถึงได้ ข้อมูลที่ละเอียดอ่อน ใช่คุณจะไม่สามารถเข้าถึงโทเค็นผ่าน JS ได้ แต่นั่นไม่น่าจะมีปัญหา
โดยทั่วไปมันก็โอเคที่จะเก็บ JWT ของคุณใน localStorage ของคุณ
และฉันคิดว่านี่เป็นวิธีที่ดี หากเรากำลังพูดถึง XSS, XSS โดยใช้ CDN ก็เป็นความเสี่ยงที่อาจเกิดขึ้นกับการเข้าสู่ระบบ / รหัสผ่านของลูกค้าของคุณเช่นกัน การจัดเก็บข้อมูลในที่จัดเก็บในตัวเครื่องจะป้องกันการโจมตีจาก CSRF เป็นอย่างน้อย
คุณต้องระวังทั้งสองอย่างและเลือกสิ่งที่คุณต้องการ การโจมตีทั้งสองอย่างนั้นไม่ใช่สิ่งที่คุณต้องระวังเพียงจำไว้ว่าแอปทั้งหมดของคุณนั้นปลอดภัยเพียงอย่างเดียวเช่นเดียวกับจุดที่ปลอดภัยน้อยที่สุดของแอพของคุณ
การจัดเก็บอีกครั้งก็โอเคเสี่ยงต่อ XSS, CSRF, ... ไม่ได้
ไม่ปลอดภัยหากคุณใช้ CDN:
มัลแวร์ที่เป็นอันตรายสามารถถูกฝังลงบนหน้าเว็บและที่เก็บข้อมูลบนเว็บถูกบุกรุก การโจมตี XSS ประเภทนี้สามารถรับที่เก็บข้อมูลเว็บของทุกคนที่เข้าชมไซต์ของคุณโดยที่พวกเขาไม่รู้ตัว นี่อาจเป็นสาเหตุที่หลายองค์กรแนะนำไม่ให้เก็บของมีค่าหรือไว้วางใจข้อมูลใด ๆ ในที่เก็บข้อมูลบนเว็บ ซึ่งรวมถึงตัวระบุเซสชันและโทเค็น
ผ่านทางStormpath
สคริปต์ใด ๆ ที่คุณต้องการจากภายนอกอาจถูกบุกรุกและสามารถดึง JWTS จากที่เก็บข้อมูลของลูกค้าของคุณและส่งข้อมูลส่วนบุคคลกลับไปยังเซิร์ฟเวอร์ของผู้โจมตี
Localstorage ได้รับการออกแบบให้สามารถเข้าถึงได้โดย javascript ดังนั้นจึงไม่มีการป้องกัน XSS ใด ๆ ดังที่กล่าวไว้ในคำตอบอื่น ๆ มีหลายวิธีที่เป็นไปได้ที่จะทำการโจมตี XSS ซึ่งการจัดเก็บในพื้นที่จะไม่ได้รับการป้องกันโดยค่าเริ่มต้น
อย่างไรก็ตามคุกกี้มีค่าสถานะความปลอดภัยซึ่งป้องกันการโจมตี XSS และ CSRF การตั้งค่าสถานะ HttpOnly ป้องกันจาวาสคริปต์ฝั่งไคลเอ็นต์ไม่ให้เข้าถึงคุกกี้การตั้งค่าความปลอดภัยอนุญาตให้เบราว์เซอร์ถ่ายโอนคุกกี้ผ่าน ssl เท่านั้นและการตั้งค่าสถานะ SameSite ทำให้มั่นใจได้ว่าคุกกี้ถูกส่งไปยังจุดเริ่มต้นเท่านั้น แม้ว่าฉันเพิ่งจะตรวจสอบและปัจจุบัน SameSite รองรับเฉพาะใน Opera และ Chrome ดังนั้นเพื่อปกป้องจาก CSRF จะดีกว่าถ้าใช้กลยุทธ์อื่น ตัวอย่างเช่นการส่งโทเค็นที่เข้ารหัสในคุกกี้อื่นที่มีข้อมูลผู้ใช้สาธารณะบางส่วน
ดังนั้นคุกกี้จึงเป็นตัวเลือกที่ปลอดภัยยิ่งขึ้นสำหรับการจัดเก็บข้อมูลการตรวจสอบสิทธิ์
id_token_hint
เซิร์ฟเวอร์ OIDC รับรองความถูกต้อง; โทเค็นให้ข้อมูลผู้โจมตีเกี่ยวกับรหัสที่ใช้ในการเซ็นชื่อ ฯลฯ
วิธีที่จะดูสิ่งนี้คือการพิจารณาระดับความเสี่ยงหรืออันตราย
คุณกำลังสร้างแอพโดยไม่มีผู้ใช้ POC / MVP หรือไม่? คุณเป็นผู้เริ่มต้นที่ต้องการออกสู่ตลาดและทดสอบแอปของคุณอย่างรวดเร็วหรือไม่? ถ้าใช่ฉันอาจจะใช้โซลูชันที่ง่ายที่สุดและรักษาโฟกัสในการหาตลาดที่เหมาะสม ใช้ localStorage เป็นวิธีที่ง่ายกว่าในการนำไปใช้
คุณกำลังสร้าง v2 ของแอปที่มีผู้ใช้ที่ใช้งานอยู่ทุกวันหรือแอพที่คน / ธุรกิจต้องพึ่งพาอย่างมาก การแฮ็คหมายถึงมีที่ว่างน้อยหรือไม่มีเลยสำหรับการกู้คืน? หากเป็นเช่นนั้นฉันจะพิจารณาการอ้างอิงของคุณอย่างหนักและพิจารณาจัดเก็บข้อมูลโทเค็นในคุกกี้แบบ http เท่านั้น
การใช้ทั้ง localStorage และที่เก็บคุกกี้ / เซสชันมีข้อดีและข้อเสียของตัวเอง
ตามที่ระบุไว้โดยคำตอบแรก: หากแอปพลิเคชันของคุณมีช่องโหว่ XSS จะไม่ปกป้องผู้ใช้ของคุณ เนื่องจากแอพพลิเคชั่นที่ทันสมัยส่วนใหญ่มีการอ้างอิงมากกว่าหนึ่งโหลหรือมากกว่านั้นมันจึงยากที่จะรับประกันได้ว่าแอพพลิเคชั่นหนึ่งในการอ้างอิงของคุณจะไม่เสี่ยงต่อการเกิด XSS
หากแอปพลิเคชันของคุณมีช่องโหว่ XSS และแฮ็กเกอร์สามารถใช้ประโยชน์จากมันแฮ็กเกอร์จะสามารถดำเนินการในนามของผู้ใช้ของคุณ แฮ็กเกอร์สามารถดำเนินการตามคำขอ GET / POST โดยดึงโทเค็นจาก localStorage หรือสามารถดำเนินการตามคำขอ POST ได้หากโทเค็นถูกเก็บไว้ในคุกกี้แบบ http เท่านั้น
ข้อเสียเพียงอย่างเดียวของการจัดเก็บโทเค็นของคุณในที่จัดเก็บในตัวเครื่องคือแฮ็กเกอร์จะสามารถอ่านโทเค็นของคุณได้
ไม่ยอมรับ localStorage หรือคุกกี้ httpOnly อย่างเดียวหรือ ในเรื่องที่เกี่ยวกับห้องสมุดของบุคคลที่ 3 ที่ถูกบุกรุกทางออกเดียวที่ฉันรู้ที่จะช่วยลด / ป้องกันไม่ให้ข้อมูลที่สำคัญจากการถูกขโมยจะมีผลบังคับใช้Subresource ความซื่อสัตย์
Subresource Integrity (SRI) เป็นคุณลักษณะด้านความปลอดภัยที่ช่วยให้เบราว์เซอร์ตรวจสอบว่ามีการส่งมอบทรัพยากร (ตัวอย่างเช่นจาก CDN) โดยไม่มีการจัดการที่ไม่คาดคิด มันทำงานได้โดยอนุญาตให้คุณจัดเตรียมแฮชการเข้ารหัสที่ทรัพยากรที่ดึงมาต้องตรงกัน
ตราบใดที่ห้องสมุดบุคคลที่สามถูกบุกรุกใช้งานบนเว็บไซต์ของคุณคีย์ล็อกเกอร์สามารถเริ่มรวบรวมข้อมูลเช่นชื่อผู้ใช้รหัสผ่านและสิ่งอื่นใดที่คุณป้อนเข้าสู่เว็บไซต์
httpOnly cookie จะป้องกันการเข้าถึงจากคอมพิวเตอร์เครื่องอื่น แต่จะไม่ทำอะไรเลยเพื่อป้องกันไม่ให้แฮกเกอร์จัดการคอมพิวเตอร์ของผู้ใช้
มีความปลอดภัยในการเก็บโทเค็นของคุณใน localStorage ตราบใดที่คุณเข้ารหัส ด้านล่างนี้เป็นข้อมูลโค้ดที่ถูกบีบอัดซึ่งแสดงหนึ่งในหลายวิธีที่คุณสามารถทำได้
import SimpleCrypto from 'simple-crypto-js';
const saveToken = (token = '') => {
const encryptInit = new SimpleCrypto('PRIVATE_KEY_STORED_IN_ENV_FILE');
const encryptedToken = encryptInit.encrypt(token);
localStorage.setItem('token', encryptedToken);
}
จากนั้นก่อนใช้โทเค็นของคุณจะถอดรหัสโดยใช้ PRIVATE_KEY_STORED_IN_ENV_FILE