web-dev-qa-db-fra.com

Est-ce que C est un bon choix pour les logiciels liés à la sécurité?

C est un langage de programmation solide et répandu qui est très populaire, en particulier dans la communauté FOSS.

De nombreux logiciels liés à la sécurité (tels que les bibliothèques de chiffrement) sont écrits en C et le seront probablement également à l'avenir. L'une des principales raisons en est la grande performance et la portabilité des programmes C. Mais le fait est que même les développeurs de logiciels très expérimentés ne peuvent pas empêcher les bugs comme les dépassements de tampon. Chaque année, de nombreux bogues de sécurité liés à la gestion de la mémoire se trouvent dans des logiciels même très populaires et examinés.

Ma question est donc la suivante: est-ce encore une bonne idée d'écrire des logiciels liés à la sécurité en C de nos jours? Ou n'est-ce pas "sécurité par conception" de choisir des langages modernes comme Rust, Go ou des langages plus avancés comme Python?

33
Aliquis

La raison principale et presque unique pour laquelle la plupart des logiciels de l'écosystème Linux sont écrits en C est Tradition. Les développeurs voient les logiciels écrits en C, les bibliothèques avec une API basée sur C, et donc ils utilisent C, parce que c'est pratique. Les compilateurs sont déjà là et fonctionnent bien car tout le système d'exploitation est écrit en C.

Rien de tout cela ne dit que C est bon pour développer un logiciel robuste. En fait, C est assez terrible. Avec C, le développeur doit toujours se méfier de beaucoup de choses. C dispose de nombreux pièges prêts à être déclenchés sur les plus petites erreurs, notamment:

  • Accès aux baies non contrôlés, permettant ainsi des débordements.
  • Gestion manuelle de la mémoire, entraînant des erreurs d'utilisation après libération ou double libération et des fuites de mémoire.
  • Le "comportement indéfini" redouté qui rend les expressions apparemment raisonnables se déchaînent (en particulier, les opérations signées qui dépassent la plage représentable).
  • Problèmes de portabilité lors de l'utilisation d'architectures de différentes longueurs pour les types entiers et les pointeurs.

Ce que C est vraiment bon dans les domaines suivants:

  • Interagir avec un ensemble existant de bibliothèques offrant une API C. C est la lingua franca qui permet l'interopérabilité entre les composants logiciels sur de nombreuses plateformes.

Ce que C est passablement bon est:

  • Écriture de code de très bas niveau (par exemple, code cryptographique résistant aux attaques de synchronisation via des modèles d'accès à la mémoire fixes) tout en essayant de maintenir un certain niveau de portabilité.

Ma conclusion est que C n'est pas une bonne idée pour écrire des logiciels liés à la sécurité en général , et ce n'est pas le cas depuis un certain temps déjà (au moins une décennie). C est toujours justifié dans certains contextes spécifiques, en particulier si vous ciblez des plateformes embarquées (non embarquées comme dans "smartphone", plutôt embarquées comme dans "carte à puce"). Au lieu de chercher des raisons de s'éloigner de C, il serait plus justifié de chercher des raisons spécifiques pour continuer à utiliser C.

49
Tom Leek

Vous pouvez écrire du code sécurisé en C. C'est juste que la langue est dangereuse par défaut. La sécurité doit être clouée manuellement avec du code supplémentaire (qui bien sûr peut lui-même contenir des bogues).

Pour cette raison, C n'a jamais vraiment le meilleur choix pour les logiciels critiques pour la sécurité. Il a été utilisé de toute façon dans FOSS car les compilateurs gratuits étaient historiquement disponibles sur à peu près toutes les plates-formes (par définition pour chaque plate-forme prise en charge par gcc).

Le conseil général pour les logiciels critiques pour la sécurité, si vous n'êtes pas lié à une langue spécifique (comme C) est d'utiliser Ada. Ce langage est à un niveau d'abstraction similaire à C ou C++, mais par défaut vers la sécurité (par exemple: vérification automatique des limites pour tous les tableaux) avec la possibilité d'ajouter du code à désactivez les vérifications, plutôt que l'inverse.

En particulier, il existe un sous-ensemble d'Ada appelé SPARK qui est conçu spécifiquement pour la sécurité et les logiciels critiques. Il peut également être utilisé pour la vérification formelle d'un logiciel, si vous êtes dans ce genre de chose.

25
T.E.D.

Tout d'abord, pour des choses telles que le cryptage les performances sont importantes.

C'est la différence entre pouvoir servir des centaines d'utilisateurs ou seulement 10 à la fois. Et cela présente une certaine sécurité: si vos serveurs rencontrent des difficultés, ils sont faciles à supprimer avec une attaque DOS.

Si vous avez déjà comparé du code python pur contre du code natif), vous serez surpris par l'ampleur des différences.

