Qu'est-ce qu'une condition de course
Étant donné que les développeurs oublient souvent que le code peut être exécuté par plusieurs threads en même temps, ils ne testent pas le produit pour une condition de concurrence, bien que cette erreur soit assez courante.
Du point de vue du backend, cela ressemble à ceci: plusieurs threads accèdent simultanément à la même ressource partagée: des variables ou des fichiers pour lesquels il n'y a pas de blocage ou de synchronisation. Cela conduit à une sortie de données incohérente.
Voici un exemple concret d'une telle vulnérabilité. Disons que nous avons une application qui vous permet de transférer des bonus entre des portefeuilles de paiement. L'attaquant a deux portefeuilles - A et B, et chacun d'eux a 1000 bonus. Le diagramme montre comment en manipulant l'heure d'envoi d'une demande de transaction, un attaquant peut augmenter le montant du transfert sur son compte et faire 10 bonus sur 20.
Il existe des outils automatiques pour rechercher de telles vulnérabilités. Par exemple, RacePWN, qui en un minimum de temps envoie de nombreuses requêtes HTTP au serveur et accepte la configuration json en entrée, facilitant ainsi le processus d'attaque des cybercriminels. Cela se fait manuellement en envoyant des requêtes POST.
Condition de race mortelle
Aux États-Unis, de juin 1985 à janvier 1987, une erreur de condition de course dans un appareil de radiothérapie Therac-25 créé par l'organisme d'État canadien Énergie atomique du Canada limitée (EACL) a causé six surdoses de radiation . Les victimes ont reçu des doses de dizaines de milliers de joyeux. Le niveau de 1000 est considéré comme mortel. Après les brûlures qui en ont résulté, les victimes sont décédées en quelques semaines. Un seul patient a réussi à survivre.
Les modèles Therac précédents avaient des mécanismes de protection matérielle: des circuits de blocage indépendants qui contrôlent le faisceau d'électrons; bloqueurs mécaniques; disjoncteurs matériels; débrancher les fusibles. La protection matérielle a été supprimée dans Therac-25. Le logiciel était responsable de la sécurité. L'appareil avait plusieurs modes de fonctionnement et, en raison d'une erreur de condition de course, le médecin ne comprenait parfois pas dans quel mode l'appareil fonctionne réellement. Au cours de la procédure judiciaire, il s'est avéré que le logiciel Therac-25 avait été développé par un programmeur, mais EACL n'avait pas d'informations sur qui exactement.
À la suite de ce processus, le gouvernement américain a sérieusement resserré les exigences relatives à la conception et à l'exploitation de systèmes dont la sécurité est essentielle pour les personnes.
Comment se protéger
Le moyen le plus simple et le moins cher de résoudre le problème des conditions de concurrence consiste à concevoir correctement l'architecture de l'application. Voici ce qu'il faut prévoir pour cela.
- Verrouillage des enregistrements critiques dans la base de données. Il existe différentes manières de vous assurer de travailler avec l'enregistrement d'un flux à un moment donné. L'essentiel est de ne rien bloquer d'inutile.
- Isolement des transactions dans la base de données , ce qui garantit que les transactions sont validées de manière séquentielle. Le plus important ici est de trouver un équilibre entre sécurité et vitesse.
- . . , , , . , , , .
Notre client est un magasin de livraison d'épicerie en ligne qui prend en charge la fonction de fournir des remises à l'aide de coupons. Lors des tests, nous avons découvert une vulnérabilité - lors de l'envoi d'une requête POST avec une valeur de coupon. En envoyant une demande avec des délais différents, il était possible d'obtenir une réduction deux fois. Apparemment, les développeurs ont commis une erreur grossière liée à l'accès partagé à l'objet identifié lors de l'achat.
Il y avait très probablement un tel pseudo-code sans mécanismes de synchronisation:
…
1 Si promo_flag n'est pas défini:
2 Price = get_price ()
3 Price - = price * promo_percent;
4 set_price (prix)
5 set_promo_flag ()
...
Ici, appliquer un code promo et définir le drapeau approprié n'est pas une opération atomique. Très probablement, lorsque la deuxième application du code promotionnel a commencé, la première s'est arrêtée sur la 5ème ligne (c'est-à-dire qu'elle n'a pas encore été exécutée). À ce moment, la fonction get_price () de la deuxième ligne a renvoyé une nouvelle valeur de prix, déjà avec une remise.
Décision
Le problème est résolu simplement:
…
1 acqure_mutex ()
2 Si promo_flag n'est pas défini:
3 Price = get_price ()
4 Price - = price * promo_percent;
5 set_price (price)
6 set_promo_flag ()
7 release_mutex ()
...
Maintenant, l'application du code promo sera effectuée complètement et complètement une fois. Même lorsqu'une situation survient dans laquelle le deuxième thread essaie d'appliquer le code promotionnel alors que le premier processus est déjà occupé avec le traitement, il ne pourra pas le faire. Le mutex bloquera l'accès à la "section critique", et le second processus devra attendre que le premier soit terminé.
La condition de race ne doit pas être sous-estimée. Mieux vaut consacrer du temps et des ressources à la recherche de vulnérabilités afin d'éviter des conséquences imprévues, y compris sur le budget de l'entreprise.
Blog ITGLOBAL.COM - Managed IT, clouds privés, IaaS, services de sécurité de l'information pour les entreprises:
- Comment nous avons découvert la vulnérabilité du serveur de messagerie de la banque et comment elle menaçait
- Sécurité de l'information en 2021. Menaces, tendances de l'industrie
- Les sites populaires sont toujours vulnérables aux attaques DDoS massives
- Pourquoi les hackers éthiques devraient travailler ensemble pour s'introduire dans les entreprises. Entretien avec le chasseur de bogues Alex Chapman
- Peur de l'automatisation du travail et autres tendances de la cybersécurité mondiale et russe