Lỗ hổng phát lại chữ ký trong hợp đồng thông minh | kiểm toán khối
Một mẹo hữu ích là ký các tin nhắn ngoài chuỗi và có một hợp đồng yêu cầu chữ ký đó trước khi thực hiện một chức năng.
Ví dụ: kỹ thuật này được sử dụng để: -
- giảm số lượng giao dịch trên chuỗi
- giao dịch ít gas, được gọi làmeta transaction
Hãy xem những gì chúng ta đang nói về
Chuỗi khối phụ thuộc rất nhiều vào chữ ký mật mã. Các giao dịch được ký bằng các khóa riêng tư tương ứng, cho phép người gửi giao dịch được liên kết với tài khoản của họ. Sổ sách kế toán của chuỗi khối sẽ không thể hoạt động nếu không có tính năng này.
Chữ ký số cũng thường được xác thực trực tiếp trong hợp đồng thông minh Ethereum, cho phép một hoặc nhiều người xác minh ủy quyền hành động bằng cách gửi chữ ký ngoài chuỗi ( hoặc thậm chí chữ ký được tạo bởi một hợp đồng thông minh khác ).
Điều này thường được sử dụng trong kho tiền nhiều chữ ký hoặc hợp đồng biểu quyết để gửi nhiều chữ ký cùng một lúc hoặc để ủy quyền.
Các cuộc tấn công phát lại chữ ký là một lỗ hổng phổ biến trong các triển khai như vậy.
Xác minh chữ ký trong hợp đồng thông minh đôi khi được yêu cầu để cải thiện khả năng sử dụng hoặc tiết kiệm chi phí gas. Việc triển khai an toàn sẽ ngăn chặn Tấn công phát lại chữ ký.
Ví dụ: -
Theo dõi tất cả các băm tin nhắn đã xử lý và chỉ cho phép xử lý các băm tin nhắn mới. Người dùng ác ý có thể tấn công một hợp đồng thiếu quyền kiểm soát như vậy và lấy được hàm băm tin nhắn do người dùng khác gửi và xử lý nhiều lần.
Chữ ký số mật mã
Chữ ký số là nguyên hàm khóa công khai của xác thực tin nhắn. Trong thế giới thực, chữ ký viết tay thường được sử dụng trên các tin nhắn viết tay hoặc đánh máy. Chúng được sử dụng để ràng buộc người ký vào thông điệp.
Chữ ký điện tử là một giá trị mật mã được tạo bởi dữ liệu và một khóa bí mật mà chỉ người ký mới biết.
Mô hình Chữ ký số
Quy trình hoàn chỉnh được giải thích kỹ lưỡng ở các điểm sau:
- Mỗi người dùng của lược đồ này có một bộ khóa công khai và khóa riêng.
- Các cặp khóa được sử dụng để mã hóa/giải mã và ký/xác minh thường khác biệt với nhau. Khóa chung được gọi là khóa xác minh và khóa riêng được gọi là khóa chữ ký.
- Dữ liệu được gửi vào hàm băm bởi người ký, tạo ra hàm băm.
- Thuật toán chữ ký sau đó tạo chữ ký số trên hàm băm được cung cấp bằng cách sử dụng giá trị băm và khóa chữ ký. Dữ liệu được cung cấp một chữ ký và cả hai sau đó được gửi đến người xác minh.
- Thuật toán xác minh được cung cấp bởi trình xác minh cùng với chữ ký số và khóa xác minh. Kết quả của thuật toán xác minh là một cái gì đó hữu ích. Trên dữ liệu mà nó nhận được, trình xác minh cũng sử dụng cùng một thuật toán băm để tạo ra giá trị băm.
- Giá trị băm này và kết quả của quá trình xác minh được so sánh để xác minh. Trình xác minh xác định xem chữ ký số có hợp pháp hay không dựa trên kết quả so sánh.
- Không ai khác có thể sử dụng khóa “riêng tư” của người ký để thiết lập chữ ký điện tử, do đó sau này người ký không thể rút lại chữ ký dữ liệu của họ.
Lớp giao thức
Chỉ những giao dịch có chữ ký hợp lệ mới được đưa vào các khối mới, nhờ vào mạng Ethereum . Đối với các giao dịch, điều này cung cấp các thuộc tính bảo mật sau:
- Xác thực : Chữ ký được sử dụng bởi các nút Ethereum để xác nhận rằng người ký giao dịch là chủ sở hữu của khóa riêng được kết nối với địa chỉ công khai của họ. Do đó, các nhà phát triển có thể tin tưởng rằng msg.sender là chính hãng.
- Tính toàn vẹn : Tính toàn vẹn là điều kiện giao dịch không bị thay đổi sau khi đã được ký kết; nếu không, chữ ký là vô hiệu.
- Không từ chối: Chữ ký của giao dịch và bất kỳ thay đổi trạng thái nào được thực hiện bởi bên ký kết sở hữu khóa riêng không thể bị tranh cãi. Khóa riêng thuộc về địa chỉ công khai được liệt kê trong trường từ .
Chữ ký giống nhau có thể được sử dụng nhiều lần để thực thi một chức năng. Điều này có thể gây hại nếu ý định của người ký là phê duyệt giao dịch một lần.
Mã ví dụ
Hãy kiểm tra lỗi.
function unlock(
address _to,
uint256 _amount,
uint8[] _v,
bytes32[] _r,
bytes32[] _s
)
external
{
require(_v.length >= 20);
bytes32 hashData = keccak256(_to, _amount);
for (uint i = 0; i < _v.length; i++) {
address recAddr = ecrecover(hashData, _v[i], _r[i], _s[i]);
require(_isValidator(recAddr));
}
to.transfer(_amount);
}
Thông báo được ký bởi những người xác thực sử dụng kỹ thuật ECDSA là nơi có vấn đề với mã nói trên. Địa chỉ người nhận và số tiền cần thiết là thông tin duy nhất trong tin nhắn. Không có gì trong tin nhắn có thể được sử dụng để tránh sử dụng cùng một chữ ký nhiều lần. Hãy xem xét trường hợp sau:
- Sam chuyển 2000 ETH từ mạng được liên kết trở lại chuỗi Ethereum bằng cùng một lượng tiền tệ.
- Xử lý giao dịch xuyên chuỗi khối này là Tom, một người chuyển tiếp. Để giải phóng 2000 ETH từ hợp đồng và gửi cho Sam, anh ấy thu thập các chữ ký xác thực cần thiết, khóa số tiền phù hợp trên chuỗi được kết nối, sau đó sử dụng chức năng mở khóa.
- Trên chuỗi khối, giao dịch chứa các mảng giá trị chữ ký được mọi người nhìn thấy.
- Bây giờ Sam đã sao chép các mảng chữ ký, anh ấy có thể gửi lệnh gọi mở khóa một cách độc lập. Một lần nữa, quá trình mở khóa sẽ thành công, dẫn đến việc chuyển 2000 ETH cho Sam.
- Sam có thể tiếp tục theo cách này cho đến khi hết hợp đồng.
Một cuộc tấn công phát lại chữ ký là những gì được mô tả trong ví dụ trên. Có thể hình dung được vì không có cách nào để xác định xem thông báo đã ký cụ thể này là duy nhất hay liệu nó đã được sử dụng trước đó hay chưa.
Ký tin nhắn với noncevà địa chỉ của hợp đồng.
public uint256 nonce;
function unlock(
address _to,
uint256 _amount,
uint256 _nonce,
uint8[] _v,
bytes32[] _r,
bytes32[] _s
)
external
{
require(_v.length >= 20);
require(_nonce == nonce++);
bytes32 hashData = keccak256(_to, _amount, _nonce);
for (uint i = 0; i < _v.length; i++) {
address recAddr = ecrecover(hashData, _v[i], _r[i], _s[i]);
require(_isValidator(recAddr));
}
to.transfer(_amount);
}
Để bảo vệ chống lại các cuộc tấn công phát lại chữ ký, hãy xem xét các khuyến nghị sau:
- Lưu trữ mọi hàm băm tin nhắn đã được xử lý bởi hợp đồng thông minh. Khi nhận được tin nhắn mới, hãy kiểm tra đối chiếu với những tin nhắn đã tồn tại và chỉ tiếp tục với logic nghiệp vụ nếu đó là một hàm băm tin nhắn mới.
- Bao gồm địa chỉ của hợp đồng xử lý tin nhắn. Điều này đảm bảo rằng tin nhắn chỉ có thể được sử dụng trong một hợp đồng duy nhất.
- Trong mọi trường hợp, hãy tạo hàm băm tin nhắn bao gồm cả chữ ký. Chức
ecrecovernăng dễ bị uốn nắn chữ ký.
Chữ ký không phải là duy nhất có thể được phát lại trong nhiều tình huống khác nhau, như đã thấy trong ví dụ trên. Để tránh các cuộc tấn công lặp lại, điều quan trọng trong phần lớn các tình huống là đảm bảo chữ ký được khớp cụ thể với từng cuộc gọi. Ngoài ra, vì lý do này, một nonce được bao gồm trong mọi giao dịch Ethereum.
Người giới thiệu: -
https://solidity-by-example.org/hacks/signature-replay/
https://blog.finxter.com/smart-contract-replay-attack-solidity/
https://swcregistry.io/docs/SWC-121
Hối hả với Bảo mật web3!!! Kết nối với chúng tôi!!!
BlockAudit : - Tại sao lại là chúng tôi??
BlockAudit có các nguồn lực và kiến thức để tạo ra các giải pháp an ninh mạng giúp tiết kiệm hàng triệu đô la.
liên kết | Trang web | Twitter

![Dù sao thì một danh sách được liên kết là gì? [Phần 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































