ในที่สุด SharedArrayBuffer ก็กลับมาใช้งานได้ในเบราว์เซอร์อีกครั้ง แต่จะใช้งานได้ก็ต่อเมื่อหน้าเว็บอยู่ในสถานะ cross-origin isolated เท่านั้น ซึ่งเป็นสถานะที่ต้องใช้ response headers สองตัว การเพิ่ม header เหล่านี้ทำให้ผมต้องตัดสคริปต์จากบุคคลที่สาม (third-party script) ทั้งหมดออกจากไซต์ของผม ซึ่งเป็นการตัดสินใจที่เปลี่ยนรูปแบบการสร้าง front end ทั้งหมด รวมถึงข้อมูลที่อาจรั่วไหลออกไปด้วย

SharedArrayBuffer ช่วยให้ JavaScript สามารถทำ multithreading ได้อย่างแท้จริง ซึ่งเป็นเงื่อนไขจำเป็นสำหรับการรัน ffmpeg ภายในแท็บ เบราว์เซอร์สมัยใหม่ได้เปิดใช้งานฟีเจอร์นี้อีกครั้งหลังจากมีการใช้มาตรการป้องกันแบบ Spectre แต่พวกเขาได้ผูกมันไว้กับ cross-origin isolation เพื่อให้บรรลุการแยกส่วน (isolation) ดังกล่าว เซิร์ฟเวอร์ต้องส่ง:

  • Cross-Origin-Opener-Policy: same-origin
  • Cross-Origin-Embedder-Policy: require-corp

Header ตัวที่สอง require-corp จะบอกเบราว์เซอร์ว่าทรัพยากรภายนอกใดๆ จะต้องมี header Cross-Origin-Resource-Policy หรือต้องถูกดึงข้อมูลผ่าน CORS (Cross-Origin Resource Sharing) บริการจากบุคคลที่สามส่วนใหญ่ไม่ได้ตั้งค่า header เหล่านี้ ดังนั้นสคริปต์, ฟอนต์ และ iframe ของพวกเขาจึงถูกบล็อกโดยสิ้นเชิง

สิ่งที่หายไปเมื่อเปิดใช้งานการแยกส่วน (isolation)

ทันทีที่ header เหล่านี้เริ่มใช้งาน ผลกระทบแบบโดมิโนก็ปรากฏขึ้น:

  • Analytics – ผู้ให้บริการส่วนใหญ่โหลดโค้ดติดตามด้วย <script> แบบธรรมดาซึ่งเป็นการส่งคำขอแบบ no-CORS หากไม่มี header CORP คำขอนั้นจะถูกปฏิเสธ ทำให้ตัวติดตามไม่ทำงาน
  • Google Fonts – stylesheet ถูกดึงมาจาก fonts.googleapis.com โดยไม่มี CORS เบราว์เซอร์จึงทิ้งไฟล์นั้นไป ทำให้หน้าเว็บไม่มีรูปแบบตัวอักษร (typography) ที่กำหนดไว้
  • Embedded media – YouTube iframes และสคริปต์ widget ขาด CORP จึงทำให้ไม่สามารถแสดงผลได้
  • OAuth pop-ups – ความสัมพันธ์แบบ window.opener ถูกทำลายโดยนโยบาย same-origin ที่เข้มงวด ทำให้ขั้นตอนการเข้าสู่ระบบผ่าน popup แบบปกติใช้งานไม่ได้

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

การสร้างใหม่โดยไม่ต้องผ่านตัวกลาง

เมื่อต้องเผชิญกับไซต์ที่พังทลาย ผมจึงเขียน stack ของ front-end ใหม่โดยเน้นไปที่การใช้ self-hosted assets:

  • Fonts and images ถูกส่งมาจาก origin ของผมเอง ช่วยลดความจำเป็นในการใช้ stylesheet ภายนอก
  • Data APIs ถูกสร้างขึ้นบน backend ส่วนตัวที่ผมควบคุม ดังนั้นทุกคำขอจะอยู่ภายในโดเมนของผมเท่านั้น
  • Analytics เปลี่ยนมาใช้ Cloudflare Worker ขนาดเล็กที่รับเหตุการณ์ POST และจัดเก็บไว้ใน private bucket ฝั่ง client-side มีเพียงโค้ด fetch ไม่กี่บรรทัดเท่านั้น
  • Error reporting and session replay เครื่องมืออย่าง Sentry ถูกตัดออกไปทั้งหมด โดยความผิดพลาด (crash) ใดๆ จะถูกบันทึกลงใน endpoint ของผมเอง

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

