OVH Cloud OVH Cloud

Partage d'une string en deux selon critères

42 réponses
Avatar
TigrouMeow
Bonjour,

Aujourd'hui j'ai une nouvelle question. J'ai un peu cherché et je vois pas
la bonne manière de faire ceci...

Je lis un fichier et j'ai une entrée de ce genre :
12 87
4783 49
1 0
429 452

Il s'agit de récupérer les deux nombres à chaque ligne. En Perl, c'est assez
aisé de le faire en utilisant une expression régulière. En C++, j'imagine
qu'il y a peut-etre une possibilité de faire ça, donc je préfère demander
avant de recoder un parseur.

Je vous remercie de votre aide une nouvelle fois ;)

10 réponses

1 2 3 4 5
Avatar
drkm
David writes:

Il y a vraiment une faille de sécurite dans ce code ?
int v1, v2;
while( file >> v1 >> v2 )
;

En effet, comme le souligne drkm, il semble délicat de valider le format
en entrée du fichier mais à part ça.

Je ne suis pas spécialiste de le programmation en milieu 'hostile'
mais je ne suis pas sûr qu'il soit facile de trouver un fichier en entrée
permettant de prendre le contrôle de la machine ou autre.


Je ne pense pas qu'il faille chercher si loin. Si on présente à ce
code une entrée composée d'un nombre impair d'entiers séparés par des
caractères blancs (par exemple une entrée valide mais tronquée), on
ignorera simplement la dernière valeur. Mais cela peut provoquer un
bug autre part.

De la à prendre le contrôle de la machine, ce n'est pas impossible,
mais d'après le bout de code, semble peu probable.

Si une entrée est erroné, il faut le détecter le plus tôt possible
et faire ce qu'il faut. Rattraper l'erreur, la signaler, aborter,
etc.

Je me souvient m'être déjà fait ce genre de réflexion à mes débuts,
« ce n'est qu'un petit programme de test », et avoir passé du temps à
comprendre ce qui n'allait pas dans une exécution où je présentais une
entrée erronée, sur une erreur de ma part. Au lieu d'avoir passé ce
temps à apprendre à écrire directement du code qui détecte une erreur
de formatage.

Autant en C, il faut faire plus attention, autant en C++ je suis beaucoup
plus souple, les outils de la librairie C++ faisant le plus gros du travail.


Je ne connais pas aussi bien les I/O C que C++, mais je ne vois pas
en quoi les IOStreams C++ standards détectent plus d'erreurs de
formatage en entrée si le développeur ne fait rien de son côté.

--drkm

Avatar
James Kanze
David writes:

|> > Il ne faut jamais faire confiance aux données entrantes,

|> Jamais ?

|> Pour moi, ça dépend beaucoup d'où viennent les données entrantes.

Tout à fait. Si elles viennent d'un tableau que tu as écris dans la même
module, deux lignes auparavent, on pourrait y faire confiance. Un peu,
au moins. Si elles viennent d'une autre module, pas tellement. Et si
elles viennent de dehors du programme, pas du tout, mais jamais, jamais.

|> En l'occurence ici, ce qui semble être un simple exercice, il ne
|> doit pas y avoir de trop grand danger.

|> > pour éviter tout abus. Une grande partie des failles de sécurité
|> > viennent justement du manque de rigueur dans la vérification de
|> > l'input.

|> Il y a vraiment une faille de sécurite dans ce code ?
|> int v1, v2;
|> while( file >> v1 >> v2 )
|> ;

Je suppose que ça dépend ce qu'on fait par la suite.

|> En effet, comme le souligne drkm, il semble délicat de valider le
|> format en entrée du fichier mais à part ça.

|> Je ne suis pas spécialiste de le programmation en milieu 'hostile'

Moi si. Je développe du code pour Solaris, pour Linux et pour Windows.
Ce sont bien des milieux hostile, il me semble. (Enfin, ce n'est pas moi
qui les a écrit. Et dans le cas du Solaris et de Linux, je ne suis même
pas seul sur la machine.)

|> mais je ne suis pas sûr qu'il soit facile de trouver un fichier en
|> entrée permettant de prendre le contrôle de la machine ou autre.

C'est cependant la base de la plupart des virus.

|> Autant en C, il faut faire plus attention, autant en C++ je suis
|> beaucoup plus souple, les outils de la librairie C++ faisant le plus
|> gros du travail.

--
James Kanze
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34
Avatar
David
Je ne pense pas qu'il faille chercher si loin. Si on présente à ce
code une entrée composée d'un nombre impair d'entiers séparés par des
caractères blancs (par exemple une entrée valide mais tronquée), on
ignorera simplement la dernière valeur. Mais cela peut provoquer un
bug autre part.


En effet, si le fichier est faux, le résultat est non défini.

De la à prendre le contrôle de la machine, ce n'est pas impossible,
mais d'après le bout de code, semble peu probable.


Je serai impressionné si cela est possible en tout cas.

Si une entrée est erroné, il faut le détecter le plus tôt possible
et faire ce qu'il faut. Rattraper l'erreur, la signaler, aborter,
etc.
Je me souvient m'être déjà fait ce genre de réflexion à mes débuts,
« ce n'est qu'un petit programme de test », et avoir passé du temps à
comprendre ce qui n'allait pas dans une exécution où je présentais une
entrée erronée, sur une erreur de ma part. Au lieu d'avoir passé ce
temps à apprendre à écrire directement du code qui détecte une erreur
de formatage.


Je n'ai pas assez d'expèrience dans le traitement de fichier
'non valide' pour avoir des idées précises sur le sujet, je n'ai
traité jusque là que des fichiers conformes au contrat.
Je me cantonne à l'utilisation 'par contrat' pourrait-on dire
qui consiste à fournir une sortie valide en cas d'entrée valide.

Je ne suis pas pour tout valider, car on ne sait jamais où s'arrêter.

Je ne connais pas aussi bien les I/O C que C++, mais je ne vois pas
en quoi les IOStreams C++ standards détectent plus d'erreurs de
formatage en entrée si le développeur ne fait rien de son côté.


Je ne parlais pas de formattage mais plutôt du dépassement de capacité
lors de la lecture des chaînes de caractères notamment.

David.

Avatar
David
Tout à fait. Si elles viennent d'un tableau que tu as écris dans la même
module, deux lignes auparavent, on pourrait y faire confiance. Un peu,
au moins. Si elles viennent d'une autre module, pas tellement. Et si
elles viennent de dehors du programme, pas du tout, mais jamais, jamais.


Pas facile de coder dans une fonctionne la notion de proximité ;-)
Du coup, j'aurais tendance à croire que ce genre de source passe
son temps à valider des données... où s'arrêter ?

J'imagine juste l'exemple de strcpy ?
Il faudrait vérifier que chaque octet écrit va bien dans une bonne
adresse par exemple ?

|> Je ne suis pas spécialiste de le programmation en milieu 'hostile'

Moi si. Je développe du code pour Solaris, pour Linux et pour Windows.
Ce sont bien des milieux hostile, il me semble. (Enfin, ce n'est pas moi
qui les a écrit. Et dans le cas du Solaris et de Linux, je ne suis même
pas seul sur la machine.)


Je développe sous hpux, linux et windows mais ce n'est pas
ce que j'entendais par milieu hostile. Mais plutôt les conditions
dans lesquelles sera utiliser le programme et qui fournira les données
en entrée. Hostile dans le sens où les données viennent de l'extérieur
de n'importe qui, où il y a une volonté de nuire et de détecter une faille.


|> mais je ne suis pas sûr qu'il soit facile de trouver un fichier en
|> entrée permettant de prendre le contrôle de la machine ou autre.

C'est cependant la base de la plupart des virus.


Je parlais dans cette exemple. Mais je serai intéressé de savoir
si ce genre de cas existe dans des programmes C++ (n'utilisant
pas char* de manière aléatoire) ou si ces virus ne s'attaquent
qu'au programme (mal) écrit en C.

Mais, je le répète, je n'ai jamais vraiment été confronté à des attaques
lors de l'utilisation des projets auxquels j'ai participé.

David.

Avatar
Fabien LE LEZ
On Mon, 11 Oct 2004 22:23:55 +0200, David :

Tout à fait. Si elles viennent d'un tableau que tu as écris dans la même
module, deux lignes auparavent, on pourrait y faire confiance. Un peu,
au moins. Si elles viennent d'une autre module, pas tellement. Et si
elles viennent de dehors du programme, pas du tout, mais jamais, jamais.


Pas facile de coder dans une fonctionne la notion de proximité ;-)


C'est à toi de savoir d'où vient les données.
Et si tu ne sais pas, imagine le pire. En informatique (et surtout en
sécurité informatique), le paranoïaque est encore optimiste.

Du coup, j'aurais tendance à croire que ce genre de source passe
son temps à valider des données...


A valider les données extérieures, oui.

où s'arrêter ?


Au moment où tu es sûr que la ligne lue est conforme aux
spécifications.
Je dois dire que les expressions régulières/rationnelles seraient
parfaitement adaptées dans le cas présent : puisqu'on sait qu'il y a
exactement deux nombres entiers positifs sur chaque ligne, et que le
seul caractère possible est un espace, il suffit d'utiliser
l'expression "^ *([0-9]+) +([0-9]+) *$" et le tour est joué : soit la
ligne est conforme à cette expression, et les nombres sont 1 et 2,
soit la ligne n'est pas conforme, et le programme râle.

J'imagine juste l'exemple de strcpy ?
Il faudrait vérifier que chaque octet écrit va bien dans une bonne
adresse par exemple ?


C'est différent : les données fournies à strcpy sont fournies par le
programme, pas lues depuis un fichier externe. Donc la fonction qui
appelle strcpy() doit faire les vérifications qu'elle juge utiles.

Je parlais dans cette exemple. Mais je serai intéressé de savoir
si ce genre de cas existe dans des programmes C++ (n'utilisant
pas char* de manière aléatoire) ou si ces virus ne s'attaquent
qu'au programme (mal) écrit en C.


S'il est plus facile de faire un programme fiable en C++, ce langage
n'est pas sans ses pièges et comportements indéfinis. Une classe de
base sans destructeur virtuel vaut bien un char* utilisé sans rigueur.

Mais, je le répète, je n'ai jamais vraiment été confronté à des attaques
lors de l'utilisation des projets auxquels j'ai participé.


Même sans attaques, si l'entrée n'est pas conforme aux spécifications,
ton programme doit l'indiquer, ne serait-ce que pour pouvoir déboguer
le programme qui crée cette entrée.


--
;-)


Avatar
drkm
David writes:

Je ne suis pas pour tout valider, car on ne sait jamais où s'arrêter.


Ben si. Il « suffit » de vérifier que l'entrée respecte
scrupuleusement le format définit pour elle.

--drkm

Avatar
drkm
David writes:

J'imagine juste l'exemple de strcpy ?
Il faudrait vérifier que chaque octet écrit va bien dans une bonne
adresse par exemple ?


Ca n'a rien à voir avec le formatage des données en entrées. Je
vois mal ce que `strcpy()' pourrait faire de mieux que de donner comme
précondition que la source soit une chaîne valide (terminée par un
'' jusqu'auquel on peut lire chaque caractère) et que la cible soit
alouée correctement (entre autre de capacité suffisante).

--drkm

Avatar
Fabien LE LEZ
On Tue, 12 Oct 2004 01:33:49 +0200, drkm :

et que la cible soit
alouée correctement (entre autre de capacité suffisante).


De toutes façons, je ne vois pas bien comment strcpy() pourrait le
vérifier.


--
;-)

Avatar
Fabien LE LEZ
On Tue, 12 Oct 2004 01:53:11 +0200, Fabien LE LEZ
:

De toutes façons, je ne vois pas bien comment strcpy() pourrait le
vérifier.


... sauf dans les bibliothèques "spécial débogage", mais c'est lent...

--
;-)

Avatar
drkm
Fabien LE LEZ writes:

On Tue, 12 Oct 2004 01:33:49 +0200, drkm :

et que la cible soit
alouée correctement (entre autre de capacité suffisante).


De toutes façons, je ne vois pas bien comment strcpy() pourrait le
vérifier.


C'est entre autre ce que je voulais dire. Comme elle ne peut
s'assurer que la source est valide.

--drkm


1 2 3 4 5