ปกป้องทรัพยากรจากการโจมตีเว็บด้วยการดึงข้อมูลข้อมูลเมตา

ป้องกันข้อมูลรั่วไหล CSRF, XSSI และข้ามต้นทาง

เหตุใดคุณจึงควรสนใจการแยกทรัพยากรบนเว็บ

เว็บแอปพลิเคชันจำนวนมากมีช่องโหว่ต่อการโจมตีแบบ cross-Origin เช่น cross-site request forgery (CSRF), การรวมสคริปต์ข้ามเว็บไซต์ (XSSI), การโจมตีแบบจับเวลา, การรั่วไหลของข้อมูลข้ามต้นทาง หรือการโจมตีแบบ Side-channel (Spectre) ของการดำเนินการแบบคาดเดา

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

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

ความเข้ากันได้กับเบราว์เซอร์

ส่วนหัวของคำขอดึงข้อมูลข้อมูลเมตาได้รับการรองรับในเครื่องมือเบราว์เซอร์รุ่นใหม่ทั้งหมด

การรองรับเบราว์เซอร์

  • Chrome: 76
  • ขอบ: 79
  • Firefox: 90
  • Safari: 16.4

แหล่งที่มา

ข้อมูลเบื้องต้น

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

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

ขอแนะนำการดึงข้อมูลข้อมูลเมตา

ส่วนหัวของคำขอดึงข้อมูลข้อมูลเมตาเป็นฟีเจอร์ความปลอดภัยของแพลตฟอร์มเว็บแบบใหม่ที่ออกแบบมาเพื่อช่วยให้เซิร์ฟเวอร์ป้องกันตัวเองจากการโจมตีแบบข้ามต้นทาง การให้ข้อมูลเกี่ยวกับบริบทของคำขอ HTTP ในชุดส่วนหัว Sec-Fetch-* ช่วยให้เซิร์ฟเวอร์ที่ตอบสนองใช้นโยบายความปลอดภัยได้ก่อนประมวลผลคำขอ สิทธิ์นี้เปิดโอกาสให้นักพัฒนาแอปตัดสินใจว่าจะยอมรับหรือปฏิเสธคําขอโดยอิงตามรูปแบบที่ส่งคำขอและบริบทที่จะนำไปใช้ ทำให้ตอบกลับได้เฉพาะคำขอที่ถูกต้องจากแอปพลิเคชันของตนเองเท่านั้น

ต้นทางเดียวกัน
คำขอที่มาจากเว็บไซต์ที่แสดงโดยเซิร์ฟเวอร์ของคุณเอง (ต้นทางเดียวกัน) จะยังคงใช้งานได้ต่อไป คำขอดึงข้อมูลจาก https://site.example สำหรับทรัพยากร https://site.example/foo.json ใน JavaScript ทำให้เบราว์เซอร์ส่งส่วนหัวของคำขอ HTTP "Sec Fetch-Site: same-origin"
แบบข้ามเว็บไซต์
เซิร์ฟเวอร์อาจปฏิเสธคำขอข้ามเว็บไซต์ที่เป็นอันตรายได้ เนื่องจากมีบริบทเพิ่มเติมในคำขอ HTTP จากส่วนหัวของ Sec-Fetch-* รูปภาพใน https://evil.example ที่ตั้งค่าแอตทริบิวต์ src ขององค์ประกอบ img เป็น "https://site.example/foo.json" ทำให้เบราว์เซอร์ส่งส่วนหัวของคำขอ HTTP "Sec-Fetch-Site: Cross-site"

Sec-Fetch-Site

การรองรับเบราว์เซอร์

  • Chrome: 76
  • ขอบ: 79
  • Firefox: 90
  • Safari: 16.4

แหล่งที่มา

Sec-Fetch-Site จะบอกเซิร์ฟเวอร์ว่าเว็บไซต์ใดส่งคำขอ โดยเบราว์เซอร์จะตั้งค่านี้เป็นค่าใดค่าหนึ่งต่อไปนี้

  • same-origin หากเป็นคำขอจากแอปพลิเคชันของคุณเอง (เช่น site.example)
  • same-site หากคำขอมาจากโดเมนย่อยของเว็บไซต์ (เช่น bar.site.example)
  • none หากคำขอนั้นเกิดจากการโต้ตอบของผู้ใช้กับ User Agent อย่างชัดเจน (เช่น การคลิกบุ๊กมาร์ก)
  • cross-site หากคำขอถูกส่งโดยเว็บไซต์อื่น (เช่น evil.example)

Sec-Fetch-Mode

การรองรับเบราว์เซอร์

  • Chrome: 76
  • ขอบ: 79
  • Firefox: 90
  • Safari: 16.4

แหล่งที่มา

Sec-Fetch-Mode ระบุโหมดของคำขอ ซึ่งจะสอดคล้องกับประเภทของคำขออย่างคร่าวๆ และช่วยให้คุณแยกความแตกต่างของการโหลดทรัพยากรกับคำขอการนำทางได้ ตัวอย่างเช่น ปลายทาง navigate บ่งบอกถึงคำขอการนำทางระดับบนสุด ขณะที่ no-cors บ่งบอกถึงคำขอทรัพยากร เช่น การโหลดรูปภาพ

Sec-Fetch-Dest

การรองรับเบราว์เซอร์

  • Chrome: 80
  • ขอบ: 80
  • Firefox: 90
  • Safari: 16.4

