NEO_Security_Development

secure projects on NEO, secure our community

View My GitHub Profile

Access Control and Permissions in NEO N3 Smart Contracts

Access control is a crucial component of smart contract security, ensuring that only authorized users or entities can interact with specific functions. In the context of NEO N3, understanding and implementing robust access control mechanisms is essential to protect your smart contracts from unauthorized access and potential exploits.

Understanding Access Control in NEO N3

In smart contract development, access control mechanisms are used to define who can perform certain actions within a contract. This involves verifying the identity of users or contracts attempting to interact with the contract’s functions. Properly implemented access control ensures that only trusted entities can execute sensitive operations, thereby preventing unauthorized access and maintaining the integrity of the contract.

Notice the Specific Permissions Way in NEO N3

NEO N3 introduces specific considerations for managing permissions that developers need to be aware of:

1. Use CheckWitness Instead of Direct User Comparison:

Example Scenario

In a typical smart contract, you might need to verify if a user has admin privileges before allowing certain actions. An incorrect approach is to directly compare the user with the transaction sender using user == tx.Sender. This method is insecure in NEO N3, as it does not leverage the platform’s best practices for verifying user permissions and can lead to unauthorized access. Here is an example from DogeRift in the first verison.

private static Transaction Tx => (Transaction) Runtime.ScriptContainer;
private static void VerifyOwner()
{
    ByteString owner = ContractMetadata.Get("Owner");
    if (!Tx.Sender.Equals(owner))
    {
        throw new Exception("Only the contract owner can do this");
    }
}

In this scenario, the contract incorrectly assumes that the sender of the transaction (tx.Sender) is the user to be verified. This approach can be bypassed or exploited, especially when dealing with contracts that interact with other contracts. Notice that, as mentioned in our previous discussion on reentrancy, NEP-11 and NEP-17 token transfers can also trigger callback functions like onNEP11Payment and onNEP17Payment. If the contract owner interacts with an unknown contract — whether through a simple transfer to a third party or other interactions to malicious contracts could exploit this by invoking functions that rely on this VerifyOwner method for authorization. This could result in the malicious contract gaining control over the vulnerable contract.

Mitigation Strategies

See DogeRift’s revised version. Directly using CheckWitness could solve this.

private static void VerifyOwner()
{
    ByteString owner = ContractMetadata.Get("Owner");
    if (!Runtime.CheckWitness((Neo.UInt160)owner))
    {
        throw new Exception("Only the contract owner can do this");
    }
}

2. Avoid Your Contract Address as the User:

3. Do Not Implement the verify Method:

Conclusion

Access control and permissions are fundamental to the security of NEO N3 smart contracts. By understanding the specific nuances of NEO N3’s permission model, including the proper use of CheckWitness and avoiding risky practices like implementing the verify method, developers can significantly reduce the risk of unauthorized access. Always prioritize security in your contract design to build robust and trustworthy applications.

Further Reading

For more insights into smart contract security on NEO N3, consider reading the following resources: