10 คะแนน โดย GN⁺ 2024-11-05 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • การคำนึงถึงความปลอดภัยระหว่างเขียนโค้ด Go เป็นงานที่ซับซ้อน
  • บทความนี้นำเสนอแนวปฏิบัติที่เป็นรูปธรรมหลายข้อ ซึ่งหากนำไปใช้อย่างต่อเนื่องจะช่วยให้เขียนโค้ดที่แข็งแกร่ง ปลอดภัย และมีประสิทธิภาพสูงได้

อัปเดตเวอร์ชัน Go ให้เป็นปัจจุบันเสมอ

  • ต้องคงเวอร์ชัน Go ที่ใช้ในโปรเจ็กต์ให้เป็นเวอร์ชันล่าสุด
  • แม้จะไม่ได้ใช้ฟีเจอร์ภาษาใหม่ล่าสุด การอัปเกรดเวอร์ชัน Go ก็ยังช่วยให้ได้รับแพตช์ความปลอดภัยทั้งหมดสำหรับช่องโหว่ที่ค้นพบแล้ว
  • Go เวอร์ชันใหม่ยังช่วยรับประกันความเข้ากันได้กับ dependency รุ่นล่าสุด
  • สามารถตรวจสอบได้จากเว็บไซต์ประวัติการออกรีลีสของ Go ว่ารีลีสใดแก้ปัญหาความปลอดภัยและ CVE อะไรบ้าง แล้วอัปเดตเป็นเวอร์ชันล่าสุดในไฟล์ go.mod ของโปรเจ็กต์
  • หลังอัปเกรดเวอร์ชัน Go แล้ว ควรตรวจสอบว่าไม่มีปัญหาเรื่องความเข้ากันได้และ dependency
  • สามารถใช้ตัววิเคราะห์โค้ดแบบสแตติกเพื่อประเมินคุณภาพและความปลอดภัยของโค้ดได้

vet

  • วิเคราะห์โค้ด Go ได้ด้วยคำสั่ง go vet ที่ Go มีมาให้ในตัว
  • หากรันคำสั่ง go vet โดยไม่ส่งอาร์กิวเมนต์ จะทำงานด้วยตัวเลือกเริ่มต้นที่อนุญาตทั้งหมด
  • จะสแกนซอร์สโค้ดและรายงานปัญหาที่อาจเกิดขึ้น
  • ปัญหาที่พบบ่อยที่สุดได้แก่ ความผิดพลาดเกี่ยวกับ goroutine, ตัวแปรที่ไม่ได้ใช้งาน, และส่วนของโค้ดที่ไม่สามารถเข้าถึงได้

staticcheck

  • Staticcheck ซึ่งเป็น linter จาก third party ช่วยค้นหาบั๊ก ตรวจจับปัญหาด้านประสิทธิภาพ และบังคับใช้สไตล์ของภาษา Go
  • อธิบายปัญหาที่พบและเสนอแนวทางแก้ไขพร้อมตัวอย่าง
  • นอกจากรันใน CI pipeline แล้ว ยังติดตั้งเป็นไฟล์ปฏิบัติการแบบสแตนด์อโลนเพื่อสแกนโค้ดบนเครื่องโลคัลได้
  • ตรวจสอบเวอร์ชันที่ติดตั้งและยืนยันว่าพร้อมสำหรับการรันสแกน
  • หากรันโดยไม่ส่งอาร์กิวเมนต์ จะเรียกใช้ตัววิเคราะห์โค้ดทั้งหมดโดยค่าเริ่มต้น
  • ดูตัวอย่างสิ่งที่สามารถตรวจพบได้ใน GitHub repository ของ NGINX Agent
  • ผลการสแกนสามารถแบ่งได้เป็น 3 กลุ่ม ได้แก่ แพ็กเกจ/เมธอด/ฟังก์ชันที่ deprecated, ตัวแปร/ฟิลด์ที่ไม่ได้ใช้งาน, และปัญหาที่เกี่ยวกับคุณภาพโค้ด

