รูปแบบใหม่ของการรักษาความปลอดภัยสัญญา DeFi: มุ่งเน้นไปที่ความไม่แปรผันของโปรโตคอล

金色财经_

สรุป

อย่าเพิ่งเขียนคำสั่ง need สำหรับฟังก์ชันเฉพาะ แต่เขียน need คำสั่งสำหรับโปรโตคอลของคุณ การตรวจสอบการปฏิบัติตามข้อกำหนดของฟังก์ชัน (ข้อกำหนด) - ประสิทธิผล (ผลกระทบ) - การโต้ตอบ (การโต้ตอบ) + ความไม่แปรผันของโปรโตคอล (Iniants) หรือโหมด FREI-PI สามารถช่วยให้สัญญาของคุณมีความปลอดภัยมากขึ้น เนื่องจากเป็นการบังคับให้นักพัฒนามุ่งเน้นไปที่การรักษาความปลอดภัยระดับฟังก์ชัน นอกจากนี้ ระวังด้วย สำหรับค่าคงที่ในระดับโปรโตคอล

แรงจูงใจ

ในเดือนมีนาคม พ.ศ. 2566 Euler Finance ถูกแฮ็กและสูญเสียเงิน 200 ล้านดอลลาร์ ออยเลอร์ไฟแนนซ์เป็นตลาดให้กู้ยืมที่ผู้ใช้สามารถฝากหลักประกันและยืมกับมันได้ มีคุณลักษณะเฉพาะบางอย่าง อันที่จริงแล้วเป็นตลาดให้กู้ยืมที่เทียบได้กับ Compound Finance และ Aave

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

ผู้เริ่มต้นขั้นพื้นฐาน

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

  • เช่นเดียวกับในตลาดการให้ยืม: ผู้ใช้ไม่สามารถดำเนินการใดๆ เพื่อให้บัญชีใดๆ อยู่ในสถานะหลักประกันที่ไม่ปลอดภัยหรือมีความปลอดภัยน้อยกว่า (“ปลอดภัยน้อยกว่า” หมายความว่าบัญชีนั้นต่ำกว่าเกณฑ์ความปลอดภัยขั้นต่ำอยู่แล้ว ดังนั้นจึงไม่สามารถถอนออกได้อีก)
  • ใน AMM DEX: x * y == k, x + y == k เป็นต้น
  • ในการเดิมพันการขุดสภาพคล่อง: ผู้ใช้ควรสามารถถอนจำนวนโทเค็นการเดิมพันที่พวกเขาฝากไว้เท่านั้น

สิ่งที่ผิดพลาดกับ Euler Finance ไม่จำเป็นว่าจะต้องเพิ่มคุณสมบัติ ไม่เขียนการทดสอบ หรือไม่ปฏิบัติตามแนวทางปฏิบัติที่ดีที่สุดแบบดั้งเดิม พวกเขาตรวจสอบการอัปเกรดและทำการทดสอบแล้ว แต่ก็ยังไม่ผ่านช่องโหว่ ปัญหาหลักคือพวกเขาลืมเกี่ยวกับค่าคงที่หลักของตลาดการให้ยืม (เช่นเดียวกับผู้สอบบัญชี!)

*หมายเหตุ: ฉันไม่ได้พยายามจะเลือกออยเลอร์ พวกเขาเป็นทีมที่มีความสามารถ แต่นี่เป็นกรณีล่าสุด *

แก่นแท้ของปัญหา

คุณอาจจะคิดว่า “ใช่แล้ว นั่นเป็นเหตุผลว่าทำไมพวกเขาถึงถูกแฮ็ก พวกเขาลืมคำสั่งที่จำเป็น” ใช่และไม่.

แต่ทำไมพวกเขาถึงลืมคำสั่งร้องขอ?

ตรวจสอบ - ตรวจสอบ - การโต้ตอบไม่ดีพอ

รูปแบบทั่วไปที่แนะนำสำหรับ Solidity Developer คือรูปแบบ Checks-Effects-Interactions มีประโยชน์มากในการกำจัดข้อบกพร่องที่เกี่ยวข้องกับการกลับเข้ามาใหม่ และมักจะเพิ่มจำนวนการตรวจสอบอินพุตที่นักพัฒนาต้องทำ _แต่_ ก็มักจะเกิดปัญหามองไม่เห็นป่าสำหรับต้นไม้

