Qui a vraiment appelé : la faille d'authentification tx.origin
Le défi
Le vault on-chain de Pembrook ne laisse retirer des fonds qu'à son propriétaire, et la clé du propriétaire n'a jamais fuité. Pourtant, le vault a été vidé après que le propriétaire a utilisé un nouveau site d'airdrop lui demandant de cliquer sur Claim. La protection de withdraw fait ce que l'auteur a écrit : l'auteur a simplement posé la mauvaise question sur l'identité de l'appelant. Lisez le contrat et nommez l'expression, dans la vérification du propriétaire, qui a permis à un contrat avec lequel le propriétaire n'a fait qu'interagir de dépenser en son nom.
Ce que tu vas apprendre
- Distinguer msg.sender (appelant immédiat) de tx.origin (signataire de la transaction)
- Expliquer comment un contrat de phishing maintient tx.origin égal à la victime
- Identifier tx.origin dans un contrôle d'accès comme la vulnérabilité
- Le comparer à un contrôle de propriété correct basé sur msg.sender
- Énoncer la règle : autoriser avec msg.sender, pas avec tx.origin
Compétences testées
Prérequis
- Lire du Solidity
- Savoir ce qu'est une chaîne d'appels entre contrats
Comment ça marche
Chaque appel Solidity voit deux identités. msg.sender est celui qui a appelé directement cette fonction, ce qui peut être un autre contrat. tx.origin est le compte externe (EOA) qui a signé toute la transaction, inchangé quel que soit le nombre de contrats traversés par l'appel.
Autoriser sur tx.origin ouvre la porte au phishing. Si le owner est incité à appeler un contrat malveillant, et que ce contrat appelle le vault, alors dans le vault msg.sender est le contrat malveillant mais tx.origin reste le owner. Un contrôle tx.origin == owner passe, et le code de l'attaquant dépense en tant que owner sans jamais toucher à la clé du owner.
La fonction transferOwnership du même contrat montre la forme correcte : elle compare msg.sender, qui ne peut pas être piloté via un intermédiaire.
Erreurs fréquentes
- Répondre
msg.sender. C'est le contrôle sûr, utilisé correctement danstransferOwnership. - Accuser une clé divulguée. Aucune clé n'a fuité : le owner a été piégé pour qu'il initie la transaction.
- Pointer
transferou le contrôle du solde. Ils sont corrects : la faille se trouve dans la façon d'identifier le owner. - Parler de reentrancy. Rien ne ré-entre : l'appel unique passe simplement une protection vulnérable au phishing.
Comment s'en protéger
Identifiez les appelants avec msg.sender.
- Remplacez
tx.origin == ownerparmsg.sender == ownerdans chaque contrôle d'accès. - Évitez complètement
tx.originpour l'autorisation. Ses rares usages légitimes sont déconseillés, et l'account abstraction érode encore la notion d'origine unique. - Ajoutez des tests qui appellent les fonctions privilégiées via un contrat intermédiaire, afin qu'une protection vulnérable au phishing échoue en CI.