Handing authorization
When developing a contract, you may want to restrict who can call a certain entrypoint or perform a certain action. In this case you must ensure that:
- The request comes from an authorized entity
- The authorized entity cannot be tricked into sending the request
To determine which account sent a request, you may be tempted to get the source of the transaction. In Tezos, the source of the transaction is the address of the account that submitted the operation that started a chain of operations, but not necessarily the account that sent the immediate transaction that the contract is running now. Relying on the source of the transaction can allow a malicious contract to impersonate an account when it calls another contract.
For this reason, contracts should never use the transaction source for authorization purposes.
Remember:
- Source: The address of the account that created the first operation in a chain of operations
- Sender: The address of the account or smart contract that created the most recent transaction in the chain
For example, assume that account A calls smart contract B, which generates an operation to call smart contract C. When C runs, in Tezos terms, account A is the source of the transaction and smart contract B is the sender of the transaction. Therefore, if it uses the source to determine which account calls it, contract B could trick it into thinking account A called it. In this way, a malicious contract can invite accounts to make seemingly innocent transactions and use the operation chain to impersonate those users in other transactions.
Checking whether the sender (the address of the immediate caller) is authorized to perform an operation is better. Because the request comes directly from an authorized entity, contracts can be more confident that the call is legitimate. This approach is a good default choice if both conditions hold true:
-
The sender contract is well secured against emitting arbitrary operations. For instance, it must not contain a certain kind of "off-chain view" entrypoint. Ordinary on-chain views do not have this vulnerability because they cannot create operations. For more information about views, see Views.
-
You need to authorize only an immediate caller and not the contracts somewhere up in the call chain.
Using tickets for security
If either of these conditions is not met, you may need to use tickets to authenticate requests. Tickets can be transferred, but they always have the address of the contract that created them as their ticketer.
In this way, tickets allow you to verify that requests came from a certain contract. For example, you can set up a contract that authenticates requests by requiring a ticket with the request, using the address of the ticketer to determine the permissions for the action, and using the data in the ticket as the parameters or input for the request.
In general, sender-based authorization is appropriate only for simple scenarios, such as when the contract has a single "owner" address controlled by a user account. In more complex scenarios, ticket-based authorization is often better.