Pourquoi les contrats intelligents sont audités
La plupart des logiciels peuvent être corrigés après la découverte d’un bogue. Un contrat intelligent sur une chaîne publique, habituellement pas. ethereum.org souligne que le code d’un contrat déployé ne peut généralement pas être modifié pour corriger une faille, et estime que la valeur volée ou perdue à cause de défauts de sécurité dans les contrats intelligents dépasse facilement 1 milliard $ [1]. Le code détient souvent de l’argent directement, il est public et tout le monde peut l’étudier, et un attaquant n’a besoin de trouver qu’une seule erreur.
C’est pourquoi les contrats qui détiennent de la valeur sont révisés par des spécialistes extérieurs à l’équipe qui les a écrits, avant leur déploiement. La question n’est pas de savoir s’il faut cette revue, mais ce qu’elle peut faire pour vous, et ce qu’elle ne peut pas faire.
Ce que fait un audit
Un audit est une revue limitée dans le temps d’une version précise de vos contrats, par des ingénieurs en sécurité qui ne les ont pas écrits. Un mandat typique se déroule ainsi.
- 01
La portée
Les auditeurs conviennent des contrats visés, à quel commit, et lisent votre documentation sur ce que le système doit faire.
- 02
La revue manuelle
Des réviseurs d’expérience lisent le code ligne par ligne, à la recherche de catégories connues de vulnérabilités (réentrance, erreurs de contrôle d’accès, appels non vérifiés, erreurs d’arithmétique et d’arrondi) et de logique qui ne correspond pas à l’intention déclarée.
- 03
L’analyse automatisée
Des analyseurs statiques, des outils de fuzzing et parfois des outils formels cherchent des motifs et des cas limites qu’une personne pourrait manquer.
- 04
Le rapport
Les constats sont classés par gravité, de critique à informatif, chacun avec une explication et une correction recommandée.
- 05
La revue des correctifs
Votre équipe corrige les constats, et les auditeurs vérifient les correctifs. Le rapport final indique quels constats ont été résolus, reconnus ou laissés ouverts.
Les failles que les auditeurs trouvent le plus, en clair
- La réentrance : le contrat envoie des fonds ou appelle un autre contrat avant de mettre à jour ses propres registres, et l’autre contrat le rappelle pour prendre les mêmes fonds une deuxième fois.
- Le contrôle d’accès : une fonction qui devrait être réservée à un administrateur peut être appelée par n’importe qui, ou un rôle d’administrateur peut être usurpé.
- La manipulation de prix : le contrat lit un prix à une source qu’un attaquant peut faire bouger dans une seule transaction, comme un bassin d’échange peu liquide.
- L’arrondi et la précision : de petites erreurs de division qu’un attaquant répète des milliers de fois, ou qui permettent à un premier déposant de fausser les parts de tous ceux qui suivent.
- Les erreurs de mise à niveau : un mandataire qui pointe vers le mauvais code, un stockage qui entre en collision d’une version à l’autre, ou une fonction d’initialisation que n’importe qui peut appeler.
- Une logique qui fait ce que dit le code, mais pas ce que voulait l’entreprise : des frais prélevés deux fois, une échéance vérifiée à l’envers.
Ce qu’un audit ne couvre pas
ethereum.org est clair là-dessus : les audits n’attrapent pas tous les bogues, et servent surtout à ajouter une ronde de revue [1]. De plus, la plupart des audits ne portent que sur le code des contrats. Bien des pertes viennent d’ailleurs.
| Volet | Pourquoi c’est important | Ce qui le couvre plutôt |
|---|---|---|
| Le code modifié après l’audit | Le rapport vaut pour un seul commit. Un changement ultérieur, si petit soit-il, n’est pas audité. | Une revue des correctifs ou un nouvel audit pour chaque changement au code audité |
| Les clés privées et les comptes d’administration | Qui détient la clé de mise à niveau ou d’administration peut souvent modifier ou vider le système. | Des portefeuilles multisignatures, des clés matérielles, des délais de garde et des procédures écrites |
| Le site web et le serveur | Une interface compromise peut demander aux utilisateurs de signer quelque chose de nuisible. | Des tests de sécurité d’applications web et des contrôles de la chaîne d’approvisionnement logicielle |
| Les oracles et les données externes | Un contrat qui se fie à un flux de prix n’est sûr que dans la mesure où ce flux l’est. | Une revue de conception du choix d’oracle, des limites et des solutions de repli |
| La conception économique | Le code peut fonctionner exactement comme écrit et rester exploitable par les incitatifs ou la manipulation de marché. | Une revue économique et de théorie des jeux, des simulations |
| Le déploiement et la configuration | De mauvais arguments de constructeur ou de mauvaises adresses peuvent annuler un audit parfait. | Des déploiements scriptés et révisés, et une vérification sur la chaîne |
Comment lire un rapport d’audit
- 01
Vérifiez le commit
Le rapport nomme la version exacte révisée. Assurez-vous qu’elle correspond, octet pour octet, à ce que vous avez déployé, et que les contrats déployés sont vérifiés sur la chaîne.
- 02
Lisez la portée et les hypothèses
Quels contrats étaient visés, lesquels ne l’étaient pas, et ce que les auditeurs ont supposé au sujet des administrateurs, des oracles et des autres contrats.
- 03
Regardez le statut de chaque constat
Résolu, reconnu ou ouvert. Un constat critique reconnu est une décision d’affaires que quelqu’un doit pouvoir expliquer.
- 04
Lisez aussi les notes informatives
Elles décrivent souvent des choix de conception que les auditeurs ont jugés risqués sans être erronés, ce qui est utile pour votre prochaine version.
Bien se préparer à l’audit
Le temps des auditeurs est rare et coûteux : chaque heure passée à comprendre du code obscur ou à trouver des bogues que vos tests auraient dû attraper est une heure de moins sur les problèmes subtils pour lesquels vous les payez. Le guide de préparation d’OpenZeppelin expose ce qu’il attend avant un audit.
- Une documentation qui explique l’intention, les choix de conception et les hypothèses, du README et des notes d’architecture jusqu’aux commentaires de chaque fonction [2].
- Des tests qui couvrent les cas limites et l’intégration avec d’autres contrats, en visant une couverture du code d’au moins 90 %, avec du fuzzing là où cela aide [2].
- Un code propre et lisible qui suit un style cohérent, utilise des patrons établis comme vérifications-effets-interactions, et importe ses dépendances par un gestionnaire de paquets plutôt que de les copier [2].
- Un code mûr : testé, documenté et prêt à déployer, plutôt qu’encore en mouvement [2].
Nous ajoutons deux habitudes à nous. Le code est figé à un commit étiqueté pendant toute la durée de l’audit, et chaque correctif passe ensuite par la même revue et la même suite de tests que le travail d’origine avant que les auditeurs le voient.
Les listes de contrôle et les normes, et leurs limites
Les listes de contrôle aident les deux parties à s’entendre sur ce qui a été vérifié. Elles vieillissent aussi. Le registre Smart Contract Weakness Classification, longtemps une référence courante, indique que son contenu n’a pas été mis à jour en profondeur depuis 2020 et qu’il peut être incomplet, et renvoie plutôt à la spécification EEA EthTrust Security Levels et au Smart Contract Security Verification Standard [3]. Demandez à tout auditeur selon quelle norme il vérifie, et accueillez avec prudence une liste de constats reliée uniquement à un vieux registre.
Aucune liste ne remplace la compréhension. Les conseils de Consensys Diligence partent du principe qu’il ne suffit pas de se défendre contre les vulnérabilités connues, et que le développement de contrats exige la discipline de domaines comme les systèmes financiers : se préparer à l’échec et déployer prudemment [4].
La sécurité au-delà de l’audit
Un audit est un instantané. Le contrat fonctionnera pendant des années, le code autour changera, et les attaquants continueront de l’étudier. Les pratiques ci-dessous gardent un système sûr entre deux audits, et la plupart coûtent peu par rapport à ce qu’elles protègent.
- Des tests de propriétés et du fuzzing qui continuent de rouler à mesure que le code change, en plus des tests unitaires [1].
- La vérification formelle pour les invariants les plus critiques, quand le coût le justifie [1].
- Un programme de primes aux bogues après le lancement, pour que les personnes qui trouvent un problème soient payées pour le signaler plutôt que pour l’exploiter [1].
- Un déploiement graduel : des limites sur les dépôts ou les utilisateurs au début, relevées à mesure que le système fait ses preuves [4].
- Une pause d’urgence et une voie de mise à niveau, si la conception les permet, contrôlées par un portefeuille multisignature avec un délai de garde, pour que les changements soient visibles avant de prendre effet.
- Une surveillance de l’activité sur la chaîne et des alertes sur les transactions inhabituelles, avec un plan écrit de qui fait quoi en cas de problème.
Deux projets web3, chiffrés selon notre grille
Les exemples ci-dessous montrent la fourchette selon notre grille tarifaire d’aujourd’hui, avec les heures par rôle et l’échéancier de paiement. Le développement comprend nos propres tests et notre revue de sécurité interne. Un audit externe, quand le contrat le justifie, est chiffré par la firme d’audit et facturé d’avance, au coût, en dehors des étapes.
Exemple chiffré en direct
Un ensemble de contrats intelligents
Des contrats de jeton ou d’entiercement avec un rôle d’administration, une suite de tests complète, du fuzzing et des scripts de déploiement, prêts pour un audit externe.
- Développement
- ≈ 20 700 USD à 31 700 USD, livré en 9 semaines au plus29 500 $ CA à 45 100 $ CA
Les prix dans votre devise sont des estimations au taux du jour de la Banque du Canada. Toute la facturation se fait en CAD ou en USD.
Effort estimé par rôle
- Développement
- 70 à 107 h
- Ingénieur chaîne de blocs
- 32 à 50 h
- Développeur frontal
- 19 à 29 h
- Ingénieur principal
- 16 à 25 h
- Ingénieur assurance qualité
- 15 à 23 h
- Gestionnaire de projet
- 14 à 22 h
- Développeur frontal principal
- 11 à 17 h
- Ingénieur
- 11 à 17 h
- Développeur dorsal principal
- 8 à 12 h
- Développeur frontal junior
- 8 à 11 h
- Développeur dorsal
- 7 à 11 h
- Architecte logiciel
- 4 à 7 h
- Développeur dorsal junior
- 4 à 5 h
- Ingénieur DevOps
- 3 à 5 h
- Rédacteur technique
- 3 à 4 h
- Concepteur de produits
- 2 à 3 h
- Concepteur de produits principal
- 1 à 2 h
Modalités de paiement
- Acompte 30 %
- 8 850 $ CA à 13 530 $ CA
- Spécification 10 %
- 2 950 $ CA à 4 510 $ CA
- Contrats et tests 30 %
- 8 850 $ CA à 13 530 $ CA
- Déploiement sur réseau de test 10 %
- 2 950 $ CA à 4 510 $ CA
- Réseau principal 10 %
- 2 950 $ CA à 4 510 $ CA
- Retenue, 30 jours après la mise en ligne (10 %)
- 2 950 $ CA à 4 510 $ CA
Exemple chiffré en direct
Une dApp avec ses contrats
Des contrats et une application web avec connexion par portefeuille, un volet d’administration, des avis et de l’analytique, sur un design sur mesure avec un plan de soutien.
- Développement
- ≈ 68 400 USD à 105 000 USD, livré en 22 semaines au plus97 400 $ CA à 149 000 $ CA
Les prix dans votre devise sont des estimations au taux du jour de la Banque du Canada. Toute la facturation se fait en CAD ou en USD.
Effort estimé par rôle
- Développement
- 287 à 440 h
- Développeur frontal
- 58 à 89 h
- Gestionnaire de projet
- 50 à 76 h
- Ingénieur assurance qualité
- 50 à 76 h
- Ingénieur chaîne de blocs
- 47 à 71 h
- Concepteur de produits
- 46 à 70 h
- Développeur dorsal principal
- 41 à 62 h
- Développeur dorsal
- 40 à 61 h
- Ingénieur principal
- 37 à 57 h
- Développeur frontal principal
- 35 à 54 h
- Concepteur de produits principal
- 31 à 47 h
- Développeur frontal junior
- 23 à 36 h
- Architecte logiciel
- 21 à 32 h
- Développeur dorsal junior
- 20 à 31 h
- Ingénieur
- 16 à 24 h
- Ingénieur DevOps
- 12 à 18 h
- Rédacteur technique
- 9 à 13 h
Modalités de paiement
- Acompte 20 %
- 19 480 $ CA à 29 800 $ CA
- Découverte 3,5 %
- 3 409 $ CA à 5 215 $ CA
- Spécification 6,3 %
- 6 136,20 $ CA à 9 387,00 $ CA
- Maquettes approuvées 3,5 %
- 3 409 $ CA à 5 215 $ CA
- Fonctions principales 10,5 %
- 10 227 $ CA à 15 645 $ CA
- Développement complet 7 %
- 6 818 $ CA à 10 430 $ CA
- Contrats et tests 19,1 %
- 18 603,40 $ CA à 28 459,00 $ CA
- Tests et corrections 3,5 %
- 3 409 $ CA à 5 215 $ CA
- Déploiement sur réseau de test 6,3 %
- 6 136,20 $ CA à 9 387,00 $ CA
- Mise en ligne 3,5 %
- 3 409 $ CA à 5 215 $ CA
- Réseau principal 6,8 %
- 6 623,20 $ CA à 10 132,00 $ CA
- Retenue, 30 jours après la mise en ligne (10 %)
- 9 740 $ CA à 14 900 $ CA
Choisir un auditeur
- 01
Lisez leurs rapports publics
Les firmes sérieuses publient leurs rapports passés. Cherchez des constats clairs, des niveaux de gravité sensés et des sections de portée honnêtes.
- 02
Demandez qui fera le travail
Le nom et l’expérience des réviseurs affectés à votre mandat comptent plus que la marque.
- 03
Convenez de la portée par écrit
Quels contrats, quel commit, quelles hypothèses, et si une revue des correctifs est comprise.
- 04
Ajustez l’effort au risque
Un contrat qui détiendra une valeur importante peut justifier plus d’un audit indépendant. Un contrat simple bâti sur des bibliothèques auditées peut en demander moins.
- 05
Réservez tôt
Les bons auditeurs sont réservés des semaines à l’avance. Planifiez l’audit au début du développement, pas à la fin.
Nous construisons et testons des contrats, les révisons à l’interne, vous aidons à choisir et à informer un auditeur, et corrigeons les constats. Nous n’auditons pas notre propre travail en le qualifiant d’indépendant.