Bảo mật Hợp đồng thông minh: Hiểu và Ngăn chặn lỗ hổng tái nhập

Các cuộc tấn công tái nhập đại diện cho một trong những mối đe dọa bảo mật nghiêm trọng nhất trong phát triển hợp đồng thông minh. Phân tích kỹ thuật này giải thích cơ chế đằng sau các lỗ hổng tái nhập và cung cấp các chiến lược phòng thủ toàn diện để bảo vệ các hợp đồng của bạn.

Tấn công Reentrancy là gì?

Tái nhập xảy ra khi một hàm trong hợp đồng thông minh có thể bị gián đoạn trong quá trình thực thi và được gọi lại trước khi lần gọi đầu tiên hoàn tất. Về mặt kỹ thuật, tái nhập khai thác ngữ cảnh thực thi của một hợp đồng thông minh bằng cách thao túng luồng điều khiển thông qua các cuộc gọi bên ngoài.

Khi Hợp đồng A tương tác với Hợp đồng B, lỗ hổng phát sinh vì Hợp đồng B có thể gọi lại Hợp đồng A trong khi việc thực thi của Hợp đồng A vẫn đang diễn ra. Mô hình gọi đệ quy này có thể bị sử dụng để thao túng trạng thái hợp đồng và rút tiền.

Cơ Chế Tấn Công: Cách Reentrancy Hoạt Động

Hãy xem xét một kịch bản với hai hợp đồng:

  • Hợp đồng A: Một hợp đồng dễ bị tổn thương đang nắm giữ 10 ETH
  • Hợp đồng B: Một hợp đồng độc hại với 1 ETH được gửi vào Hợp đồng A

Luồng tấn công theo mô hình này:

  1. Hợp đồng B gọi hàm withdraw() trong Hợp đồng A
  2. Hợp đồng A xác minh rằng số dư của Hợp đồng B lớn hơn 0 ( vượt qua kiểm tra )
  3. Hợp đồng A gửi 1 ETH đến Hợp đồng B trước khi cập nhật bản ghi số dư của nó
  4. Việc chuyển ETH kích hoạt hàm fallback của Hợp đồng B
  5. Bên trong hàm fallback, Hợp đồng B gọi lại hàm rút tiền của Hợp đồng A ()
  6. Vì Hợp đồng A vẫn chưa cập nhật số dư của Hợp đồng B, nên kiểm tra lại thành công.
  7. Hợp đồng A gửi thêm ETH đến Hợp đồng B
  8. Quy trình này lặp lại cho đến khi Hợp đồng A hết tiền.

Lỗ hổng nghiêm trọng nằm ở thứ tự thực thi của Hợp đồng A: nó thực hiện cuộc gọi bên ngoài ( gửi ETH) trước khi cập nhật trạng thái nội bộ của nó ( đặt số dư về không ).

Ba Kỹ Thuật Phòng Ngừa Chống Tái Xâm Nhập

1. Bảo vệ cấp chức năng với bộ sửa đổi noReentrant

Modifier noReentrant thực hiện một cơ chế khóa ngăn không cho một hàm được gọi đệ quy:

solidity // Biến trạng thái để theo dõi sự tái nhập bool private locked = false;

// Bộ sửa đổi để ngăn chặn reentrancy modifier noReentrant() { require(!locked, "Reentrant call"); locked = true; _; locked = false; }

// Hàm được bảo vệ function withdraw() public noReentrant { // Logic chức năng ở đây }

Cách tiếp cận này chặn các nỗ lực gọi lại bằng cách duy trì một biến trạng thái toàn bộ hợp đồng, ngăn chặn việc thực thi đồng thời các hàm được bảo vệ.

2. Kiểm tra - Hiệu ứng - Mẫu tương tác

Mẫu này cấu trúc lại mã để tuân theo một trình tự cụ thể của các thao tác:

  1. Kiểm tra: Xác minh điều kiện ( chẳng hạn, số dư > 0)
  2. Hiệu ứng: Cập nhật biến trạng thái ( ví dụ, đặt số dư = 0)
  3. Tương tác: Thực hiện các cuộc gọi bên ngoài ( ví dụ, chuyển ETH )

So sánh mã dễ bị tổn thương và mã được bảo vệ:

