Security best practices: Data storage
Rust: Use thread_local!
with Cell/RefCell
for state variables and put all your globals in one basket
Security concern
Canisters need a global mutable state. In Rust, there are several ways to achieve this. However, some options can lead to vulnerabilities such as to memory corruption.
Recommendation
Use
thread_local!
withCell/RefCell
for state variables (from effective Rust canisters).Put all your globals in one basket (from effective Rust canisters).
Limit the amount of data that can be stored in a canister per user
Security concern
If a user is able to store a big amount of data on a canister, this may be abused to fill up the canister storage and make the canister unusable.
Recommendation
Limit the amount of data that can be stored in a canister per user. This limit has to be checked whenever data is stored for a user in an update call.
Consider using stable memory, version it, test it
Security concern
Canister memory is not persisted across upgrades. If data needs to be kept across upgrades, you may serialize the canister memory in pre_upgrade
, and deserialize it in post_upgrade
. However, the available number of instructions for these methods is limited. If the memory grows too big, the canister can no longer be updated.
Recommendation
Stable memory is persisted across upgrades and can be used to address this issue.
Consider using stable memory (from effective Rust canisters). Take note of the discussed disadvantages.
See also the section on upgrades in how to audit an ICP canister (focused on Motoko canisters).
Write tests for stable memory to avoid bugs.
Some libraries commonly used are:
HashMap: https://github.com/dfinity/stable-structures/pull/1 (currently not production ready.)
Please note some of these libraries may be partially unfinished.
See current limitations of the Internet Computer, sections "Long running upgrades" and "[de]serializer requiring additional Wasm memory".
For example, Internet Identity uses stable memory directly to store user data.
Consider encrypting sensitive data on canisters
Security concern
By default, canisters provide integrity but not confidentiality. Data stored on canisters can be read by nodes / replicas.
Recommendation
Consider end-to-end encrypting any private or personal data (e.g. user’s personal or private information) on canisters.
The example dapp encrypted notes illustrates how end-to-end encryption can be done.
Create backups
Security concern
A canister could be rendered unusable and impossible to upgrade again e.g. due reasons such as:
It has a faulty upgrade process due to some bug from the dapp developer.
The state becomes inconsistent or corrupt because of a bug in the code that persists data.
Recommendation
Make sure methods used in upgrading are tested or the canister becomes immutable.
It may be useful to have a disaster recovery strategy that makes it possible to reinstall the canister.
See the "Backup and recovery" section in how to audit an Internet Computer canister