Halborn Logo

// Blog

Blockchain Security

Designing Secure Access Control For Smart Contracts


profile

Rob Behnke

November 28th, 2022


Access control in cybersecurity defines how an organization restricts access to resources and data in a computing environment. Proper access control is critical, as unauthorized access to sensitive information and operations in a system poses a security risk. 

Access control is even more important for smart contracts, as they live on public blockchains that permit anyone to call functions. In this article, we’ll explain 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 control in smart contracts? 

Access control in smart contracts is a technique for regulating who has the power to perform certain operations in a contract. 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). 

Access control is necessary for protecting critical contract functions from being abused (e.g., by malicious actors). This is achieved by granting special accounts the privilege to trigger specific operations and implementing safeguards such that non-approved entities cannot trigger restricted operations. 

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 control in smart contracts 

Smart contract security

As mentioned, certain functionalities are key to the safety of a smart contract. Consider a contract that implements the proxy pattern for performing upgrades. If access to the upgrade function is never restricted, a malicious actor can potentially alter the contract’s logic. 

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).

Improper access control is one of the vulnerabilities that can affect the security of a smart contract. Take for example the Temple DAO Stax exploit where the attacker managed to mint new tokens without depositing collateral. While the attack exploited weaknesses in the contract, the exploit mostly happened because a sensitive function (migrateStake) was never protected from unauthorized callers. 

User protection 

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 contracts 

The Ownable pattern and role-based permissioning are two common techniques for establishing access control in smart contracts today. Both techniques have unique advantages and drawbacks which we explore in detail:

Ownable pattern

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 should their account get compromised (as we have seen happen many times like with the recent Ronin hack). 

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. 

Role-based permissioning 

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. 

You can check Compound’s Comptroller contract for a real example of role-based permissioning. For instance, the function to set new borrow caps for cToken markets (setBorrowCap) can only be called by the admin or the “borrow cap guardian” (Line #996-997). 

How to improve access control in smart contracts 

Both contract ownership and role-based access control can be improved using the following mechanisms:

Multisigs 

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. 

Timelocks 

In a timelock contract, the state of the smart contract is “locked” for a specified length of time—any state-changing operations triggered during this period cannot execute unless the timelock expires. 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. 

Conclusion

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.