ประโยชน์ด้านความเป็นส่วนตัว เทียบกับ ต้นทุนในการดำเนินงาน

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

สิ่งที่ต้องแลกมาคือภาระในการดูแลรักษาที่เพิ่มขึ้น การโฮสต์ฟอนต์, การจัดการการจัดเก็บ analytics และการคอยอัปเดต proxy เป็นงานที่นักพัฒนาส่วนใหญ่มักจะจ้างบริการเฉพาะทางทำ นอกจากนี้ แนวทางนี้ยังหมายถึงการสูญเสียฟีเจอร์ที่บริการเหล่านั้นมีให้ เช่น การรวบรวมข้อผิดพลาดแบบเรียลไทม์ หรือการแสดงภาพ funnel แบบละเอียด

มุมมองแย้ง: ระบบนิเวศจะปรับตัวหรือไม่?

บางคนแย้งว่าในที่สุดผู้ให้บริการบุคคลที่สามจะเพิ่ม header ที่จำเป็น ทำให้การนำ cross-origin isolation มาใช้เป็นเรื่องง่าย มีบางรายที่ทำแล้ว แต่บริการส่วนใหญ่ที่ใช้กันอย่างแพร่หลายยังไม่ได้ทำ จนกว่าระบบนิเวศจะตามทัน นักพัฒนาต้องตัดสินใจว่าข้อดีด้านความเป็นส่วนตัวนั้นคุ้มค่ากับความพยายามทางวิศวกรรมที่ต้องใช้ในการทำ self-host หรือไม่

วิธีตรวจสอบว่าคุณได้รับการแยกส่วน (isolated) อย่างแท้จริง

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

crossOriginIsolated   // should be true
typeof SharedArrayBuffer   // should be "function"

หากการตรวจสอบใดการตรวจสอบหนึ่งล้มเหลว แสดงว่า header ไม่ได้ถูกนำมาใช้อย่างถูกต้อง และ SharedArrayBuffer จะยังคงใช้งานไม่ได้

ก้าวต่อไปสำหรับนักพัฒนาคืออะไร?

เมื่อเว็บแอปพลิเคชันจำนวนมากขึ้นต้องการประสิทธิภาพที่เพิ่มขึ้นจาก multithreaded JavaScript แรงกดดันต่อผู้ให้บริการบุคคลที่สามในการนำ CORP มาใช้จะเพิ่มมากขึ้น ในระหว่างนี้ โปรเจกต์ใดก็ตามที่ต้องการ SharedArrayBuffer ควรวางแผนกลยุทธ์การใช้ self-hosted asset หรือเลเยอร์ proxy ขนาดเล็ก นอกจากนี้ การคอยติดตามบันทึกการอัปเดต (release notes) ของเบราว์เซอร์เกี่ยวกับการเปลี่ยนแปลงข้อกำหนดการแยกส่วนก็เป็นสิ่งสำคัญเช่นกัน

สรุปสาระสำคัญ: การเปิดใช้งาน cross-origin isolation เพื่อปลดล็อก SharedArrayBuffer บีบให้ต้องตัดสินใจเลือกอย่างใดอย่างหนึ่ง ระหว่างการรักษาความสะดวกสบายจากการใช้ third-party scripts หรือการยอมแลกเพื่อเปลี่ยนไปใช้โมเดลความเป็นส่วนตัวที่รัดกุมและควบคุมได้ด้วยตนเองมากขึ้น ซึ่งการตัดสินใจนี้จะส่งผลต่อการปรับเปลี่ยนทั้งสถาปัตยกรรมทางเทคนิคและรูปแบบการไหลของข้อมูล (data-flow footprint) ของเว็บไซต์สมัยใหม่