Nhật ký phát triển hợp đồng thông minh Rust (8)
BlockSec
2022-04-01 11:38
本文约2449字,阅读全文需要约10分钟
Bài viết này sẽ giới thiệu cụ thể các vấn đề liên quan đến kiểm soát quyền hạn trong hợp đồng thông minh Rust từ hai góc độ sau.

    Bài viết này sẽ giới thiệu cụ thể các vấn đề liên quan đến kiểm soát quyền hạn trong hợp đồng thông minh Rust từ hai góc độ sau:

    Khả năng truy cập/gọi phương thức hợp đồng (chức năng);

    tiêu đề phụ

    1. Khả năng hiển thị chức năng (phương pháp) hợp đồng

    Khi viết hợp đồng thông minh, chúng ta có thể kiểm soát những chức năng nào có thể được gọi bởi ai bằng cách chỉ định khả năng hiển thị của các chức năng hợp đồng. Điều này cho phép chúng tôi dễ dàng bảo vệ một số phần quan trọng nhất định của hợp đồng khỏi sự truy cập hoặc thao túng tình cờ.

    Để phản ánh tầm quan trọng của việc thiết lập chính xác khả năng hiển thị của các chức năng hợp đồng, bài viết này sẽ lấy sàn giao dịch Bancor Network làm ví dụ. Ngay từ ngày 18 tháng 6 năm 2020, một sự cố bảo mật tài sản hợp đồng đã xảy ra trong sàn giao dịch do cài đặt sai quyền kiểm soát truy cập cho các chức năng chính của hợp đồng. Hợp đồng được viết bằng ngôn ngữ Solidity. Trong ngôn ngữ này, khả năng hiển thị của các chức năng hợp đồng được chia thành công khai/bên ngoài và riêng tư/nội bộ. Cái trước cho phép các chức năng hợp đồng được gọi bởi những người gọi bên ngoài, có thể được coi là một phần của giao diện hợp đồng.

    Tuy nhiên, khi sàn giao dịch Bancor Network sửa một lỗ hổng bảo mật nào đó, do sơ suất nên đã đặt nhầm một số chức năng chuyển key trong hợp đồng thành thuộc tính public (như hình bên dưới):

    Dựa trên điều này, bất kỳ ai, kể cả người dùng thông thường, đều có thể gọi các chức năng này từ bên ngoài hợp đồng để thực hiện các thao tác chuyển giao tương ứng cho mình hoặc người khác.

    Sự tồn tại của lỗ hổng nghiêm trọng này khiến tài sản trị giá 590.000 USD của người dùng gặp rủi ro nghiêm trọng.


    Tương tự, trong hợp đồng thông minh Rust, cũng phải chú ý đến khả năng kiểm soát khả năng hiển thị của các chức năng hợp đồng.

    Trong loạt hợp đồng thông minh này để phát triển nhật kýNhật ký phát triển hợp đồng thông minh Rust (1), chúng tôi đã giới thiệu các macro được NEAR SDK xác định: #[near_bindgen]:

    #[near_bindgen] được xác định bởi hàm near_bindgen trong gói phiên bản close-sdk-macro, là nơi các macro được sử dụng để tự động tạo mã tiêm (Macros-Auto-Auto-Generated Injected Code, viết tắt là MAGIC)

    Bằng cách tham khảo tài liệu mô tả chính thức do NEAR cung cấp, chúng ta có thể thấy rằng có một số thuộc tính hiển thị khác nhau trong chức năng hợp đồng thông minh Rust được xác định bởi macro #[near_bindgen]:

    • pub fn: Chỉ ra rằng phương thức hợp đồng là công khai và là một phần của giao diện hợp đồng, có nghĩa là bất kỳ ai cũng có thể gọi nó từ bên ngoài hợp đồng.

    • fn: Nếu chức năng phương thức của hợp đồng không chỉ định rõ ràng pub, điều đó có nghĩa là chức năng không thể được gọi trực tiếp từ bên ngoài hợp đồng và chỉ có thể được gọi nội bộ bởi các chức năng khác trong hợp đồng.

    • pub(crate) fn: tương đương với pub(in crate), tương tự như fn, công cụ sửa đổi khả năng hiển thị này có thể giới hạn các phương thức hợp đồng cụ thể được gọi trong phạm vi của thùng.

    Một cách khác để đặt phương thức của hợp đồng là nội bộ là xác định một khối mã Hợp đồng impl riêng biệt trong hợp đồng.

    Nhưng cần lưu ý rằng việc triển khai không bị sửa đổi bởi #[near_bindgen]:

    Kiểm soát truy cập các chức năng gọi lại (Callbacks):

    Định nghĩa của hàm gọi lại trong hợp đồng phải được đặt thành thuộc tính công khai, để có thể gọi nó bằng lệnh gọi hàm.

    Khi chúng tôi xác định chức năng gọi lại trong hợp đồng, chúng tôi cũng cần đảm bảo rằng chức năng gọi lại không thể được gọi bởi người khác theo ý muốn. Nghĩa là, người gọi hàm gọi lại env::current_account_id() phải là env::current_account_id() của chính hợp đồng.

    NEAR SDK xác định một macro Rust tương đương #[riêng tư] cho chúng tôi. Sử dụng macro này, chức năng gọi lại của hợp đồng có thể đạt được chức năng tương tự như chức năng được triển khai trong các dòng 4-5 của mã trên.

    Theo mặc định, mọi thứ trong ngôn ngữ Rust đều ở chế độ riêng tư, ví dụ hàm fn không đặt thuộc tính public ở trên có chế độ hiển thị mặc định là private.

    Điều mà solidity cần phân biệt ở đây là trong một số phiên bản cũ của trình biên dịch solidty: nếu không có công cụ sửa đổi nào được thêm vào định nghĩa của hàm hợp đồng, thì nó sẽ được coi là công khai theo mặc định.

    Nhưng trong ngôn ngữ Rust, có hai trường hợp ngoại lệ:

    • Các mục phụ trong pub Trait được mặc định công khai;

    • Các biến Enum trong pub Enum cũng được mặc định là công khai;


    2. Kiểm soát truy cập các chức năng đặc quyền (cơ chế danh sách trắng)

    Khi viết hợp đồng thông minh Rust, ngoài việc biết khả năng hiển thị chức năng cụ thể, chúng ta cũng cần suy nghĩ sâu sắc từ cấp độ ngữ nghĩa của hợp đồng, tức là thiết lập cơ chế danh sách trắng kiểm soát truy cập hoàn chỉnh.

    Tương tự như hợp đồng hợp đồng/truy cập/Ownable.sol được xác định và sử dụng trong thư viện hợp đồng thông minh của Solidity openzeppelin-contracts, một số chức năng là chức năng đặc quyền, chẳng hạn như khởi tạo hợp đồng, mở/tạm dừng hợp đồng, chuyển giao hợp nhất, v.v... ... chỉ có thể được gọi bởi chủ sở hữu của hợp đồng Các chức năng này cũng thường chỉ được gọi là các chức năng của chủ sở hữu.

    Nhưng chủ sở hữu về cơ bản là một người gọi hợp đồng bên ngoài, để gọi, các chức năng chính này phải được đặt làm thuộc tính công khai. Vì vậy, vì các chức năng này là thuộc tính công khai, điều đó có nghĩa là tất cả những người dùng thông thường khác cũng có thể đến và gọi chúng?

    Câu trả lời là có, nhưng những người dùng thông thường không phải là chủ sở hữu sẽ sớm phát hiện ra rằng họ có thể điều chỉnh, nhưng không hoàn toàn.

    Điều này là do trong hợp đồng thông minh, một số quy tắc kiểm soát truy cập có thể được xác định cho các chức năng của hợp đồng và các quy tắc tương ứng phải được thỏa mãn để được ủy quyền hoàn toàn để thực thi. Ví dụ: có các công cụ sửa đổi thường được sử dụng sau đây trong các hợp đồng solidity:

    Khi chức năng hợp đồng được sửa đổi bởi công cụ sửa đổi này được gọi, trước tiên, nó sẽ kiểm tra xem người gọi msg.sender của giao dịch này có phải là chủ sở hữu được đặt khi hợp đồng được khởi tạo hay không. Nếu nó không khớp, quá trình thực thi tiếp theo của chức năng sẽ hủy bỏ hoặc hoàn nguyên Qua đó ngăn chặn người dùng trái phép truy cập và thực thi.

    Tương tự, trong hợp đồng thông minh của NEAR Rust, chúng ta cũng có thể triển khai một Đặc điểm tùy chỉnh tương tự như sau:

    Sử dụng đặc điểm này cũng có thể triển khai kiểm soát quyền truy cập vào một số chức năng đặc quyền trong hợp đồng, nghĩa là, người gọi env::predecessor_account_id() của hợp đồng trong giao dịch này cần phải bằng với chủ sở hữu của hợp đồng.

    Ở trên, chúng tôi đã thiết lập một ví dụ danh sách trắng đơn giản chỉ dành cho các chức năng đặc quyền có thể sở hữu. Dựa trên nguyên tắc này, chúng tôi có thể đặt nhiều người dùng trong danh sách trắng bằng cách tùy chỉnh các đặc điểm hoặc công cụ sửa đổi phức tạp hơn hoặc đặt nhiều danh sách trắng để đạt được hiệu quả kiểm soát truy cập nhóm chi tiết và tốt.

    3. Các phương pháp kiểm soát truy cập khác

    Các phương pháp kiểm soát truy cập trong các hợp đồng thông minh Rust khác như:

    • Kiểm soát thời gian cuộc gọi hợp đồng

    • Cơ chế gọi đa chữ ký của chức năng hợp đồng, thực hiện quản trị (DAO)

    • ...

    Hãy chú ý đến phần tiếp theo của loạt nhật ký phát triển hợp đồng thông minh này😊

    BlockSec
    作者文库