1 คะแนน โดย GN⁺ 1 시간 전 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • การโจมตีซัพพลายเชนต่อ npm registry ทำให้แอปองค์กรนับล้านและข้อมูลผู้ใช้นับพันล้านรายการถูกเปิดเผย แต่ระบบนิเวศกลับยอมรับเรื่องนี้ราวกับเป็นสิ่งที่หลีกเลี่ยงไม่ได้
  • Senior Frontend Engineer Mark Vance เสียดสีความจริงที่ว่าการแปลงสตริงให้เป็นตัวพิมพ์ใหญ่ยังต้องพึ่งพา dependency แบบซ้อนลึก 40 ชั้นจากแพ็กเกจที่ไม่ผ่านการตรวจสอบ
  • การที่แพ็กเกจยูทิลิตีซึ่งถูกปล่อยทิ้งร้างมานานถูกยึดไปใช้เพื่อฝัง crypto-miner ลงในโปรดักชันบิลด์ทั่วโลก ถูกปฏิบัติราวกับเป็นภัยพิบัติทางธรรมชาติ
  • ระบบนิเวศ Node.js ยอมรับ remote code execution ที่เป็นอันตรายเหมือนเป็นโศกนาฏกรรมที่คาดเดาไม่ได้ ขณะที่ทีม DevOps ก็วุ่นอยู่กับการหมุน AWS key
  • ระบบนิเวศของ Go, Rust และ Native Web API เป็นภาพเปรียบเทียบที่ตัดกัน โดยอาศัย standard library ที่แข็งแรงและการตรวจสอบเชิงเข้ารหัสเพื่อลดการพึ่งพา third-party

เสียดสีการโจมตีซัพพลายเชนของ npm

  • การโจมตีซัพพลายเชนของ npm registry ทำให้แอปพลิเคชันองค์กรนับล้านรายการถูกเจาะและข้อมูลผู้ใช้นับพันล้านรายการรั่วไหล แต่เหล่านักพัฒนาในระบบนิเวศ JavaScript กลับรับมันเหมือนเป็นเรื่องที่ “หลีกเลี่ยงไม่ได้โดยสิ้นเชิง”
  • Senior Frontend Engineer Mark Vance มองว่าการต้องพึ่ง dependency tree แบบซ้อนลึก 40 ชั้นจากแพ็กเกจที่ไม่ผ่านการตรวจสอบ เพียงเพื่อทำให้สตริงเดี่ยวกลายเป็นตัวพิมพ์ใหญ่ คือราคาที่ต้องจ่ายของการพัฒนาเว็บแอปสมัยใหม่
  • สถานการณ์ที่แพ็กเกจยูทิลิตีซึ่งถูกปล่อยทิ้งไว้นานถูกยึดและใช้ฝัง crypto-miner ลงในโปรดักชันบิลด์ทั่วโลก ถูกปฏิบัติราวกับเป็นภัยธรรมชาติ
  • ระบบนิเวศ Node.js ยอมรับ remote code execution ที่เป็นอันตรายเหมือนเป็นโศกนาฏกรรมที่คาดเดาไม่ได้ และส่ง “ความคิดและคำภาวนา” ไปยังทีม DevOps ที่กำลังยุ่งกับการเปลี่ยน AWS key

ความต่างระหว่างระบบนิเวศอื่นกับ npm

  • ระบบนิเวศของ Go, Rust และ Native Web API มี standard library ที่แข็งแรง จึงลดการพึ่งพาโค้ดจาก third-party ได้มาก และยังมีการตรวจสอบเชิงเข้ารหัสอย่างเข้มงวดใน toolchain หลัก
  • เมื่อเทียบกันแล้ว ในระบบนิเวศเหล่านั้นยังสามารถพูดได้ว่า “วันนี้มี 0 ครั้งที่โปรเจกต์สุดสัปดาห์ของคนลาออกจากมหาวิทยาลัยมาทำลายโครงสร้างพื้นฐานโลจิสติกส์ระดับโลก”
  • โฆษกของ npm ย้ำว่าในโลกที่มีผู้ไม่หวังดีอยู่ ก็ต้องยอมรับเรื่องนี้ และไม่มีนโยบายของ registry หรือ guardrail แบบ build sandbox ที่จะป้องกันได้
  • npm registry ถูกวาดภาพว่าเป็นโอเพนซอร์ส registry ที่รัน install script ตามค่าเริ่มต้นบนเครื่องโลคัล ทำให้คำพูดของโฆษกสอดรับกับความเสี่ยงเชิงโครงสร้าง
  • ตอนท้ายกล่าวปลอบใจผู้เสียหาย แต่ก็ปิดด้วยน้ำเสียงทำนองว่าต้องรักษาความยืดหยุ่นไว้จนกว่าจะถึง “การเจาะระบบที่หลีกเลี่ยงไม่ได้ครั้งถัดไป” ในเช้าวันพรุ่งนี้