golangci-lint

  • ติดตั้ง golangci-lint ได้ด้วยคำสั่ง go install
  • ตรวจสอบเวอร์ชันเพื่อยืนยันว่าติดตั้งเรียบร้อยแล้ว
  • หากเรียกใช้โดยไม่ส่งอาร์กิวเมนต์ จะรัน linter ทั้งหมด
  • ตรวจดูว่ามีคำเตือนและข้อเสนอแนะใดบ้างใน repository agent ที่โคลนไว้ก่อนหน้านี้
  • linter จะระบุไฟล์และบรรทัดที่เกี่ยวข้องได้อย่างแม่นยำ
  • ประเมินโค้ดและแก้ไข จากนั้นรัน linter อีกครั้งและรัน unit test ทั้งหมด
  • หากการทดสอบผ่าน ก็ commit โค้ดที่อัปเดตแล้วและ push ขึ้นรีโมต

การตรวจจับ Race Condition

  • Race condition อาจเกิดขึ้นเมื่อหลาย goroutine พยายามเข้าถึงทรัพยากรเดียวกันพร้อมกัน
  • จะถูกตรวจจับเมื่อมีอย่างน้อยหนึ่ง goroutine พยายามแก้ไขทรัพยากรนั้น
  • Go รองรับการทดสอบสถานะลักษณะนี้โดยตรงผ่านเครื่องมือ test ร่วมกับอาร์กิวเมนต์ -race
  • ตัวตรวจจับ race จะประเมินเฉพาะโค้ดที่ถูกรันจริง และจะมองข้ามเส้นทางโค้ดที่ไม่ถูกรัน ดังนั้นจึงควรรันตัววิเคราะห์โค้ดแบบสแตติกก่อนเพื่อให้แน่ใจว่าไม่มี dead code
  • การรันทดสอบแบบขนานจะเพิ่มโอกาสในการตรวจพบปัญหาที่เกี่ยวข้องกับ concurrency

การสแกนซอร์สโค้ดหาช่องโหว่

govulncheck

  • เครื่องมือสำหรับสแกนโค้ดเบสเพื่อหาช่องโหว่ที่ทราบแล้วซึ่งอยู่ในฐานข้อมูล CVEs
  • พัฒนาโดยทีม Go และมีฐานข้อมูลเฉพาะด้านช่องโหว่ของ Go เป็นแหล่งข้อมูลให้ตัวสแกน
  • ติดตั้งเวอร์ชันล่าสุดแล้วลองใช้งานฟังก์ชันพื้นฐาน
  • โคลน repository habit แล้วรันเครื่องมือจากไดเรกทอรีราก
  • ไม่พบช่องโหว่
  • หากสแกนไฟล์ไบนารี อาจพบช่องโหว่อื่นเพิ่มเติมได้
  • อัปเกรดเวอร์ชัน Go ให้ล่าสุด ดึง dependency มาให้ครบ แล้วตรวจสอบว่าซอฟต์แวร์และ dependency ไม่มี CVE

gosec

  • ตัววิเคราะห์โค้ดแบบสแตติกที่ช่วยค้นหาการตั้งค่าโค้ดที่ไม่ปลอดภัย
  • สามารถรันได้ทั้งบนระบบโลคัลหรือใน CI pipeline ผ่าน GitHub Action
  • มีตัวเลือกและรายการกฎสำหรับตั้งค่าการสแกนที่หลากหลาย
  • โคลน GitHub repository ที่มีโค้ด Go ที่ต้องการสแกน แล้วเริ่มสแกนจากไดเรกทอรีราก
  • ในรายงานการสแกน สามารถดูรายการปัญหาที่อาจเกิดขึ้นซึ่งจัดเรียงตามระดับความรุนแรงและความน่าเชื่อถือได้
  • ตรวจสอบ CWE ที่ถูกรายงานและศึกษารายละเอียดเพิ่มเติมเกี่ยวกับจุดอ่อนที่ระบุไว้