สิ่งที่สอนนักพัฒนาคือ: “ก่อนอื่นฉันเขียนคำสั่งร้องขอของฉัน จากนั้นฉันทำการตรวจสอบ จากนั้นบางทีฉันอาจโต้ตอบใดๆ จากนั้นฉันก็จะปลอดภัย” ปัญหาคือ บ่อยกว่านั้น มันกลายเป็นส่วนผสมของการตรวจสอบและผลกระทบ – ไม่เลวใช่ไหม การโต้ตอบยังคงเป็นที่สิ้นสุด ดังนั้นการกลับเข้ามาใหม่จึงไม่ใช่ปัญหา แต่บังคับให้ผู้ใช้มุ่งเน้นไปที่ฟังก์ชันเฉพาะและการเปลี่ยนสถานะแต่ละสถานะมากกว่าบริบททั่วโลกที่กว้างขึ้น ซึ่งหมายความว่า:

รูปแบบการโต้ตอบตรวจสอบความถูกต้องเพียงอย่างเดียวทำให้นักพัฒนาลืมเกี่ยวกับค่าคงที่หลักของโปรโตคอลของตน

ยังคงเป็นรูปแบบที่ยอดเยี่ยมสำหรับนักพัฒนา แต่ควรรักษาความแปรปรวนของโปรโตคอลไว้เสมอ (จริงๆ แล้วคุณยังควรใช้ CEI อยู่!)

ทำถูกต้อง: โหมด FREI-PI

ยกตัวอย่าง ตัวอย่างนี้จากสัญญา SoloMargin ของ dYdX (ซอร์สโค้ด) ซึ่งเป็นตลาดให้ยืมและสัญญาซื้อขายโดยใช้เลเวอเรจ นี่เป็นตัวอย่างที่ดีของสิ่งที่ฉันเรียกว่ารูปแบบ Function Requirements-Effects-Interactions + Protocol Iniants หรือรูปแบบ FREI-PI

ด้วยเหตุนี้ ฉันจึงเชื่อว่านี่เป็นตลาดการให้กู้ยืมเพียงแห่งเดียวในตลาดการให้กู้ยืมระยะเริ่มต้นที่ไม่มีช่องโหว่ที่เกี่ยวข้องกับตลาด Compound และ Aave ไม่มีปัญหาโดยตรง แต่ส้อมของพวกเขามี และ bZx ถูกแฮ็กหลายครั้ง

ตรวจสอบรหัสด้านล่างและสังเกตสิ่งที่เป็นนามธรรมต่อไปนี้:

  1. ตรวจสอบพารามิเตอร์อินพุต (_verifyInputs)
  2. การกระทำ (การแปลงข้อมูล, การจัดการสถานะ)
  3. ตรวจสอบสถานะสุดท้าย (_verifyFinalState)

Checks-Effects-Interactions ยังคงดำเนินการตามปกติ เป็นที่น่าสังเกตว่าการโต้ตอบการตรวจสอบความถูกต้องกับการตรวจสอบเพิ่มเติมนั้นไม่เทียบเท่ากับ FREI-PI ซึ่งมีความคล้ายคลึงกันแต่มีเป้าหมายที่แตกต่างกันโดยพื้นฐาน ดังนั้น นักพัฒนาควรมองว่าพวกเขาแตกต่างกัน: FREI-PI เป็นนามธรรมที่สูงกว่า มีเป้าหมายที่ความปลอดภัยของโปรโตคอล ในขณะที่ CEI มีเป้าหมายที่ความปลอดภัยในการทำงาน

โครงสร้างของสัญญานี้น่าสนใจมาก - ผู้ใช้สามารถดำเนินการตามที่พวกเขาต้องการ (ฝาก ยืม ซื้อขาย โอน เลิกกิจการ ฯลฯ) ในห่วงโซ่ของการดำเนินการ ต้องการฝาก 3 โทเค็นที่แตกต่างกัน ถอนโทเค็นที่ 4 และชำระบัญชีหรือไม่? เป็นการโทรเพียงครั้งเดียว

