Tự học Solidity bài 36: Random Numbers safely. Tại sao tạo số ngẫu nhiên trong SOLIDITY lại không an toàn?
Random Numbers Safely.
Tự học Solidity bài 36: Tại sao tạo số ngẫu nhiên trong SOLIDITY lại không an toàn?
Trong bài học trước chúng ta đã được giới thiệu về việc tạo số ngẫu nhiên trong SOLIDITY, tuy nhiên tôi cũng có ghi chú là việc tạo số ngẫu nhiên như vậy là không an toàn. Trong bài học này chúng ta cùng tìm hiêu tại sao nó lại không an toàn nhé :)
Tạo số ngẫu nhiên trong SOLIDITY
Nguồn ngẫu nhiên tốt nhất mà chúng ta có trong ngôn ngữ lập trình Solidity là hàm băm keccak256.
Chúng ta có thể làm như sau để tạo một số ngẫu nhiên từ 1 đến 100:
uint randNonce = 0;
uint random = uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % 100;
randNonce++;
uint random2 = uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % 100;
Đầu vào của chúng ta sẽ lấy: dấu thời gian của now, msg.sender và một biến integer nonce tăng dần (một số chỉ được sử dụng một lần, vì vậy chúng ta không chạy cùng một hàm băm với các tham số đầu vào giống nhau hai lần).
Sau đó, nó sẽ "đóng gói" các tham số đầu vào và sử dụng keccak để chuyển đổi chúng thành một hàm băm ngẫu nhiên. Tiếp theo, ta sẽ chuyển đổi hàm băm đó thành uint, và sử dụng %100 để chỉ lấy 2 chữ số cuối cùng. Điều này sẽ cung cấp cho chúng tôi một số hoàn toàn ngẫu nhiên từ 0 đến 99. ( Thế mà lại không an toàn :) )
Vì sao số ngẫu nhiên trong SOLIDITY lại không an toàn?
Phương pháp này dễ bị tấn công bởi một nút không trung thực
Trong Ethereum, khi bạn gọi một hàm trên hợp đồng, bạn sẽ phát nó tới một nút hoặc các nút trên mạng như một giao dịch. Sau đó, các nút trên mạng thu thập một loạt các giao dịch, cố gắng trở thành người đầu tiên giải quyết một vấn đề toán học chuyên sâu về tính toán dưới dạng "Proof of Work", và sau đó xuất bản nhóm giao dịch đó cùng với Proof of Work (PoW) của chúng dưới dạng một khối đối với phần còn lại của mạng.
Khi một nút đã giải được PoW, các nút khác sẽ ngừng giải PoW, xác minh rằng danh sách giao dịch của nút khác là hợp lệ, sau đó chấp nhận khối đã được giải và chuyển sang giải khối tiếp theo.
Điều này làm cho hàm số ngẫu nhiên của chúng ta có thể bị tấn công bởi một nút gian lận.
Giả sử chúng ta đã có một trò cá cược Tài Xỉu. Giả sử nó đã sử dụng hàm ngẫu nhiên trong ví dụ ở trên để xác định Tài hoặc Xỉu. (random> = 50 là tài, random <50 là xỉu).
Nếu tôi đang sở hữu một nút trong ETH, tôi có thể xuất bản một giao dịch lên nút của chính mình và không chia sẻ nó. Sau đó, tôi có thể chạy chức năng Tài-Xỉu để xem liệu tôi có thắng hay không - và nếu tôi thua, tôi sẽ không đưa giao dịch đó vào khối tiếp theo. Tôi có thể tiếp tục làm điều này vô thời hạn cho đến khi cuối cùng tôi thắng trong trò chơi Tài-Xỉu và Tôi cố gắng giải quyết được khối tiếp theo, nếu thành công việc giải khối tiếp theo (dù phải cạnh tranh với hàng chục nghìn note ETH khác) thì tôi sẽ thu được lợi nhuận từ trò chơi Tài - Xỉu đó :)
Tất nhiên, vì hàng chục nghìn nút Ethereum trên mạng đang cạnh tranh để giải khối tiếp theo, tỷ lệ giải quyết khối tiếp theo của tôi là cực kỳ thấp. Tôi sẽ mất rất nhiều tài nguyên để khai thác lợi nhuận này - nhưng nếu phần thưởng đủ cao (như nếu tôi có thể thắng 100.000.000 đô la vào chức năng Tài-Xỉu, thì tôi sẽ mới đáng để tấn công.
Vì vậy, mặc dù việc tạo số ngẫu nhiên này KHÔNG an toàn trên Ethereum, nhưng trên thực tế, trừ khi chức năng ngẫu nhiên của chúng tôi phục vụ cho một game có thật nhiều tiền thưởng mới lo ngại việc bị khai thác lỗ hổng bảo mật này.
Thực hành luôn cho nhớ lâu bạn nhé
Nếu bạn chưa biết cách TẠO FILE, COMPILER và DEPLOY thì hãy xem lại trong bài giới thiệu nhé. Có hướng dẫn chi tiết ở đó.
BÀI TIẾP THEO: BÀI SỐ 37
HỌC TỪ ĐẦU: BÀI SỐ 1