Deuxièmement, il n'y a pas de Python/Java sans C. Quel que soit le langage "moderne" que vous regardez, il utilise une quantité substantielle de bibliothèques en dessous. Et devinez quoi, la majorité d'entre elles sont des bibliothèques C.

Maintenant, si vous écrivez une bibliothèque "critique pour la sécurité" dans un tel langage, vous devez vous inquiéter 1. des problèmes dans votre propre code 2. des problèmes dans le code Java/Python que vous utilisez 3. des problèmes dans le code C sous-jacent (il y a une sécurité fréquente mises à jour de Java!) et 4. problèmes dans les bibliothèques C en dessous qui peuvent changer sans que vous le sachiez (par exemple les mises à jour du système d'exploitation). Si vous voulez un code pertinent pour la sécurité, minimisez les dépendances.

Le la quantité de C en dessous augmente, ne diminue pas. Cela peut ne pas sembler évident. Mais numpy, tensorflow, JavaFX, ... tous utilisent beaucoup de code C en dessous, à cause des performances .

De nombreux problèmes pourraient être évités par une ingénierie minutieuse et une programmation détaillée . Par exemple, le bug OSX "goto fail" a été provoqué par des programmeurs ne respectant pas la meilleure pratique de toujours utiliser des crochets ...

if (a)
  goto fail;
  goto fail;
somethingelse

est une erreur facile à manquer dans la plupart des langues (sauf Python, où vous auriez besoin de deux espaces de moins pour le même problème) qui peut être évitée simplement avec la verbosité:

if (a) {
  goto fail;
  goto fail;
}
somethingelse

Ce n'est pas comme si python serait très utile pour éviter de tels problèmes (en fait, Java vous avertiraient du code inaccessible - Python ne le fait pas, et les compilateurs C peuvent si activé par l'utilisateur) ... En fin de compte discipline du développeur reste un facteur clé.

Le code C nécessite généralement beaucoup plus de soin pour l'écriture; ce qui n'est pas une mauvaise chose pour la qualité. Le principal inconvénient est qu'il est plus lent à se développer.

5

Le C est utilisé par des millions de personnes depuis plus de 20 ans. Ses failles de sécurité, comme celle avec scanf () sont bien connues et documentées, et il existe des solutions de contournement établies et fortement testées.

Un langage plus récent, par exemple Perl 6 ou python 3 n'est utilisé que depuis peu de temps, peu de gens sont experts en la matière, des failles de sécurité peuvent encore exister et un examen critique et la documentation est rare.

Ces deux nouveaux langages sont beaucoup plus `` grands '' que C avec beaucoup plus de capacités, et cela peut prendre énormément plus de 20 ans avant que toutes les constructions de programmation possibles aient été utilisées, et nous pouvons être sûrs de leur sécurité.

2
Arif Burhan

C'est de bas niveau et totalement dangereux par défaut. Bien sûr, il est possible d'écrire des logiciels sécurisés - mais vous devez être bon dans ce domaine. OTOH: C est de bas niveau et vous n'avez pas besoin d'inclure des bibliothèques qui pourraient avoir leurs propres problèmes de sécurité - cela pourrait être bon. Il ne faut pas non plus oublier qu'un langage "sécurisé" signifie qu'il y a des programmes impliqués qui, encore une fois, sont un problème de sécurité possible.

Personnellement [~ # ~] i [~ # ~] recommanderait probablement d'utiliser Rust = car il peut être suffisamment bas et se concentre également sur la sécurité.

Je n'utiliserais pas de code non natif (c'est-à-dire pas Java, C #, etc.) sauf si vous livrez votre propre runtime. Il en va de même pour toutes les bibliothèques auxquelles vous créez un lien, mais cela peut être évité contrairement au code non natif.

Dans l'ensemble, vous devez vous concentrer sur le moins de code possible, c'est-à-dire. faites-le aussi simple que possible et ne faites pas confiance à un autre code. En revanche, si vous pouvez l'éviter, ne vous fiez pas à l'écriture de code sécurisé - ce n'est généralement pas bon.

0
larkey