นี่คือพลังของ FREI-PI: ผู้ใช้สามารถทำอะไรก็ได้ตามต้องการภายในโปรโตคอล ตราบใดที่ค่าคงที่ของตลาดสินเชื่อหลักยังคงอยู่เมื่อสิ้นสุดการโทร: ผู้ใช้รายเดียวไม่สามารถดำเนินการใดๆ ที่จะทำให้บัญชีใดๆ ไม่ปลอดภัยได้ หรือตำแหน่งหลักประกันที่ไม่ปลอดภัยมากกว่า สำหรับสัญญานี้ ดำเนินการใน _verifyFinalState ตรวจสอบหลักประกันของแต่ละบัญชีที่ได้รับผลกระทบเพื่อให้แน่ใจว่าข้อตกลงนั้นดีกว่าตอนที่เริ่มธุรกรรม

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

FREI-PI ที่มีเอนทิตีเป็นศูนย์กลาง

ปัญหาอีกประการหนึ่งของ FREI-PI คือแนวคิดที่เน้นเอนทิตี ใช้ตลาดการให้กู้ยืมและสมมติค่าคงที่หลักเป็นตัวอย่าง:

ในทางเทคนิคแล้ว นี่ไม่ใช่ค่าคงที่เพียงอย่างเดียว แต่มีไว้สำหรับเอนทิตีผู้ใช้ (ยังคงเป็นค่าคงที่ของโปรโตคอลหลัก และโดยปกติค่าคงที่ของผู้ใช้จะเป็นค่าคงที่ของโปรโตคอลหลัก) โดยทั่วไปแล้วตลาดการให้กู้ยืมจะมีหน่วยงานเพิ่มเติมอีก 2 แห่ง:

  • ออราเคิล
  • การจัดการ / การกำกับดูแล

การเปลี่ยนแปลงไม่ได้เพิ่มเติมทุกรายการทำให้รับประกันโปรโตคอลได้ยากขึ้น ดังนั้นยิ่งน้อยยิ่งดี นี่คือสิ่งที่ Dan Elitzer พูดไว้ในบทความของเขาที่ชื่อว่า: Why DeFi is Broken and How to Fix It #1 Oracle-less Protocol (คำใบ้: บทความไม่ได้บอกว่า oracles เป็นปัญหา)

##ออราเคิล

สำหรับนักทำนาย ให้ใช้ประโยชน์จาก Cream Finance มูลค่า 130 ล้านดอลลาร์ ความไม่เปลี่ยนรูปหลักของเอนทิตี oracle:

ปรากฎว่า การตรวจสอบ oracles ขณะรันไทม์ด้วย FREI-PI นั้นยุ่งยาก แต่สามารถทำได้ด้วยความรอบคอบ โดยทั่วไปแล้ว Chainlink เป็นตัวเลือกที่ดีที่จะพึ่งพาเป็นส่วนใหญ่ ซึ่งตอบสนองความเปลี่ยนรูปส่วนใหญ่ไม่ได้ ในกรณีที่พบไม่บ่อยของการจัดการหรือความประหลาดใจ การมีการป้องกันที่ลดความยืดหยุ่นเพื่อสนับสนุนความถูกต้องอาจเป็นประโยชน์ (เช่น การตรวจสอบว่าค่าที่ทราบล่าสุดนั้นมากกว่าค่าปัจจุบันไม่กี่เปอร์เซ็นต์) นอกจากนี้ ระบบ SoloMargin ของ dYdX ยังทำงานได้ดีกับ DAI oracle ของพวกเขา นี่คือรหัส (ถ้าคุณไม่สามารถบอกได้ ฉันคิดว่ามันเป็นระบบสัญญาอัจฉริยะที่ซับซ้อนที่สุดเท่าที่เคยเขียนมา)

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการประเมินของออราเคิลและการเน้นความสามารถของทีมออยเลอร์ พวกเขาได้เขียนบทความดีๆ เกี่ยวกับการจัดการราคาออราเคิล Uniswap V3 TWAP ด้วยคอมพิวเตอร์

