Reentrancy
การเรียกภายนอกที่ทำก่อนอัปเดตสถานะทำให้ผู้โจมตีสามารถเข้าฟังก์ชันซ้ำก่อนที่ยอดจะถูกหักลด ปฏิบัติตาม checks-effects-interactions และใช้ reentrancy guard
// vulnerable
function withdraw(uint a) public {
require(bal[msg.sender] >= a);
(bool ok,) = msg.sender.call{value:a}("");
bal[msg.sender] -= a; // too late
}
// fixed
function withdraw(uint a) public nonReentrant {
require(bal[msg.sender] >= a);
bal[msg.sender] -= a; // effects first
(bool ok,) = msg.sender.call{value:a}("");
require(ok);
}
การยืนยันตัวตนด้วย tx.origin
การใช้ tx.origin เพื่ออนุญาตทำให้สัญญาตัวกลางสามารถทำการแทนผู้ใช้ได้ ให้ใช้ msg.sender
การจัดการออราเคิล / ราคา
การอ่านราคาสปอตจากพูลเดียวทำให้ถูกจัดการได้ด้วยการสวอปขนาดใหญ่ ซึ่งมักได้ทุนจาก flash loan ควรใช้ราคาเฉลี่ยถ่วงน้ำหนักตามเวลา (TWAP) หรือออราเคิลแบบรวม
ขาดการควบคุมการเข้าถึง
ฟังก์ชันที่อ่อนไหวโดยไม่มี modifier จำกัดสามารถถูกเรียกได้โดยใครก็ตาม ป้องกันฟังก์ชันที่มีสิทธิพิเศษด้วย onlyOwner หรือการตรวจสอบบทบาท
การเรียกภายนอกที่ไม่ตรวจสอบ
การเพิกเฉยต่อค่าที่คืนจากการเรียกระดับต่ำทำให้สัญญาทำงานต่อหลังการโอนที่ล้มเหลว ตรวจสอบค่าบูลีนที่คืนเสมอ
ข้อบกพร่องของตรรกะทางธุรกิจ
การเปรียบเทียบที่กลับด้านหรือการคำนวณส่วนแบ่งที่ผิดทำลาย invariant ข้อบกพร่องเหล่านี้เฉพาะกับสัญญา หลุดรอดจากตัวตรวจจับทั่วไป และมักแพงที่สุด อธิบายพฤติกรรมที่ตั้งใจไว้แล้วเทียบกับโค้ด
อยากฝึกใช้ประโยชน์อย่างปลอดภัย? ดู เรียนรู้ พร้อมสแกนสัญญาของคุณแล้ว? เปิดสแกนเนอร์