Fuzzing

  • วิธีสุดท้ายในการตรวจสอบคุณภาพโค้ดและค้นหาช่องโหว่
  • เป็นการทดสอบอัตโนมัติแบบเฉพาะทางที่ใช้ code coverage ของการทดสอบเพื่อปรับแต่งข้อมูลนำเข้าแบบสุ่มที่สร้างขึ้น
  • มีประโยชน์มากในการค้นหาข้อบกพร่องด้านความปลอดภัยที่อาจเกิดขึ้น เช่น buffer overflow, SQL injection, การโจมตีแบบ DoS, และการโจมตีแบบ XSS
  • เนื่องจากมีการสร้างชุดข้อมูลนำเข้าหลายรูปแบบโดยอัตโนมัติ นักพัฒนาจึงไม่จำเป็นต้องคิดชุดข้อมูลอินพุตนับร้อยหรือนับพันแบบด้วยตนเอง

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

 
GN⁺ 2024-11-05
ความเห็นบน Hacker News
  • govulncheck เป็นเครื่องมือที่ตรวจสอบได้ว่าโค้ดที่มีช่องโหว่นั้นถูกเข้าถึงใช้งานจริงหรือไม่ จึงมีประโยชน์กว่าการตรวจสอบ dependency ของโปรแกรมเพียงอย่างเดียว
  • ควรอย่าลืมอ้างอิงโปรเจ็กต์ capslock ของ Google ด้วย
  • มีทิปที่เป็นประโยชน์เกี่ยวกับ go vet และ go test -race
  • Go ไม่ได้ปลอดภัยด้านหน่วยความจำ แต่เขียนโค้ดให้ปลอดภัยได้ง่ายกว่าภาษาอื่น
    • ด้วยไวยากรณ์ที่ชัดเจนของ Go จึงทำให้เข้าใจการทำงานของฟังก์ชันและโครงสร้างข้อมูลได้ง่าย
    • เหตุผลที่เครื่องมือ AI ทำงานกับ Go ได้ดี ก็เพราะบริบทภายในฟังก์ชันมีความชัดเจน
  • Semgrep เป็นเครื่องมือที่ยอดเยี่ยมซึ่งทำการตรวจสอบภาษาและเฟรมเวิร์กทั่วไปผ่าน static analysis
    • สามารถดู open rules ของ Semgrep ได้บน GitHub
  • มีการตั้งคำถามเกี่ยวกับชื่อเสียงด้านความปลอดภัยของ Go
    • โดยทั่วไปมองว่า Go ปลอดภัยและเสถียร และอยู่ในระดับใกล้เคียงกับเครื่องมืออื่นอย่าง .NET
  • เพิ่งได้รู้จัก gosec
  • จากการดูแลรักษาแอป Go มา 9 ปี พบว่าสามารถอัปเกรดเวอร์ชัน Go และโมดูลได้อย่างง่ายดาย
    • GitHub จะแจ้งช่องโหว่ให้อัตโนมัติ และใน 99% ของกรณีก็ทำงานได้โดยไม่ต้องแก้ไขอะไร
  • จริง ๆ แล้ว Go ไม่ได้ปลอดภัยด้านหน่วยความจำ
    • มีการรับประกัน atomicity เฉพาะกับค่าที่มีขนาดเท่ากับหนึ่ง word เท่านั้น ส่วนค่าที่มีขนาดสอง word เช่น interface pointer หรือ slice อาจทำลายความปลอดภัยของหน่วยความจำในการทำงานพร้อมกันได้
  • Go นั้นดี แต่ช่วงหลังเมื่อมีการใช้ generics มากขึ้น ความสามารถในการอ่านโค้ดกลับลดลง
    • ทำให้อ่านยากกว่าโค้ด Go แบบเดิมที่แทบไม่ได้ใช้ generics