การบริหาร / การกำกับดูแล

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

โดยพื้นฐาน ค่าคงที่หลักของเอนทิตีที่ได้รับการจัดการอาจเป็น:

การตีความ: ผู้ดูแลระบบสามารถทำสิ่งต่างๆ ที่ไม่ควรจบลงด้วยการไม่ทำลายค่าคงที่ เว้นแต่ว่าพวกเขาจะเปลี่ยนแปลงสิ่งต่างๆ อย่างมากเพื่อปกป้องเงินของผู้ใช้ (เช่น การย้ายสินทรัพย์ไปยังสัญญาช่วยเหลือคือการลบค่าคงที่) นอกจากนี้ ผู้ดูแลระบบควรได้รับการพิจารณาว่าเป็นผู้ใช้ ดังนั้น ค่าคงที่ของผู้ใช้ในตลาดการให้ยืมหลักควรถือไว้สำหรับพวกเขาด้วย (หมายความว่าพวกเขาไม่สามารถโจมตีผู้ใช้รายอื่นหรือโปรโตคอล) ขณะนี้ การดำเนินการบางอย่างของผู้ดูแลระบบไม่สามารถตรวจสอบในขณะรันไทม์ผ่าน FREI-PI ได้ แต่ด้วยค่าคงที่ที่เพียงพอในที่อื่น หวังว่าปัญหาส่วนใหญ่จะลดลง ฉันพูดในขณะนี้ เพราะใคร ๆ ก็สามารถจินตนาการได้ว่าใช้ระบบพิสูจน์ zk ที่อาจตรวจสอบสถานะทั้งหมดของสัญญา (ต่อผู้ใช้ ต่อ oracle ฯลฯ)

เป็นตัวอย่างของการที่ผู้ดูแลระบบทำลายการไม่เปลี่ยนรูป ให้ดำเนินการจัดการแบบผสมผสานที่ทำให้ตลาด cETH หยุดชะงักในเดือนสิงหาคม 2022 โดยพื้นฐานแล้ว การอัปเกรดนี้ทำลายความสามารถในการเปลี่ยนแปลงไม่ได้ของ Oracle: Oracle ให้ข้อมูลแบบเรียลไทม์ที่แม่นยำและ (ค่อนข้าง) เนื่องจากไม่มีฟังก์ชันการทำงาน Oracle สามารถให้ข้อมูลที่ไม่ถูกต้องได้ การตรวจสอบ FREI-PI แบบรันไทม์ การตรวจสอบว่า Oracle ที่ได้รับผลกระทบสามารถให้ข้อมูลแบบเรียลไทม์ สามารถป้องกันไม่ให้สิ่งนี้เกิดขึ้นกับการอัปเกรด สิ่งนี้สามารถรวมเข้ากับ _setPriceOracle เพื่อตรวจสอบว่าสินทรัพย์ทั้งหมดได้รับข้อมูลแบบเรียลไทม์หรือไม่ สิ่งที่ดีเกี่ยวกับ FREI-PI สำหรับบทบาทผู้ดูแลระบบคือ บทบาทของผู้ดูแลระบบค่อนข้างไม่อ่อนไหวต่อราคา (หรืออย่างน้อยควรเป็น) ดังนั้นการใช้ก๊าซมากขึ้นจึงไม่ใช่ปัญหาใหญ่

ความซับซ้อนเป็นสิ่งที่อันตราย

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

ทำไม Uniswap ไม่เคยถูกแฮก (น่าจะ)

AMM สามารถมีค่าคงที่พื้นฐานที่ง่ายที่สุดของ DeFi ดั้งเดิม: tokenBalanceX * tokenBalanceY == k (เช่น รุ่นผลิตภัณฑ์คงที่) ทุกฟังก์ชันใน Uniswap V2 จะหมุนรอบค่าคงที่ง่ายๆ นี้:

  1. มิ้นท์: เพิ่มใน k
  2. เบิร์น: ลบออกจาก k
  3. สลับ: โอน x และ y แต่เก็บ k ไว้
  4. Skim: ปรับ tokenBalanceX * tokenBalanceY ใหม่เพื่อให้เท่ากับ k และลบส่วนที่ซ้ำซ้อนออก

