เรียนรู้วิธีการป้องกันการปฏิเสธการโจมตี (DOS) ในสัญญาอัจฉริยะโดยมั่นใจว่าคิวมีความปลอดภัยจัดการโทเค็นทศนิยมต่ำและจัดการการโทรภายนอกอย่างปลอดภัย
ยินดีต้อนรับกลับสู่ซีรีย์ Resolution รายการตรวจสอบ Solodit เราจะสำรวจรายการตรวจสอบ การตรวจสอบสัญญา Solodit Smart โดยมุ่งเน้นไปที่กลยุทธ์การปฏิบัติสำหรับการเขียน สัญญาอัจฉริยะ ที่ปลอดภัยและยืดหยุ่น
รายการตรวจสอบนี้ช่วยให้คุณระบุช่องโหว่ที่อาจเกิดขึ้นและใช้มาตรการรักษาความปลอดภัยเชิงรุก ในส่วนก่อนหน้านี้ " ความละเอียดรายการตรวจสอบ Solodit (1) " เราตรวจสอบรายการตรวจสอบสามรายการ ( รูปแบบการสกัด, จำนวน ธุรกรรม ขั้นต่ำ และบัญชีดำ ) ที่เกี่ยวข้องกับการปฏิเสธการบริการ (DOS) การโจมตีและให้โซลูชั่นสำหรับนักพัฒนา หากคุณยังไม่ได้อ่านฉันขอแนะนำให้ตรวจสอบบทความก่อนดำเนินการต่อ
ในบทความนี้เราจะหารือเกี่ยวกับรายการอื่น ๆ อีกสามรายการในรายการตรวจสอบโดยเน้นการโจมตี DOS อีกครั้ง เราจะดำน้ำในช่อง โหว่การจัดการคิวความ ท้าทายที่เกิดขึ้นจากโทเค็นทศนิยมต่ำ และ ความสำคัญของการจัดการการเรียกสัญญาภายนอกอย่างปลอดภัย
สำหรับประสบการณ์ที่ดีที่สุดให้เปิดแท็ก รายการตรวจสอบ Solodit สำหรับการอ้างอิง
นี่คือสิ่งที่เราจะพูดคุยในวันนี้:
Sol-am-Dosa-4: การปิดกั้นการจัดการคิว : ปัญหานี้เกิดขึ้นเมื่อผู้โจมตีจัดการกับคิวให้หยุดชั่วคราวหรือขัดจังหวะการทำงานของมันส่งผลให้ DOS เราจะดูว่าผู้โจมตีสามารถทำลายคิวการประมวลผลได้อย่างไร
Sol-am-Dosa-5: โทเค็นทศนิยมต่ำ : ปัญหาที่เกิดขึ้นเมื่อจัดการกับโทเค็นที่มีทศนิยมต่ำ การคำนวณโดยเฉพาะการแบ่งสามารถถูกตัดทอนเป็นศูนย์ส่งผลให้เกิดพฤติกรรมที่ไม่คาดคิดและเป็นอันตราย โทเค็นความแม่นยำต่ำเหล่านี้อาจทำให้เกิดปัญหากับการแบ่งจำนวนเต็มดังนั้นจึงรบกวนฟังก์ชั่นหลัก
Sol-Am-Dosa-6: การโทรภายนอกที่ไม่ปลอดภัย : เราจะสำรวจวิธีการพึ่งพาสัญญาภายนอกโดยไม่ต้องจัดการข้อผิดพลาดที่เหมาะสมเพื่อสร้างช่องโหว่ เมื่อความล้มเหลวของการโทรภายนอกไม่ได้รับการจัดการอย่างถูกต้องอาจทำให้สัญญาทั้งหมด ย้อนกลับ
การโจมตีในโลกแห่งความเป็นจริงพิสูจน์ให้เห็นถึง ความเสียหายที่อาจเกิดขึ้น ช่องโหว่เหล่านี้อาจทำให้เกิด โครงการประสบความสูญเสียครั้งใหญ่เนื่องจากความประมาทเลินเล่อเล็กน้อย
รายการตรวจสอบ Solodit จะขึ้นอยู่กับผลการตรวจสอบรายงานความเสี่ยงและเหตุการณ์ในโลกแห่งความเป็นจริง โดยการศึกษารายการตรวจสอบเหล่านี้คุณสามารถ เรียนรู้จากความผิดพลาดที่ผ่านมาและปรับปรุงความปลอดภัยของรหัสของคุณ
ทีนี้มาดูรายการตรวจสอบแต่ละรายการทีละรายการผ่านรหัสตัวอย่าง ตัวอย่างเหล่านี้ง่ายขึ้นเพื่อเน้นช่องโหว่หลัก
ปัญหา : หากสัญญาอัจฉริยะของคุณขึ้นอยู่กับคิวสำหรับการประมวลผลงานผู้โจมตีอาจ จัดการสถานะเฉพาะในคิว เพื่อป้องกันการประมวลผลที่ถูกต้อง
คำถามรายการตรวจสอบ : "ผู้โจมตีสามารถบล็อกหรือป้องกันการประมวลผลคิวเพื่อทำให้เกิดการหยุดทำงานของบริการได้หรือไม่"
วิธีแก้ปัญหา : กลไกการจัดการคิวของคุณต้องใช้ กลไกการจัดการข้อผิดพลาดที่มีประสิทธิภาพและกลไกทางเลือก เพื่อให้แน่ใจว่าปัญหาสามารถดำเนินการต่อไปได้แม้ว่าจะเกิดขึ้น
ตัวอย่าง :
พิจารณาตัวอย่างของการสกัดคิว:
ผู้ใช้ร้องขอการสกัดและธงบางตัวระบุว่าคำขอนั้นใช้งานได้
ผู้โจมตีสามารถใช้ฟังก์ชั่น resetUserStatus
หลังจากการสกัดถูกยึดเพื่อป้องกันการดำเนินการเดียวกันของผู้ใช้รายอื่น
// 易受攻击的函数:可以被利用function resetUserStatus() external { // 任何人在仍然处于队列中的情况下都可以重置他们的状态withdrawalRequested[msg.sender] = false; // 注意:用户没有被移出队列! } // 处理队列中的下一次提取function processNextWithdrawal() external { require(withdrawalQueue.length > currentIndex, "没有可处理的提取"); // 获取下一次提取Withdrawal memory withdrawal = withdrawalQueue[currentIndex]; // 可被攻击者利用:此检查可能会被重置状态所攻击require(withdrawalRequested[withdrawal.user], "提取请求不再有效"); // 处理提取uint256 amount = withdrawal.amount; require(balances[withdrawal.user] >= amount, "余额不足"); // 更新余额balances[withdrawal.user] -= amount; // 重置提取请求withdrawalRequested[withdrawal.user] = false; // 发送资金(bool success, ) = payable(withdrawal.user).call{value:amount}(""); require(success, "资金发送失败"); // 移动到队列中的下一个currentIndex++; }
เพื่อใช้ประโยชน์จากสิ่งนี้ผู้โจมตีสามารถทำสิ่งต่อไปนี้:
resetUserStatus
processNextWithdrawal
จะย้อนกลับทำให้เกิดการโจมตี DOS อย่างต่อเนื่องการเยียวยา :
withdrawalRequested
กับผู้ดูแลระบบปัญหา : โทเค็นที่มีทศนิยมต่ำอาจทำให้เกิด ปัญหาการแบ่งจำนวนเต็มซึ่งจะปัดเศษเป็นศูนย์
ลองนึกภาพสัญญาสตรีมมิ่งโทเค็นที่จัดสรรโทเค็นในช่วงระยะเวลาหนึ่ง หาก tokensPerSecond
เป็นศูนย์เนื่องจากการแบ่งจำนวนเต็มที่มีโทเค็นทศนิยมต่ำฟังก์ชันการจัดสรรจะถูกบล็อก คำถามรายการตรวจสอบ : "โทเค็นทศนิยมต่ำนำไปสู่ DOS หรือไม่" วิธีแก้ปัญหา : ใช้ ตรรกะเพื่อจัดการกับจุดทศนิยมต่ำ เพื่อป้องกันการหยุดชะงักของกระบวนการซื้อขายเนื่องจากข้อผิดพลาดในการปัดเศษ ตัวอย่าง :
พิจารณาสัญญา TokenStream
ที่สตรีมโทเค็นจำนวนหนึ่งเป็นประจำให้กับผู้ใช้โดยที่:
total_tokens
จะต้องถูกโอนไปยังสัญญาtoken_per_second
อาจถูกปัดเป็นศูนย์เพราะเราใช้โทเค็นที่มีจุดทศนิยม 1distributeTokens
จะย้อนกลับ contract TokenStream { IERC20 public token; uint256 public streamDuration; uint256 public tokensPerSecond; constructor(IERC20 _token, uint256 _streamDuration, uint256 _tokensPerSecond) { token = _token; streamDuration = _streamDuration; tokensPerSecond = _tokensPerSecond; } function distributeTokens(address recipient) external { uint256 balance = token.balanceOf(address(this)); uint256 amount = tokensPerSecond * streamDuration; uint256 tokensToSend = amount > balance ? balance : amount; require(tokensToSend > 0, "没有足够的代币进行流送"); token.transfer(recipient, tokensToSend); } } contract LowDecimalToken is ERC20 { constructor() ERC20("LowDecimalToken", "LDT") { _mint(msg.sender, 100000 * (10 ** decimals())); } function decimals() public view virtual override returns (uint8) { return 1; // 模拟小数点为低的代币} }
ในกรณีนี้การทดสอบ testDOSWithLowDecimalTokens
ใน TokenStreamTest
จะถูกย้อนกลับไป
การแก้ไข : ตรวจสอบให้แน่ใจว่าสัญญาจัดการโทเค็นทศนิยมต่ำอย่างถูกต้อง บรรเทาปัญหาที่เกิดจากจำนวนเต็มปัดเศษในระหว่างกระบวนการคำนวณโดยการปรับสัดส่วนสูตรทางคณิตศาสตร์
ปัญหา : สัญญาอัจฉริยะจำนวนมากขึ้นอยู่กับสัญญาภายนอกเพื่อโต้ตอบ พฤติกรรมที่ไม่คาดคิดของสัญญาภายนอกอาจทำให้ทั้งระบบย้อนกลับ ความล้มเหลวในการจัดการกับข้อผิดพลาดภายนอกเหล่านี้สามารถนำไปสู่ช่องโหว่ของ DOS
คำถามรายการตรวจสอบ : "โปรโตคอลจัดการการโต้ตอบสัญญาภายนอกอย่างปลอดภัยหรือไม่"
การแก้ไข : ตรวจสอบให้แน่ใจว่า มีการจัดการข้อผิดพลาดที่แข็งแกร่งสำหรับการโต้ตอบสัญญาภายนอก เพื่อปกป้องความสมบูรณ์ของโปรโตคอลโดยไม่คำนึงถึงประสิทธิภาพของสัญญาภายนอก
ตัวอย่าง : พิจารณาสัญญาที่โต้ตอบกับแหล่งข้อมูลราคา chainlink ภายนอก หากคุณไม่ได้ใช้ลอง/จับสำหรับการจัดการข้อผิดพลาดที่เหมาะสมการย้อนกลับจากแหล่งข้อมูลภายนอกจะเผยแพร่ไปยังที่เหนือกว่าและทำให้สัญญาย้อนกลับ
getPrice
ดึงข้อมูลราคาcalculateSomethingImportant
ฟังก์ชั่นที่สำคัญที่สุดขึ้นอยู่กับ getPrice
และจะย้อนกลับ contract PriceDependentContract { AggregatorV3Interface public priceFeed; constructor(address _priceFeed) { priceFeed = AggregatorV3Interface(_priceFeed); } // 易受攻击的函数,在没有处理可能的Chainlink 回滚的情况下获取价格function getPrice() public view returns (uint256) { (, int256 price, , , ) = priceFeed.latestRoundData(); // 易受攻击的行:没有错误处理require(price > 0, "价格必须为正"); return uint256(price); } function calculateSomethingImportant() public view returns (uint256) { uint256 price = getPrice(); // ... 使用价格的一些重要计算return price * 2; }
วิธีการแก้ไข : ห่อการเรียกสัญญาภายนอกในบล็อกลอง/จับ เพื่อจัดการกับข้อผิดพลาดย้อนกลับและใช้ค่าย้อนกลับหรือค่าแคช
หมายเหตุ : มีกรณีขอบที่สัญญาภายนอกใช้ ก๊าซ โดยเจตนาซึ่งอาจล้มเหลวในการจับบล็อก! เราจะหารือเกี่ยวกับเรื่องนี้ในภายหลัง
เราสำรวจการตรวจสอบที่สำคัญสามครั้งที่ออกแบบมาเพื่อเพิ่มความสามารถของสัญญาอัจฉริยะของคุณในการต่อต้านการโจมตี DOS: ช่องโหว่การจัดการคิว ความท้าทายที่เกี่ยวข้องกับโทเค็นทศนิยมต่ำ และ ความสำคัญของการจัดการการโต้ตอบสัญญาภายนอกอย่างปลอดภัย
โปรดจำไว้ว่าตัวอย่างที่ให้ไว้มีวัตถุประสงค์เพื่อแสดงให้เห็นถึงช่องโหว่หลัก เป็นสิ่งสำคัญมาก ที่จะต้องเข้าใจหลักการพื้นฐาน และปรับแนวคิดเหล่านี้ให้เข้ากับกรณีการใช้งานเฉพาะของคุณ
ด้วยการใช้คำแนะนำเหล่านี้คุณสามารถปรับปรุงความปลอดภัยและความยืดหยุ่นของสัญญาอัจฉริยะของคุณได้อย่างมีนัยสำคัญ
ติดตามความคืบหน้าสำหรับส่วนถัดไปของซีรีย์ความละเอียดของรายการตรวจสอบ Solodit
- ลิงค์ดั้งเดิม: cyfrin.io/blog/solodit-c ...
- ชุมชน Denglian AI ผู้ช่วยแปลบทความภาษาอังกฤษที่ยอดเยี่ยมสำหรับทุกคน หากมีพื้นที่ใด ๆ ที่การแปลไม่เป็นที่เข้าใจโปรดยกโทษให้ฉัน ~