1 ความคิดเห็น

 
GN⁺ 1 시간 전
ความเห็นจาก Hacker News
  • แต่ละคนอาจมีความเห็นต่างกันเรื่อง cooldown แต่การโจมตี supply chain ของ npm จำนวนมากในช่วงหลัง รวมถึง axios, tanstack น่าจะหลีกเลี่ยงได้ด้วย cooldown
    ถ้าใช้ Artifactory / Nexus ก็มีโอกาสสูงว่าอาจมี cooldown อยู่แล้ว และถ้ายังไม่มีก็ตั้งค่าได้ง่าย
    การเจาะ npm หรือ PyPI ส่วนใหญ่ถูกถอดลงภายในไม่กี่ชั่วโมง ดังนั้น cooldown จึงหมายถึง “เมินแพ็กเกจที่เพิ่งปล่อยออกมาไม่เกิน N วัน” แม้ 1 วันก็ช่วยได้, 3 วันก็กำลังดี, และ 7 วันอาจจะเยอะไปหน่อยแต่ก็ใช้ได้
    วิธีตั้งค่าคือใช้ pnpm รุ่นล่าสุดที่มี cooldown เริ่มต้น 1 วันอยู่แล้ว https://pnpm.io/supply-chain-security หรือถ้าอยากแก้ทีเดียวจบก็ใช้ https://depsguard.com ที่ใส่ cooldown และค่าที่แนะนำให้กับ npm, pnpm, yarn, bun, uv, dependabot ได้เลย ผมเป็นผู้ดูแลมันเอง
    หรือจะใช้ https://cooldowns.dev ที่เน้นเรื่อง cooldown มากกว่า และมีสคริปต์ช่วยตั้งค่าในเครื่องด้วย ทั้งหมดเป็นโอเพนซอร์สหรือใช้ฟรี
    ถ้าคุณแก้ ~/.npmrc เองได้ก็อาจไม่จำเป็น แต่สำหรับคนรอบตัวที่ต้องการวิธีแก้แบบคลิกเดียว มันน่าจะช่วยให้รอดจากการโจมตีครั้งถัดไปได้
    เพียงแต่เวลาต้องแพตช์ CVE ร้ายแรงตัวใหม่ ก็ต้องมีวิธีข้าม cooldown ซึ่งแต่ละตัวก็มีวิธีข้ามของมันเอง ไม่มีตัวเลขที่แม่นยำ แต่ในช่วงไม่กี่สัปดาห์ที่ผ่านมา ดูเหมือนความเสี่ยงจาก การโจมตีซัพพลายเชนซอฟต์แวร์ จะมากกว่า CVE zero-day ตัวใหม่

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

      Disclaimer: I maintain depsguard

    • ไม่แน่ใจว่า cooldown จะได้ผลจริงแค่ไหน ยังไงก็ต้องมีคนสักคนข้าม cooldown ไปติดตั้งรีลีสที่อาจมีปัญหาแล้วเป็นคนเจอปัญหา ถ้าไม่มีใครทำ ก็แค่ทำให้ปัญหาช้าลง 3/7/10/14 วันเท่านั้น
      แต่พอพิมพ์ไปก็คิดเพิ่มว่า ถึงอย่างนั้นผมก็เห็นด้วยกับ cooldown 10 วัน ที่จะไม่ติดตั้งอะไรที่ออกมาในช่วง 10 วันที่ผ่านมา เพียงแต่ไม่ควรคาดหวังว่านี่จะเป็นมาตรการบรรเทาเพียงอย่างเดียว
    • ทำไมไม่ทำดิสโทรหรือช่องทางแยกแบบ Linux อย่าง latest/stable/LTS ไปเลย?
  • สงสัยว่า Go หรือ Rust ให้การรับประกันอะไรจริง ๆ มากกว่า Python/npm บ้าง หรือจริง ๆ แล้ว Python/npm แค่เป็นเป้าหมายที่ล่อตาล่อใจกว่า
    ตอนนี้ยิ่งพยายามหลีกเลี่ยงแพ็กเกจ third-party ทั้งหมดมากขึ้นเรื่อย ๆ

    • การกำหนดความเป็นเจ้าของแพ็กเกจและ namespace ขึ้นอยู่กับ ผู้ดูแลแพ็กเกจแมเนเจอร์ 100%
      Maven Central มีมาหลายสิบปีแล้ว แต่เหตุการณ์ขโมย namespace เกิดขึ้นน้อยมาก
      คุณจะอัปโหลดแพ็กเกจด้วย groupId com.ycombinator ไม่ได้ ถ้าไม่มีการยืนยันว่าคุณเป็นเจ้าของโดเมน ycombinator.com และเมื่อแพ็กเกจถูกอัปโหลดแล้ว มันจะ immutable 100% แม้จะมีโค้ดอันตรายอยู่ข้างในก็ตาม แน่นอนว่าไลบรารีแบบนั้นจะถูกติดป้ายว่าเปราะบางในหลายที่
      ผมไม่เข้าใจว่า NPM ใช้เวลานานขนาดนี้แล้วยังลอกมาตรการป้องกันแบบ Maven Central ไม่ได้อย่างไร
    • ประเด็นหลักอย่างหนึ่งของบทความคือ ภาษาอื่นยอดนิยมส่วนใหญ่มี standard library ที่ค่อนข้างครบถ้วน ส่วน standard library ของ JS เล็กจนน่าตกใจ
      แทนที่จะมีชุดไลบรารีที่ผ่านการตรวจสอบและมากับภาษา แอปพลิเคชันกลับต้องเขียนเองหรือดึงมาจากคลังแพ็กเกจ third-party และเพราะเราถูกสอนมาตลอดให้หลีกเลี่ยง NIH ผู้คนเลยมักหยิบแพ็กเกจมาใช้
      มันไม่ใช่เรื่องแย่เสมอไป แต่บ่อยครั้งก็ดึงโค้ดเข้ามามากเกินความจำเป็น ระบบนิเวศ JS ยังนิยมโมดูลเล็ก ๆ จึงต้องใช้หลายโมดูล และทุกคนก็ซ้อนทับกันต่อไปจนกราฟ dependency ใหญ่มหาศาล ไม่ว่าจะตั้งใจหรือไม่ พื้นที่เสี่ยงต่อปัญหาก็มหาศาลเกินไป
      ภาษาอื่นมีของที่ให้มาพร้อมใช้มากกว่า ไม่ใช่ว่าไม่เคยมีบั๊กหรือปัญหาความปลอดภัย แต่เมื่อเทียบกับที่เห็นในระบบนิเวศ JS แล้วถือว่าน้อยมาก กราฟ dependency ภายนอกก็เล็กกว่ามาก และฟังก์ชันหลักก็มาจาก third party ที่เชื่อถือได้
    • ผู้โจมตีไปที่ที่มีเหยื่ออยู่ ฝั่งฟรอนต์เอนด์แทบจะเป็นวัฒนธรรมเดียวที่ใช้ NPM กันเป็นส่วนใหญ่ ส่วนแบ็กเอนด์ยังไม่เป็นแบบนั้นมากนัก
      นี่ไม่ใช่ข้อแก้ตัวให้ NPM กลับยิ่งเป็นอีกปัจจัยที่ทำให้ NPM เสียเปรียบ
      จะบอกว่านี่สะท้อนความต่างระหว่างนักพัฒนาฟรอนต์เอนด์กับแบ็กเอนด์ได้ชัดขึ้นอีกก็ได้ แต่ผมจะไม่ไปไกลถึงขั้นนั้น
    • เอาจริง ๆ Rust ก็มี รูปแบบการโจมตีซัพพลายเชน แบบเดียวกันเป๊ะ แค่มันใหม่กว่าและตอนนี้ยังถูกดูแลดีกว่าเท่านั้น รออีก 10 ปีก็รู้
    • ล่าสุดที่ผมเช็ก npm มี 2FA สำหรับการ publish แต่ cargo ไม่มี ผมไม่คิดว่า cargo ดีกว่า npm เป็นพิเศษ มันแค่ยังไม่ใช่เป้าหมายที่น่าดึงดูดเท่าไร
  • หลายที่ทำงานของผมต้องลำบากกับการติดตั้งค่าตั้งต้น npm แบบปลอดภัยระดับ global ลงในเครื่องนักพัฒนาทุกคน ขอร้องไม่ให้ปิด และใช้เครื่องมือ MDM คอยตรวจสอบ
    ค่าตั้งต้นที่ปลอดภัยกว่า ควรมีมาตั้งนานแล้ว

    • ก็แค่ไม่ใช้ npm ใช้แพ็กเกจแมเนเจอร์ที่ไม่รัน postinstall เป็นค่าเริ่มต้น และการย้ายไปใช้นั้นง่ายจนน่าเหลือเชื่อ
    • สงสัยว่าค่าตั้งต้นที่ปลอดภัยหมายถึงอะไร ถ้าหมายถึงการบังคับ cooldown หรือ allow/block list ของแพ็กเกจ แนวทางที่ถูกต้องคือบริษัทควรตั้งรีโพซิทอรีที่ควบคุมเอง เพื่อดึงจาก upstream npm registry พร้อมบังคับใช้นโยบายที่ต้องการ
  • ไม่มีเหตุผลที่ชอบธรรมที่ postinstall script ควรมีอยู่ ทีม npm ควรโตพอแล้วที่จะประกาศว่า “ตั้งแต่ npm เวอร์ชันใดก็ตาม จะรัน postinstall script เฉพาะกับเวอร์ชันแพ็กเกจที่ถูก publish ก่อน ${today} เท่านั้น”

    • ช่วงหลังผม audit postinstall script ของแพ็กเกจยอดนิยมหลายตัว ส่วนใหญ่ทำเรื่องใช้หรือดาวน์โหลด ไบนารีเนทีฟ, ตรวจจับความเข้ากันได้ของแพลตฟอร์ม, เชื่อมต่อเองแทนที่จะปล่อยให้ Node bootstrap ให้, และหลบปัญหาของ npm เวอร์ชันเก่า
      เพราะ toolchain ฝั่ง dev อย่าง esbuild ถูกเขียนด้วยภาษาแบบคอมไพล์แล้วแจกเป็นไบนารีผ่าน npm registry ถ้าคุณใช้ Node/npm รุ่นใหม่และ OS/แพลตฟอร์มยอดนิยมที่ค่อนข้างใหม่ ก็น่าจะปิด postinstall script ทั้งหมดได้โดยไม่เกิดปัญหาที่ชอบธรรม
    • install script ก็เหมือน package signing ตรงที่เป็น สิ่งดึงความสนใจออกจากประเด็น ต่อให้เพิ่มหรือลบฟีเจอร์ไหน ก็แทบไม่กระทบศักยภาพการกลายเป็นหนอนของระบบนิเวศแพ็กเกจนี้มากนัก
      โค้ด npm ที่ติดตั้งแล้วแทบทั้งหมดก็ถูกนำไปรันอยู่ดี
    • ความจริงที่ว่าแพ็กเกจ Rust สามารถ ถูกรันโดยไม่มี sandbox ตอน build ได้ ก็ไม่ได้มีเหตุผลรองรับมากนักเช่นกัน
    • แบบนี้ก็ยังไม่ได้แก้ปัญหาจริง ๆ เพราะโค้ดในแพ็กเกจก็ถูกรันตอน build และตอนทดสอบอยู่ดี อาจลดขอบเขตได้เล็กน้อย แต่ก็แค่นั้น
    • ถ้าจะพูดอย่างระวัง postinstall script แทบจะเป็น ประเด็นลวงตา คนแค่ตกใจที่โค้ดซึ่งคนอื่นควบคุมสามารถถูกรันบนคอมพิวเตอร์ตัวเองและทำเรื่องแย่ ๆ ได้ ซึ่งก็ใช่ มันทำได้
      แต่โค้ดปกติภายในแพ็กเกจก็เหมือนกัน ถึงจะไม่ถูกรันตอนติดตั้ง แต่สุดท้ายอะไรบางอย่างข้างในก็ต้องถูกรัน ไม่อย่างนั้นมันก็คงไม่ถูกใส่เป็น dependency ตั้งแต่แรก
      การคิดว่าการเอา postinstall script ออกจะส่งผลต่ออัตราการถูกโจมตีได้มากกว่าชั่วครู่ เป็นสัญญาณว่ายังคิดปัญหานี้ไม่สุด น่าเสียดายที่เรื่องนี้ซับซ้อนกว่าที่บทความต้นฉบับชวนให้คิดมาก
      มันไม่ใช่ปัญหาแบบ “อย่าเอาปุ่มปล่อยปีกเครื่องบินไปไว้ข้างสวิตช์ไฟ” แต่แก่นจริง ๆ คือเราไม่มีวิธีแยก “โค้ดแย่ของคนอื่นที่เราไม่อยากให้มารันบนเครื่องเรา” ออกจาก “โค้ดดีของคนอื่นที่เราอยากให้มารันบนเครื่องเรา” ได้เลย ถ้าไม่ใช้แรงคนจำนวนมากตรวจด้วยมือ และเหตุผลที่เรายอมรันโค้ดคนอื่นก็เพื่อหลีกเลี่ยงงานตรวจด้วยมือนั่นเอง
  • ทุกโปรเจกต์ Node.js เริ่มต้นด้วย npm install แล้วจู่ ๆ ก็มี แพ็กเกจ 500 ตัว โผล่มา ทั้งที่ครึ่งหนึ่งไม่มีใครแตะมาหลายปีแล้ว

  • มี ปัญหาเชิงวัฒนธรรม ที่อยากอัปทุกอย่างให้เป็นแพ็กเกจใหม่ล่าสุด ทั้งที่ของเดิมก็ทำงานดีอยู่แล้ว บางทียังไม่อ่าน changelog ด้วยซ้ำว่าการเปลี่ยนนั้นเกี่ยวข้องไหม
    cooldown เป็นแค่วิธีบังคับให้ผู้ดูแลโครงการอดทนขึ้นอีกนิด และมันก็ได้ผลจริง

    • ถ้ามีข้อกำหนดด้าน compliance ก็ต้องอัปเดตเพราะช่องโหว่ CVE ที่ถาโถมใส่เวอร์ชันเก่า ส่วนใหญ่แทบเป็นของปลอมประเภท “regex DoS” แต่ก็ต้องทำตามขั้นตอนอยู่ดีจึงต้องอัปเดต
    • แล้วก็มีกรณีที่เจ้าของแพ็กเกจอัปเดตของที่ไม่จำเป็นต้องอัปเดต แค่ไม่อยากให้ดูเก่าและถูกทิ้ง
      แพ็กเกจ Lisp ใช้แบบไม่เปลี่ยนอะไรมา 15 ปีก็ยังได้ แต่แพ็กเกจ JS ถ้าไม่ได้ดูแลจะถูกมองเหมือนเป็นเรื่องใหญ่ ทั้งที่จริงมันอาจเสร็จสมบูรณ์ตั้งแต่ 15 ปีก่อนแล้ว แต่เพื่อให้ดูเหมือนยังมีการดูแลบน npm และ GitHub ก็เลยออกเวอร์ชันใหม่ทั้งที่ไม่ได้เพิ่มอะไร หรือบางทีก็ใส่ breaking change เข้าไปด้วย สุดท้ายทุกอย่างก็ต้องอัปเดตตาม
  • cooldown 7 วัน ดูเหมือนมาตรการเฉพาะหน้าที่ติดได้ด้วยแรงน้อย ทางแก้จริงคงเป็น reproducible builds กับ signed attestations แต่ทีมส่วนใหญ่คงไม่ยอมจ่ายต้นทุนนี้จนกว่าจะโดนเข้ากับตัวก่อน

  • อ่านแล้วเหมือนบทความของ Onion มาก

    residents of the Node.js ecosystem stood unified in their belief that the malicious remote-code execution was a completely unpredictable tragedy
    มีคนเชื่อประโยคนี้จริง ๆ หรือ? ตัวอย่างโต้แย้งมีเยอะเกินไป
    มันเป็นงานเสียดสีที่แทงใจเรื่องความล้มเหลวของระบบนิเวศได้ดี แต่สุดท้ายก็เป็นแค่ความบันเทิง อาจกลายเป็นช่องให้พวกนักการตลาดเอาของตัวเองมาโปรโมตก็ได้ อย่างกรณีผู้ดูแล depsguard ที่ลบแล้วใส่กลับเข้าไป แล้วก็ลบอีกว่าตัวเองเป็นใครในบทความของตัวเอง ตอนที่ผมเขียนนี้ โพสต์นั้นอยู่บนสุดพอดี

  • ลิงก์นี้เป็นเวอร์ชันที่เอามุกที่ Xe Iaso เล่นมานานไป ฟอกด้วย AI แบบเห็นชัด เสียดาย
    https://xeiaso.net/shitposts/no-way-to-prevent-this/CVE-2024...
    https://news.ycombinator.com/item?id=40438408