ความลับด้านความปลอดภัยของ Uniswap V2: แกนหลักคือความไม่เปลี่ยนรูปที่เรียบง่าย และฟังก์ชันทั้งหมดมีให้บริการ เอนทิตีอื่นๆ เพียงอย่างเดียวที่สามารถโต้แย้งได้คือธรรมาภิบาล ซึ่งสามารถเปิดสวิตช์ค่าธรรมเนียมได้ ซึ่งไม่แตะต้องการเปลี่ยนแปลงหลัก เป็นเพียงการกระจายความเป็นเจ้าของยอดโทเค็น ความเรียบง่ายในคำสั่งความปลอดภัยของพวกเขาคือเหตุผลที่ Uniswap ไม่เคยถูกแฮ็ก ความเรียบง่ายไม่ได้เป็นการดูหมิ่นสำหรับนักพัฒนาที่ยอดเยี่ยมของสัญญาอัจฉริยะของ Uniswap ตรงกันข้าม ต้องใช้วิศวกรที่ยอดเยี่ยมเพื่อค้นหาความเรียบง่าย

##ปัญหาแก๊ส

Twitter ของฉันเต็มไปด้วยเสียงกรีดร้องของผู้เพิ่มประสิทธิภาพที่แสดงความสยองขวัญและความเจ็บปวดว่าการตรวจสอบเหล่านี้ไม่จำเป็นและไม่มีประสิทธิภาพ สองสิ่งเกี่ยวกับคำถามนี้:

  1. คุณรู้หรือไม่ว่ามีอะไรอีกบ้างที่ไม่มีประสิทธิภาพ? ต้องส่งข้อความถึง Laurence แฮ็กเกอร์ชาวเกาหลีเหนือผ่าน etherscan โอนเงินโดยใช้ ETH และขู่ว่า FBI จะเข้าแทรกแซง
  2. คุณอาจได้โหลดข้อมูลทั้งหมดที่คุณต้องการจากที่เก็บข้อมูลแล้ว ดังนั้นเมื่อสิ้นสุดการโทร ให้เพิ่มการตรวจสอบที่จำเป็นเล็กน้อยลงในข้อมูลด่วน คุณต้องการให้ข้อตกลงของคุณเสียค่าธรรมเนียมเล็กน้อยหรือปล่อยให้มันตายไป?

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

สิ่งนี้มีความหมายกับฉันอย่างไร

ในฐานะนักพัฒนา สิ่งสำคัญคือต้องกำหนดและแสดงค่าคงที่หลักตั้งแต่เนิ่นๆ ในกระบวนการพัฒนา ตามคำแนะนำที่เป็นรูปธรรม: ฟังก์ชันแรกในการเขียนด้วยตัวคุณเองคือ _verifyAfter เพื่อตรวจสอบค่าคงที่ของคุณหลังจากการเรียกใช้สัญญาของคุณทุกครั้ง ใส่ไว้ในสัญญาของคุณและปรับใช้ที่นั่น เสริมค่าคงที่ที่ไม่แปรเปลี่ยนนี้ (และค่าคงที่อื่นที่มีเอนทิตีเป็นศูนย์กลาง) ด้วยการทดสอบค่าคงที่ที่กว้างขึ้นซึ่งมีการตรวจสอบก่อนการใช้งาน (คู่มือ Foundry)

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

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

สรุปแล้ว

นอกเหนือจากตัวย่อที่ติดหู (FREI-PI) หรือชื่อสคีมา บิตที่สำคัญจริงๆ คือ:

ค้นหาความเรียบง่ายในการไม่เปลี่ยนแปลงหลักของโปรโตคอลของคุณ และทำงานอย่างหนักเพื่อให้แน่ใจว่ามันจะไม่ถูกทำลาย (หรือถูกจับได้ก่อนที่มันจะถูกทำลาย)

ดูต้นฉบับ
news.article.disclaimer
แสดงความคิดเห็น
0/400
ไม่มีความคิดเห็น