Dễ bị tổn thương: solidity hàm rút() bên ngoài { uint bal = balances[msg.sender]; require(bal > 0);

// Tương tác trước Hiệu ứng (vulnerable)
(bool sent, ) = msg.sender.call{value: bal}("");
require(sent, "Gửi Ether không thành công");

balances[msg.sender] = 0; // Có thể không bao giờ được truy cập nếu xảy ra tấn công tái nhập

}

Được bảo vệ: solidity function withdraw() bên ngoài { uint bal = balances[msg.sender]; require(bal > 0);

// Hiệu ứng trước khi tương tác (secure)
balances[msg.sender] = 0;

(bool sent, ) = msg.sender.call{value: bal}("");
require(sent, "Gửi Ether không thành công");

}

Bằng cách cập nhật trạng thái trước các tương tác bên ngoài, hợp đồng vẫn an toàn ngay cả khi cuộc gọi bên ngoài kích hoạt một cuộc gọi hàm tái nhập.

3. Bảo vệ Chéo Hợp Đồng với GlobalReentrancyGuard

Đối với các dự án có nhiều hợp đồng tương tác, một bộ bảo vệ reentrancy chung cung cấp sự bảo vệ toàn diện:

solidity // Hợp đồng trung tâm để bảo vệ chống lại việc gọi lại hợp đồng GlobalReentrancyGuard { mapping(address => bool) private _status;

function _beforeNonReentrant() internal {
    require(_status[msg.sender] == false, "ReentrancyGuard: reentrant call");
    _status[msg.sender] = true;
}

function _afterNonReentrant() internal {
    _status[msg.sender] = false;
}

}

// Sử dụng guard trong một hợp đồng hợp đồng ProtectedContract là GlobalReentrancyGuard { function protectedFunction() external { _beforeNonReentrant();

    // Logic hàm bảo vệ ở đây
    
    _afterNonReentrant();
}

}

Kỹ thuật này ngăn chặn sự tái nhập chéo hợp đồng bằng cách duy trì một sổ đăng ký trạng thái toàn cầu theo dõi trạng thái thực thi giữa nhiều hợp đồng trong hệ sinh thái của bạn.

Các Thực Hành Bảo Mật Tốt Nhất

Để đảm bảo bảo vệ toàn diện chống lại các cuộc tấn công tái nhập:

  1. Áp dụng nhiều lớp phòng thủ: Kết hợp mẫu kiểm tra-tác động-tương tác với các rào cản tái nhập để có độ bảo mật tối đa
  2. Tiến hành kiểm tra kỹ lưỡng: Sử dụng các công cụ chuyên biệt như Mythril để phát hiện các lỗ hổng tái nhập tiềm ẩn.
  3. Tuân theo các mẫu đã được thiết lập: Thực hiện các biện pháp bảo mật một cách nhất quán trên tất cả các hợp đồng trong dự án của bạn
  4. Sử dụng các phụ thuộc đã được kiểm toán: Kết hợp các thư viện đã được kiểm nghiệm với hồ sơ an ninh đã được chứng minh.
  5. Cập nhật số dư trước: Luôn thay đổi trạng thái trước khi thực hiện các cuộc gọi hoặc chuyển tiền bên ngoài

Bằng cách triển khai những cơ chế bảo vệ này, bạn có thể bảo vệ hiệu quả các hợp đồng thông minh của mình trước một trong những vectơ tấn công nguy hiểm nhất trong an ninh blockchain.

ETH5.89%
Xem bản gốc
Trang này có thể chứa nội dung của bên thứ ba, được cung cấp chỉ nhằm mục đích thông tin (không phải là tuyên bố/bảo đảm) và không được coi là sự chứng thực cho quan điểm của Gate hoặc là lời khuyên về tài chính hoặc chuyên môn. Xem Tuyên bố từ chối trách nhiệm để biết chi tiết.
  • Phần thưởng
  • Bình luận
  • Đăng lại
  • Retweed
Bình luận
0/400
Không có bình luận
  • Ghim
Giao dịch tiền điện tử mọi lúc mọi nơi
qrCode
Quét để tải xuống ứng dụng Gate
Cộng đồng
Tiếng Việt
  • 简体中文
  • English
  • Tiếng Việt
  • 繁體中文
  • Español
  • Русский
  • Français (Afrique)
  • Português (Portugal)
  • Bahasa Indonesia
  • 日本語
  • بالعربية
  • Українська
  • Português (Brasil)