--- title: Blind Signing tags: protocol --- # Blind Signing [toc] ## Summary This document will go over: * How current FA2 marketplaces work. * What kind of attacks are possible against users of the FA2 marketplace. * What we can do to prevent such attacks. We focus on the security of FA2 tokens as they are the biggest non-XTZ store of wealth in Tezos hence the most appealing attack surface. ## Players Here is a list of players that we will reference in our following examples. * ***Alice:*** Developer of an FA2 token marketplace. * She owns two contracts: * ***FA2 contract***: manages some asset * ***Marketplace contract***: handles the business logic of the marketplace (auctions, listing, etc.). * And one website: * ***Marketplace website:*** Provides UI for the marketplace. * ***Bob***: A normal Dapp user that holds assets in Alice's FA2 contract * ***Charlie***: A normal Dapp user that is interested in buying Bob's assets * ***Mallory***: A malicious attacker who is trying to steal Bob's assets ## How things work Here is how Bob interacts with Alice's token marketplace: 1. Bob visits Alice's marketplace website to execute operations on his tokens. 1. Alice's marketplace website generates a *transaction batch* that calls Alice's FA2/marketplace contract in some sequence. 1. Bob signs the transaction batch via his wallet. The contents in the *transaction batch* in 2. depend on the kind of operation Bob initiates. Let's take a look at two examples. ### Example 1: Bob sends a token to Charlie ```sequence participant Bob participant Alice's market website participant Alice's FA2 contract Alice's market website->Bob: transaction batch Bob->Bob:sign batch Bob->Alice's FA2 contract: transfer Alice's FA2 contract->Alice's FA2 contract: transfer ownership to Charlie ``` If Bob wants to send his token to Charlie the transaction batch will contain a single call to Alice's FA2 contract's [`transfer`](https://gitlab.com/tezos/tzip/-/blob/master/proposals/tzip-12/tzip-12.md#transfer) entry-point. ### Example 2: Bob lists his token for sale ```sequence participant Charlie participant Bob participant Alice's Market website participant Alice's Market contract participant Alice's FA2 contract Alice's Market website->Bob: transaction batch Bob->Bob:sign batch Bob->Alice's FA2 contract: update_operator Bob->Alice's Market contract: register as "for sale" Note over Charlie,Bob:...Some time passes... Charlie->Alice's Market contract: Buy Bob's token in sale Alice's Market contract->Alice's FA2 contract: transfer Alice's FA2 contract->Alice's FA2 contract: transfer ownership to Charlie ``` If Bob wants to list his token for sale at a particular price: * Bob will sign a transaction batch that contains: * A call to Alice's FA2 contract's [`update_operator`](https://gitlab.com/tezos/tzip/-/blob/master/proposals/tzip-12/tzip-12.md#operators) entry point that adds Alice's marketplace contract as an operator. This enables Alice's marketplace contract to transfer Bob's token freely. * A call to Alice's marketplace contract registers Bob's token as "for sale". * When Charlie wants to buy the token: * Charlie will sign a transaction to Alices' market contract for buying the token. * Alice's market contract will transfer Bob's token to Charlie by calling Alice's FA2 contract. This is possible because Bob registered Alice's market contract as an operator. ## Attack senarios For Mallory to steal Bob's assets, she will need to create a malicious website. Let's look at what kind of malicious website she can create.For both senarios, Mallory will exploit the fact that Bob signs a transaction without fully knowing it's content, which is a problem called *blind signing*. ### Scenario 1: Fake marketplace website In this senario, Mallory will create a fake marketplace website that interacts with a fake marketplace contract. Here is how the attack will play out: * Mallory deploys a fake marketplace website and a fake marketplace contract. * Bob visits Mallory's fake marketplace website. * Bob tries to transfer a token to Charlie: * Mallory's website creates a `transfer` transaction for Alice's FA2 contract, but the receiver will be Mallory instead of Charlie * Bob tries to list his token for sale: * Mallory's website creates a transaction batch with: * `update_operators` transaction to Alice's FA2 contract that adds Mallory as an operator. * A "register for sale" call to Mallory's fake market contract that does nothing (it can update some "for_sale" field to seem legit when inspecting the transaction, but such a "for_sale" field will never be used). * Later, Mallory will transfer Bob's token to her own account using her operator status. ### Scenario 2: Fake airdrop website In this senario, Mallory will create an airdrop site. The advantage of this approach for Mallory is that it can potentially attract more users. Here is how the attack will play out: * Mallory deploys a malicious website that claims to give out airdrops. * Bob visits Mallory's malicious website to receive an airdrop. * Mallory's website creates a single transaction that calls Alice's FA2 contract's [`transfer`](https://gitlab.com/tezos/tzip/-/blob/master/proposals/tzip-12/tzip-12.md#transfer) entry point (or `update_operators` entry point that adds Mallory as an operator), presents it in the website UI as if it is for the airdrop. * Bob signs the above transaction thinking it is for receiving the airdrop. ## Potential security solutions ### Solution 1: Contract white list in wallets Have wallets maintain a "contract white list" that contains contracts that are probably safe to interact with. Contracts in this list will be, for example, * Contracts registered in some global contract registry. * Contracts that the wallets have interacted with in the past. #### What does this protect against? * ✅ Gives good protection against fake marketplaces (scenario 1). * Bob will be alerted that the market contract address has changed since his last interaction. * ❌ While FA2 contract are updated rarely, the market contract would. This can lead to frequent false alarms. * ❌ Doesn't provide good protection against the fake airdrop website (scenario 2). * Airdrop sites are short living by design, and Bob might expect them not to be in the white list. #### Implementation difficulty * Someone would have to manage the "global contract registry," which can either be a central server of a smart contract. The process of adding contracts to the registry will require careful coordination. * Alerting users when they first interact with a contract that is not in the registry would probably be bad UX. ### Solution 2: Better insights into transactions Have wallets display better insight into the transaction that is being signed. This is already being done for some standard entry points such as `transfer` of FA2 (left image from Kukai), but insights are lacking for other entry points such as `update_operator` (right image from Kukai). For the `update_operator` case we should also display the contract metadata, etc. ![](https://i.imgur.com/O3h5Pwh.png =250x) ![](https://i.imgur.com/1g6TeYb.png =200x) Such insight can be generated based on: * Token standards such as FA2. * Metadata provided via the contract dev explaining the entry point (this metadata can be standardized as an extension of TZIP-16). #### What does this protect against? * ❔Gives some protection against the fake marketplace website (scenario 1). * ❌ The called entry points and their associated insights will seem natural for Bob as he actually intends to interact (transfer, list, etc.) with his tokens. * ❌ For calls to the fake marketplace contract, Mallory can simply lie in the metadata. * ✅ But the insight can highlight the "target address" of the operation (the token receiver for `transfer`, the added operator for `update_operator`). Bob might notice something is wrong with the target address. * ✅ Gives good protection against the fake airdrop website (scenario 2). * Bob should be alerted if messages such as "are you sure you want to transfer your token?" or "are you sure you want to give this contract full control over your token?" in an airdrop website. #### Implementation difficulty * Insights for TZIP standardized entry points should be relatively easy. It is already being done for the FA2 `transaction` entry point, etc. * Insights for non-TZIP standardized entry points will require standardizing the entry point metadata in some TZIP. ### Solution 3: Postconditions (Postconditions was proposed in this [agora post](https://forum.tezosagora.org/t/postconditions-on-transactions/4516)) Implement a proto update that enables wallets to inject *postconditions* when signing batch transactions. Postconditions are Michelson lambdas that take the batch operation result (i.e., receipt) and return a bool indicating whether to accept/reject the operations. If the lambda returns false, the whole batch will be rejected, and no effect will be taken. Wallets can have a set of "default postconditions" that they inject into every transaction. Such postconditions would include things like "disallow token transfer". Wallet users can relax the condition if needed with explicit approval. #### What does this protect against? * ❔Gives some protection against the fake marketplace website (scenario 1). * If we display the target address when prompting to relax the "disallow token transfer" postcondition, the situation would be the same as the "Solution 2" case. * ✅ Gives good protection against fake airdrop scenario (scenario 2). * Bob will be prompted to relax his "disallow token transfer" postcondition. **Note:** There seem to be more interesting use cases for postconditions when the batch transactions are more "self-concluding." The `update_operator` in scenario 1 is not self-concluding in the sense that Bob has to finish the batch with a "dangling" `update_operator` and wait for another party to conclude the transfer. A more self concluding example would be [flash loans](https://docs.aave.com/developers/guides/flash-loans): In this case, Bob can inject a postcondition that guarantees that the token is sent back to him at the end of the transaction batch. #### Implementation difficulties There are two fundamental difficulties in implementing postconditions: * There is no way to reliably detect token transfers in FA2 contract as their storage layout will differ between implementations. * This can be solved by a wider use of tickets and/or [standarized events](https://forum.tezosagora.org/t/fa2-1-fa3-its-time/3704/33?u=linoscope) for token transfer, but adaptation tickets/event standard will take time. * Events and tickets can contain arbitrary types within them, making it impossible uniformly type them in current Michelson. * One way to overcome this is to represent the receipt as bytes and dynamically decode them, but that would be very complex. * Heard that "dynamic types" could solve this but haven't had the time to read about it yet: [dynamic types in Michelson](https://gitlab.com/tezos/tzip/-/blob/master/drafts/current/draft-dynamic-types-in-michelson.md) ## Conclusion It seems like some combination of Solution 1 and Solution 2 will give us good security coverage (can provide good protection against both Scenario 1 and Scenario 2). These will not require a protocol update but will require a lot of help from the wallet devs. Postconditions is a cool idea, but we will need to find more use cases to justify the technical difficulties of implementing them.