Les langages de programmation sûrs gagnent en popularité. Je me demande quelle est la définition officielle du PL en sécurité. Par exemple, C n'est pas sûr, mais Java est sûr. Je soupçonne que la propriété «safe» devrait être appliquée à une implémentation de PL plutôt qu'à la PL elle-même. Si tel est le cas, discutons d’une définition de la mise en œuvre d’une PL sécurisée. Mes propres tentatives pour formaliser cette notion ont abouti à un résultat étrange, j'aimerais donc entendre d'autres opinions. S'il vous plaît, ne dites pas que chaque PL a des commandes dangereuses. Nous pouvons toujours prendre un sous-ensemble sécurisé.
programming-languages
Beroal
la source
la source
Réponses:
Lorsque nous appelons une langue «sûre» à certains égards , cela signifie formellement qu'il est prouvé qu'aucun programme bien formé dans la langue ne peut faire quelque chose que nous considérons dangereux. Le mot «sûr» est également utilisé de manière moins formelle, mais c'est ce que les gens ici comprennent votre question. Il existe de nombreuses définitions différentes des propriétés que nous souhaitons pour un langage «sûr».
Quelques points importants sont:
La définition de «validité de type» d'Andrew Wright et Matthias Felleisen , qui est citée dans de nombreux endroits (y compris Wikipedia) en tant que définition acceptée de «sécurité de type», et leur preuve de 1994 qu'un sous-ensemble de ML satisfait à cette exigence.
Michael Hicks énumère ici plusieurs définitions de «sécurité de la mémoire» . Certaines sont des listes de types d'erreur qui ne peuvent pas se produire, et d'autres sont basées sur le traitement des pointeurs comme des capacités. Java garantit qu'aucune de ces erreurs n'est possible (à moins que vous n'utilisiez explicitement une fonctionnalité marquée
unsafe
) en faisant en sorte qu'un garbage collector gère toutes les allocations et les désallocations. Rust fournit la même garantie (là encore, sauf indication explicite contraire du codeunsafe
), via son système de type affine, qui requiert qu'une variable soit possédée ou empruntée avant d'être utilisée au maximum une fois.De même, le code thread-safe est généralement défini comme un code ne pouvant pas présenter certains types de bogues impliquant des threads et la mémoire partagée, y compris les courses de données et les blocages. Ces propriétés sont souvent appliquées au niveau de la langue: Rust garantit que les données ne peuvent pas être parcourues dans son système de types, C ++ garantit que ses
std::shared_ptr
pointeurs intelligents pointant vers les mêmes objets dans plusieurs threads ne supprimeront pas un objet prématurément ou ne l'auront pas supprimé lors de la dernière référence. Pour le détruire, C et C ++ ont en plus desatomic
variables intégrées dans le langage, avec des opérations atomiques garantissant l’application de certains types de cohérence de la mémoire s’ils sont utilisés correctement. MPI limite la communication interprocessus aux messages explicites et OpenMP a une syntaxe permettant de garantir la sécurité de l'accès aux variables de différents threads.La propriété que la mémoire ne perdra jamais est souvent appelée sécurité pour l'espace. Le ramassage automatique des ordures est une des fonctionnalités linguistiques permettant d’assurer ce résultat.
Beaucoup de langues ont la garantie que ses opérations auront des résultats bien définis et que ses programmes se comporteront bien. Comme Supercat en a donné un exemple, C le fait pour l'arithmétique non signée (garantie de se dérouler en toute sécurité) mais non pour l'arithmétique signée (où le dépassement de capacité est autorisé à provoquer des bogues arbitraires, car C devait prendre en charge des processeurs très différents les uns des autres lorsque l'arithmétique signée débordements), mais le langage convertit parfois en silence des quantités non signées en quantités signées.
Les langages fonctionnels ont un grand nombre d'invariants qu'un programme bien formé est assuré de maintenir, par exemple, que des fonctions pures ne peuvent pas causer d'effets secondaires. Ceux-ci peuvent ou non être décrits comme «sûrs».
Certaines langues, telles que SPARK ou OCaml, sont conçues pour faciliter la vérification de l’exactitude des programmes. Cela peut être ou ne pas être décrit comme "sûr" des bugs.
Preuves qu'un système ne peut pas violer un modèle de sécurité formel (d'où le message suivant: «Tout système qui est sûrement sécurisé ne l'est probablement pas.)
la source
Il n'y a pas de définition formelle de "langage de programmation sûr"; c'est une notion informelle. Les langues qui prétendent offrir une sécurité fournissent généralement une déclaration formelle précise du type de sécurité revendiquée / garantie / fournie. Par exemple, le langage peut fournir une sécurité de type, une sécurité de mémoire ou une autre garantie similaire.
la source
double
oulong
alors qu'elle est modifiée dans un autre thread, pour lequel il n'est pas garanti de ne pas produire la moitié d'une valeur mélangée d'une manière non spécifiée avec la moitié d'un autre), mais la spécification de l'API Cependant, le comportement n'est pas défini dans certains cas.Si vous pouvez mettre la main sur un exemplaire des types et langages de programmation de Benjamin Pierce , dans l'introduction, il a une bonne vue d'ensemble des divers points de vue sur le terme "langage sûr".
Une interprétation proposée du terme qui pourrait vous intéresser est la suivante:
Donc, j'hésiterais à utiliser le terme "peu sûr" pour désigner une implémentation de langage de programmation. Si un terme non défini dans un langage produit un comportement différent selon les implémentations, l'une des implémentations peut produire un comportement plus attendu, mais je ne l'appellerais pas "sans danger".
la source
Coffre-fort n'est pas binaire, c'est un continuum .
De manière informelle, la sécurité signifie l’opposition aux bugs, les 2 plus souvent cités étant:
Ce ne sont pas les seules classes de bugs que les langues empêchent, la liberté de la course des données ou la liberté de l'impasse est plutôt souhaitable, les preuves de correction sont très gentilles, etc.
Des programmes tout simplement incorrects sont rarement considérés comme "dangereux" (uniquement des bogues), et le terme sécurité est généralement réservé aux garanties qui affectent notre capacité à raisonner au sujet d'un programme. Ainsi, C, C ++ ou Go, ayant un comportement indéfini, sont dangereux.
Et bien sûr, il existe des langages avec des sous-ensembles non sécurisés (Java, Rust, ...) qui délimitent délibérément les zones dans lesquelles le développeur est responsable de la gestion des garanties de langage et où le compilateur est en mode "mains libres". Les langues sont encore généralement qualifiées de sûres , malgré cette échappatoire, définition pragmatique.
la source
Obj.magic
en Ocaml). Et dans la pratique, ils sont vraiment nécessairesBien que je ne sois pas en désaccord avec la réponse de DW, je pense que cela laisse une partie de "sûr" sans réponse.
Comme indiqué, il existe plusieurs types de sécurité promus. Je pense qu'il est bon de comprendre pourquoi il y a plusieurs notions. Chaque notion est associée à l'idée que les programmes souffrent en particulier d'une certaine classe de bogues et que les programmeurs seraient incapables de créer ce type de bogue spécifique si le langage empêchait le programmeur de le faire.
Il convient de noter que ces différentes notions ont donc différentes classes de bogues et que ces classes ne s’excluent pas mutuellement. Ces classes ne couvrent pas toutes les formes de bogues. Juste pour prendre les 2 exemples de DW, la question de savoir si un certain emplacement de mémoire contient un certain objet est à la fois une question de sécurité de type et de sécurité de mémoire.
Une autre critique des "langues sûres" découle de l'observation selon laquelle l'interdiction de certaines constructions jugées dangereuses laisse au programmeur le besoin de proposer des alternatives. Empiriquement, la sécurité est mieux assurée par de bonnes bibliothèques. L'utilisation de code déjà testé sur le terrain vous évite de créer de nouveaux bogues.
la source
Une différence fondamentale entre C et Java réside dans le fait que si on évite certaines fonctionnalités facilement identifiables de Java (par exemple, celles de l'
Unsafe
espace de noms), toute action possible, y compris les actions "erronées" - aura un nombre limité de résultats possibles. . Bien que cela limite ce que l’on puisse faire en Java - du moins sans utiliser l’Unsafe
espace de nom, cela permet également de limiter les dommages pouvant être causés par un programme erroné ou - plus important encore - par un programme qui traiterait correctement fichiers valides, mais n'est pas particulièrement protégé contre les fichiers erronés.Traditionnellement, les compilateurs C traitaient de nombreuses actions de la manière définie par la norme dans les cas "normaux", tout en traitant de nombreux cas critiques "d'une manière caractéristique de l'environnement". Si vous utilisiez un processeur qui court-circuiterait et prendrait feu en cas de dépassement de capacité numérique et souhaitait éviter que le processeur ne prenne feu, il faudrait écrire du code pour éviter tout dépassement de capacité numérique. Si, toutefois, on utilisait un processeur qui tronquerait parfaitement les valeurs en complément de deux, on n'aurait pas à éviter les débordements dans les cas où une telle troncature entraînerait un comportement acceptable.
Le C moderne va encore plus loin: même si l’on cible une plate-forme qui définirait naturellement un comportement tel que le dépassement numérique où la norme n’imposerait aucune exigence, le dépassement d’une partie du programme peut affecter le comportement d’autres parties du programme. programme de manière arbitraire non liée par les lois du temps et de la causalité. Par exemple, considérons quelque chose comme:
Un compilateur C "moderne" à partir de ce qui précède pourrait conclure que puisque le calcul de x * x déborderait si x était supérieur à 46340, il pouvait effectuer l'appel de "foo" sans condition. Notez que même s'il serait acceptable qu'un programme se termine anormalement si x est en dehors de la plage, ou que la fonction retourne une valeur quelconque dans de tels cas, appeler foo () avec un x en dehors de la plage pourrait causer des dommages bien au-delà. l'une de ces possibilités. Le C traditionnel ne fournirait pas d’équipement de sécurité autre que celui fourni par le programmeur et la plate-forme sous-jacente, mais permettrait à l’équipement de sécurité de limiter les dommages résultant de situations inattendues. Le C moderne contournera tout équipement de sécurité qui ne serait pas efficace à 100% pour tout contrôler.
la source
int
est 32 bits, alorsx
sera promu à signéint
. A en juger par la raison, les auteurs de la norme attendue que les implémentations non-étranges traiteriez types signés et non signés en dehors de la mode équivalent de certains cas de particuliers, mais gcc parfois « Optimise » de façon rupture siuint16_t
par lesuint16_t
rendements se multiplient un résultat au - delà INT_MAX , même lorsque le résultat est utilisé comme valeur non signée.-Wconversion
.return x+1;
qui ne devrait pas être problématique, et le fait de renvoyer le résultat à uint32_t aurait pour effet d’étouffer le message sans résoudre le problème.Il existe plusieurs niveaux de correction dans une langue. Par ordre d'abstraction croissante:
Au niveau suivant, les erreurs détectées lors de la compilation plutôt que lors de l'exécution rendent un langage plus sûr. Un programme correct du point de vue syntaxique doit également être sémantiquement correct autant que possible. Bien sûr, le compilateur ne peut pas connaître la situation dans son ensemble, cela concerne donc le niveau de détail. Les types de données forts et expressifs sont un aspect de la sécurité à ce niveau. On pourrait dire que la langue devrait rendre difficile de faire certains types d'erreurs(erreurs de type, accès hors limites, variables non initialisées, etc.). Les informations de type à l'exécution, telles que les tableaux contenant des informations de longueur, évitent les erreurs. J'ai programmé Ada 83 au collège et constaté qu'un programme de compilation Ada contenait généralement un nombre d'erreurs moins important que le programme C correspondant. Il suffit de prendre la capacité d'Ada pour définir par l'utilisateur des types entiers qui ne sont pas assignables sans conversion explicite: des vaisseaux spatiaux entiers se sont écrasés parce que pieds et mètres étaient confondus, ce que l'on pourrait éviter trivialement avec Ada.
Au niveau suivant, le langage devrait fournir un moyen d'éviter le code passe-partout. Si vous devez écrire vos propres conteneurs, ou leur tri, ou leur concaténation, ou si vous devez écrire le vôtre,
string::trim()
vous commettez des erreurs. Comme le niveau d'abstraction augmente, ce critère implique le langage proprement dit ainsi que la bibliothèque standard du langage.De nos jours, la langue devrait fournir des moyens pour une programmation simultanée au niveau de la langue. La concurrence est difficile à obtenir et peut-être impossible à faire correctement sans la prise en charge linguistique.
Le langage devrait fournir des moyens de modularisation et de collaboration. Les types forts, élaborés et définis par l'utilisateur décrits ci-dessus aident à créer des API expressives.
De manière un peu orthogonale, la définition du langage devrait être intelligible; la langue et les bibliothèques doivent être bien documentées. Une documentation incorrecte ou manquante conduit à des programmes incorrects et erronés.
1 Mais comme il est généralement impossible de prouver l'exactitude de la machine virtuelle, de tels langages peuvent, paradoxalement, ne pas être adaptés à des exigences de sécurité très strictes.
la source
Chaque langue que je connais a des façons d'écrire des programmes illégaux qui peuvent être (compilés et) exécutés. Et chaque langue que je connais a un sous-ensemble sûr. Alors, quelle est votre question vraiment?
La sécurité est multidimensionnelle et subjective.
Certaines langues ont de nombreuses opérations "dangereuses". D'autres ont moins d'opérations de ce type. Dans certaines langues, le moyen par défaut de faire quelque chose est intrinsèquement dangereux. Dans d'autres, la méthode par défaut est sûre. Dans certaines langues, il existe un sous-ensemble "non sécurisé" explicite. Dans d'autres langues, il n'existe aucun sous-ensemble de ce type.
Dans certaines langues, le terme "sécurité" fait exclusivement référence à la sécurité de la mémoire - un service offert par la bibliothèque standard et / ou le moteur d'exécution lorsque les violations d'accès à la mémoire sont rendues difficiles ou impossibles. Dans d'autres langues, "sécurité" inclut explicitement la sécurité des threads. Dans d'autres langues, "sécurité" fait référence à la garantie qu'un programme ne fonctionnera pas (une exigence qui inclut l'interdiction d'autoriser des exceptions non capturées). Enfin, dans de nombreuses langues, "sécurité" fait référence à la sécurité de type - si le système de type est cohérent d'une certaine manière, il est dit "sain" (par ailleurs, Java et C # ne disposent pas de systèmes de type complètement sonores).
Et dans certaines langues, toutes les significations différentes de "sécurité" sont considérées comme des sous-ensembles de types de sécurité (par exemple, Rust et Pony assurent la sécurité des threads grâce aux propriétés du système de types).
la source
Cette réponse est un peu plus large. Les mots sécurité et sécurité ont été mutilés au cours des dernières décennies par certaines composantes de la société anglophone à caractère politique, de sorte que leur usage courant n’a presque pas de définition. Cependant, pour les sujets techniques, je reviens toujours à définir les termes "sécurité" et "sûr" comme: un dispositif empêchant l’utilisation involontaire de quelque chose ou rendant l’utilisation accidentelle beaucoup plus difficile, et le fait d’être sous la protection d’un tel dispositif .
Ainsi, un langage sûr a un dispositif pour limiter une classe de bogues particulière. Bien sûr, les limites viennent avec des inconvénients ou même une incapacité dans certains cas, et cela ne veut pas dire que les langues "non sécurisées" vont générer des bugs. Par exemple, je n'ai pas de bouchons de sécurité sur ma fourche et je réussis, depuis des décennies, sans trop d'effort, à ne pas me poignarder les yeux en mangeant. Certainement moins d’efforts qu’ils n’auraient dépensé avec les bouchons de liège. La sécurité a donc un coût qui doit être évalué. (la fourchette en liège est une référence à un personnage de Steve Martin)
la source