In cybersecurity, access controls are measures that are put in place to prevent unauthorized access to systems, networks, and data. These controls are designed to protect against unauthorized access, modification, or destruction of sensitive information and critical systems.
Access control is even more important for smart contracts, as they live on public blockchains that permit anyone to call functions. In this blog, Let’s jump in what access control for smart contracts means, why it matters, and how to implement better access control patterns for your smart contracts.
What is Access Controls in Smart Contract?
In a smart contract, access controls are measures that are put in place to limit which users or contracts are able to access the contract’s functions and variables. This can help ensure that only authorized users are able to interact with the contract, and that sensitive information is protected. Typically, these are operations critical to the security and health of the protocol (e.g., minting new tokens, pausing transfers and withdrawals, or executing upgrades).
Designing secure access control for smart contracts can be difficult, as projects must balance two competing objectives: efficiency and security.
Centralized access control (where a small set of participants control administrative functions) makes it easier to perform administrative operations, but can introduce new trust assumptions and degrade security.
Distributed access control aids robustness and decentralization, but can increase the complexity of managing a smart contract.
In later parts of the article, we’ll dive into different access control patterns and how and when they can be used.
The Importance of Access Controls in Smart Contract
Smart Contract Security
Access controls can help prevent unauthorized modifications to a smart contract. For example, if a contract has a function that can only be accessed by a specific user or contract, it can prevent other users or contracts from making changes to that function. This can help ensure the integrity and security of the contract.
Overall, implementing effective access controls is an important part of any smart contract design, and can help protect against potential security threats.
Upgrades aren’t the only functions that need proper access control—every function that can significantly influence a protocol’s operations must be adequately protected. For example, DeFi protocol MakerDAO uses access control to regulate who can submit a price oracle update (to prevent attackers from manipulating the valuation of assets in the system).
The developer(s) responsible for creating and managing a protocol typically have more access to administrative functions than regular users. This makes some sense since devs will need to perform routine admin tasks (e.g., adding new features), or respond to emergencies (e.g., pausing withdrawals).
However, users must trust developers not to exercise these powers arbitrarily for selfish reasons, such as minting new tokens and dumping them on the market to make quick profits (i.e., rug-pulling users). To reduce trust assumptions and centralization risks, projects can implement decentralized access control.
For example, a protocol might subject the execution of critical functions in contracts to a multisig wallet to provide a level of fault tolerance. Even if one or two insiders attempt to subvert protocol rules (by accident or design), users still have some degree of protection.
Access Control mechanisms in Smart Contract
Access modifiers, ownable patterns & role-based permissioning are three common techniques for establishing access control in smart contracts today. These techniques have unique advantages and drawbacks which we explore in detail:
Access modifiers specify which users or contracts are allowed to access the function or variable. For example, the
private modifier can be used to restrict access to a function or variable to only the contract itself, while the
public modifier allows any user or contracts to access the function or variable.
The Ownable pattern builds on the idea of a contract “owned” by a special account with exclusive access to administrative functions in that contract. The contract’s owner is usually the address that deployed it, although it is possible to transfer ownership to another account.
Under the Ownable pattern, restricted functions have an
onlyOwner modifier that checks the identity of the calling account before executing. If the caller’s address fails to match the owner’s address stored in the contract storage, the call reverts.
Owned contracts are usually easy to implement since only one administrative account is involved. Delegating control of a smart contract this way also reduces administrative overhead—contract owners can quickly implement changes such as freezing a contract to minimize damage from an exploit.
However, contract ownership can also introduce the risks of centralization. When a single individual has the power to take critical actions (without meaningful checks on this power), users must trust that party to act responsibly. But even honesty might be insufficient—a centralized owner can still cause damage, which can cause numerous destructions (as we have seen happen many times like with the FTX collapse).
Most projects will favor contract ownership during the bootstrapping phase since it affords simplicity, speed, and cost-effectiveness. But, as a project grows and onboards more users, a more robust access control mechanism may be necessary. This is where role-based permissioning comes into the picture.
In cybersecurity, the principle of least privilege (also called the principle of least authority) means actors in a system have only as much access as they need to perform their functions. This concept forms the building block of role-based permissioning where individuals/entities are granted powers according to their roles in the system.
While the Ownable pattern assigns the administration of a smart contract to a single account, role-based access control delegates administrative powers to multiple accounts.
Role-based permissioning works like this:
- At deployment, the developer specifies different roles relevant to the contract’s administration (e.g., token minter, token burner, etc.). Each role will have access to the function(s) needed to perform its administrative duties.
- Special accounts are appointed to roles in a smart contract’s system by updating a key-value mapping that maps an address to a corresponding role. Depending on the design, new roles can be created after deployment, while old roles can be modified.
Role-based permissioning is considered ideal because it remedies most of the problems associated with contract ownership. For example, restricting individual powers minimizes the damage that a privileged account can wreak. It also improves decentralization and fault tolerance since administrative powers are distributed between different individuals.
Role-based permissioning also grants projects more administrative flexibility by encouraging separation of concerns. Administrative duties, such as minting tokens, burning tokens, implementing upgrades, or triggering emergency actions, can be split among entities to ensure efficiency.
That said, it is important to consider the tradeoffs involved with using role-based acres control. One is that having too many roles can make coordination harder and reduce the speed of implementing critical changes. It is also necessary to have a process for revoking authorization for roles to prevent misuse.
How to improve access control in Smart Contracts
Both contract ownership and role-based access control can be improved using the following mechanisms:
A multisignature (often called a multisig) account is a special type of account that requires a minimum number of addresses to sign a transaction before executing it. Multisigs are a powerful addition to your toolbox for access control and provide the following benefits:
- Decentralization: Sometimes, managing administrative actions from one account (i.e., Ownable pattern) may be ideal. In this case, setting a multisignature account as the Owner of a smart contract ensures that no single entity has total control. This is an approach adopted by many Web3 projects, such as Compound and Balancer.
- Fault tolerance: A multisig uses an m-of-n signing scheme, where m and n can be set to different values to achieve fault tolerance. For example, using a 3-of-5 multisig for contract administration ensures that:
- Changes can be made so long as ⅗ of the participants are available
- If at least three parties are honest and refuse to sign a malicious proposal, then the contract remains secure.
One way to improve access control in a smart contract is to use a timelock. A timelock is a mechanism that restricts access to a contract’s functions or variables until a specific time or block height is reached. Timelocks can improve access control schemes in the following ways:
- Delaying contract execution: A common pattern is to set a timelock contract as the owner of a protocol’s contract(s). Under this setup, transactions that perform administrative operations in a protocol contract must first pass through a time-locked process. This ensures that users have enough time to react to a new protocol change and potentially exit the system if necessary.
- Stalling malicious actions: Delaying the execution of sensitive functions—like transferring ownership or minting tokens—provides an additional layer of security for smart contracts. Even if an attacker managed to gain certain privileges (either by hijacking whitelisted accounts or targeting unprotected functions), you still have enough time to respond to the action.
Uniswap’s Timelock contract is a great example of controlling administrative actions using timelocks.
Access control remains a critical aspect of smart contract security–one that demands balancing efficiency and security. Moreover, you’ll need to implement safeguards (e.g., timelocks and multisigs) to guard against malicious actions and aid decentralization in access control mechanisms.
Reliability and transparency also matter for access control. You should highlight different privileged accounts in a smart contract’s system (and their powers) and notify users if a detail in the access control mechanism changes (e.g., via log events).
For example, you can program a contract to emit events whenever a new role is added or ownership is transferred to another account. This keeps users in the loop, promotes accountability, and shows a commitment to transparency.