แหล่งที่มา

Sec-Fetch-Dest จะแสดงปลายทางของคำขอ (เช่น หากแท็ก script หรือ img ทำให้เบราว์เซอร์ขอทรัพยากร)

วิธีใช้การดึงข้อมูลข้อมูลเมตาเพื่อป้องกันการโจมตีแบบข้ามต้นทาง

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

การใช้นโยบายการแยกทรัพยากร

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

ขั้นตอนที่ 1: อนุญาตคำขอจากเบราว์เซอร์ที่ไม่ส่งการดึงข้อมูลข้อมูลเมตา

เนื่องจากบางเบราว์เซอร์ไม่รองรับการดึงข้อมูลข้อมูลเมตา คุณจึงต้องอนุญาตคำขอที่ไม่ได้ตั้งค่าส่วนหัว Sec-Fetch-* โดยตรวจหาการมีอยู่ของ sec-fetch-site

if not req['sec-fetch-site']:
  return True  # Allow this request

ขั้นตอนที่ 2: อนุญาตคำขอที่มาจากเว็บไซต์เดียวกันและเบราว์เซอร์ที่เริ่มต้น

คำขอที่ไม่ได้มาจากบริบทแบบข้ามต้นทาง (เช่น evil.example) จะได้รับอนุญาต โดยเฉพาะอย่างยิ่งคำขอที่:

  • มาจากแอปพลิเคชันของคุณเอง (เช่น คำขอต้นทางเดียวกันโดยที่ site.example จะอนุญาตคำขอ site.example/foo.json เสมอ)
  • มาจากโดเมนย่อยของคุณ
  • เกิดจากการโต้ตอบของผู้ใช้กับ User Agent อย่างชัดเจน (เช่น การไปยังส่วนต่างๆ โดยตรงหรือการคลิกบุ๊กมาร์ก เป็นต้น)
if req['sec-fetch-site'] in ('same-origin', 'same-site', 'none'):
  return True  # Allow this request

ขั้นตอนที่ 3: อนุญาตการนำทางและ iframe ระดับบนสุดแบบง่าย

เพื่อให้มั่นใจว่าเว็บไซต์ของคุณจะยังลิงก์จากเว็บไซต์อื่นๆ ได้ คุณต้องอนุญาตการนำทางระดับบนสุดแบบง่าย (HTTP GET)

if req['sec-fetch-mode'] == 'navigate' and req.method == 'GET'
  # <object> and <embed> send navigation requests, which we disallow.
  and req['sec-fetch-dest'] not in ('object', 'embed'):
    return True  # Allow this request

ขั้นตอนที่ 4: เลือกไม่ใช้ปลายทางที่ให้บริการรับส่งข้อมูลข้ามเว็บไซต์ (ไม่บังคับ)

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

  • ปลายทางที่ต้องการเข้าถึงแบบข้ามต้นทาง: หากแอปพลิเคชันของคุณให้บริการปลายทางที่ CORS เปิดใช้อยู่ คุณต้องเลือกไม่ใช้การแยกทรัพยากรอย่างชัดแจ้งเพื่อให้มั่นใจว่าคำขอข้ามเว็บไซต์ที่ส่งไปยังปลายทางเหล่านี้ยังคงเป็นไปได้
  • ทรัพยากรสาธารณะ (เช่น รูปภาพ รูปแบบ ฯลฯ): ทรัพยากรสาธารณะและที่ไม่ได้ตรวจสอบสิทธิ์ใดๆ ที่ควรโหลดแบบข้ามต้นทางจากเว็บไซต์อื่นๆ ได้สามารถยกเว้นได้เช่นกัน
if req.path in ('/my_CORS_endpoint', '/favicon.png'):
  return True

ขั้นตอนที่ 5: ปฏิเสธคำขออื่นๆ ทั้งหมดที่เป็นข้ามเว็บไซต์และไม่ใช้การนำทาง

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

ตัวอย่าง: โค้ดต่อไปนี้แสดงการใช้งานนโยบายการแยกทรัพยากรที่มีประสิทธิภาพบนเซิร์ฟเวอร์หรือเป็นมิดเดิลแวร์เพื่อปฏิเสธคำขอทรัพยากรแบบข้ามเว็บไซต์ที่อาจเป็นอันตราย ในขณะเดียวกันก็อนุญาตคำขอการนำทางแบบง่ายๆ

# Reject cross-origin requests to protect from CSRF, XSSI, and other bugs
def allow_request(req):
  # Allow requests from browsers which don't send Fetch Metadata
  if not req['sec-fetch-site']:
    return True

  # Allow same-site and browser-initiated requests
  if req['sec-fetch-site'] in ('same-origin', 'same-site', 'none'):
    return True

  # Allow simple top-level navigations except <object> and <embed>
  if req['sec-fetch-mode'] == 'navigate' and req.method == 'GET'
    and req['sec-fetch-dest'] not in ('object', 'embed'):
      return True

  # [OPTIONAL] Exempt paths/endpoints meant to be served cross-origin.
  if req.path in ('/my_CORS_endpoint', '/favicon.png'):
    return True

  # Reject all other requests that are cross-site and not navigational
  return False

การทำให้นโยบายการแยกทรัพยากรใช้งานได้

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

การระบุและแก้ไขการละเมิดนโยบาย

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

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

การบังคับใช้นโยบายการแยกทรัพยากร

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

อ่านเพิ่มเติม