Sign in Join
Wiki copytemporary

Secure programming/fr: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11# Avant-propos
22
33Cette page de wiki tente d'enseigner une approche différente dans la façon créer un logiciel. La page utilise des exemples très simples pour montrer que beaucoup de problèmes peuvent être profitables pour prendre l'avantage dans le but de créer une attaque de sécurité sur un ordinateur, un programme ou un système en entier.
44
55Veuillez noter que le document est seulement un début sur la technologie sur comment écrire un meilleur et un code un peu plus sécurisé code, mais il n'essaye pas d'être un guide complet sur la façon de le faire. En fait c'est seulement un résumé de la façon dont nous devons voir notre code et programme , et comment éviter beaucoup de problèmes communs.
66
77Veuillez vous rappeler que ce document vise un meilleur codage et n'est pas là pour montrer comment hacker(bidouiller) ou craquer (casser la protection) de programmes.
88
99# Ne faites pas confiance aux entrées
1010
1111En développant un programme, il est probable qu'il interagira avec un utilisateur de différentes façons, même s'il se limite à lire des fichiers dans le système et présenter les données.
1212
1313Généralement à l'école et à l'université, quand quelqu'un commence à écrire des programmes, cette personne apprend comment recevoir des données, les professeurs disent généralement à cette personne "supposez que les données que vous recevez sont valide".
1414
1515Mais **Nous ne pouvons pas faire confiance à toute entrée que nous ne pouvons pas contrôler car son contenu est inconnu et pourrait exploiter une vulnérabilité dans notre logiciel.**
1616
1717Lire depuis un fichier est lire depuis une source non sûre, de même que les entrées d'un utilisateur ou les données provenant d'un réseau par exemple.
1818
1919## Pourquoi ne dois-je pas croire aux entrées ?
2020
2121Pour comprendre pourquoi une entrée est dangereuse, nous devons d'abord comprendre ce qu'est une entrée.
2222
2323Une entrée peut être lue depuis un clavier, le mouvement de la souris ou des clics de souris, ou depuis la lecture ou l'acceptation d'information de différente façons telles que les flux de données ou même les fonctions système. En fait, tout ce qu'obtient votre programme de l'extérieur est une entrée.
2424
2525Peu importe le type d'entrée : par exemple, un utilisateur ou un autre système peut nous donner une mauvaise entrée, et les raisons peuvent être intentionnelles ou une erreur. Vous ne pouvez pas contrôler cette entrée, et la raison principale est que vous ne pouvez pas deviner ce que l'entrée sera.
2626
2727Les résultats peuvent être des "données" vides (NULL) que l'utilisateur nous fournit, un nombre qui est hors de l'étendue attendue, ou une plus grande quantité de caractères que nous attendions, ou même une tentative de changer l'adresse de la variable qui accepte L'entrée de l'utilisateur. Nous ne pouvons tout simplement pas savoir ce que l'utilisateur va fournir.
2828
2929Tout manipulation "non-sûre" de l'entrée peut aboutir à
3030
3131- la récupération d'information critique que l'utilisateur n'est pas autorisé à voir,
3232- la modification non permise de donnée,
3333- la corruption de donnée,
3434- l'interruption (crash, plantage) du programme lui-même.
3535
3636## A quel type de problèmes pouvons-nous nous attendre ?
3737
3838Pour chaque type de bug, vous pouvez sans doute trouver un type d'attaque, mais je vais vous donner une petite liste de types d'attaque communs, au lieu d'écrire beaucoup de types d'attaque.
3939
4040Le types d'attaque les plus communs sont :
4141
4242### Débordement de tampon
4343
4444C'est quand une donnée dépasse la quantité de mémoire qui lui est allouée :
4545
4646``` pascal
4747var
4848 iNums : array [0..9] of integer;
4949 ...
5050 FillChar (iNums[-1], 100, #0);
5151 ...
5252 for i := -10 to 10 do
5353 readln (iNums[i]);
5454 ...
5555```
5656
5757Dans cet exemple, nous pouvons voir que le tableau statique iNums n'accepte que 10 nombres, alors que nous entrons dans cette variable 21 nombres.
5858
5959Veuillez noter que le compilateur sait signaler de tels cas, qui ne sont que des formes peu élaborées.
6060
6161Si l'utilisateur peut entrer de la donnée qui est envoyée dans un tampon, il peut entrer certaines valeurs pouvant être interprétées par les instructions en code machine, qui seront écrites en dehors de notre tampon. L'ordinateur pourra alors exécuter ce code au lieu du code qui aurait dû être là.
6262
6363C'est le débordement de tampon.
6464
6565### Attaque par déni de service (*DoS*)
6666
6767Le déni de service n'est pas seulement un problème de réseau, il peut exister dans d'autres formes :
6868
6969``` pascal
7070procedure Recurse;
7171begin
7272 while (True) do
7373 begin
7474 Recurse;
7575 end;
7676end;
7777```
7878
7979Cette procédure s'exécutera jusqu'à ce que le système soit à court de ressources car il alloue plus de mémoire de pile à chaque récursion, cela provoquera l'arrêt de réponse du système, ou même le crash. Bien que certains systèmes, comme GNU/Linux, tentera de vous donner la possibilité d'arrêter le programme, cela prendra un certain temps pour se faire.
8080
8181Veuillez remarquer que cela n'est qu'un exemple statique, mais nous pouvons faire une attaque DoS sur un système en exécutant ce code.
8282
8383Une autre attaque DoS connue est le manque de libération de ressources système telle que la mémoire, les sockets, les descripteurs de fichiers, ...
8484
8585Par exemple :
8686
8787``` pascal
8888...
8989 begin
9090 while True do
9191 begin
9292 Getmem(OurPtr, 10);
9393 OurPtr := Something;
9494 end;
9595 end.
9696```
9797
9898Cet exemple montre une allocation de mémoire (Getmem est comme malloc en langage C ; il réserve de la mémoire pour utilsiation), mais nous sortons de l'exécution sans avoir libérer la mémoire après emploi.
9999
100100### Injections
101101
102102Quand l'utilisateur nous donne une entrée avec laquelle nous travaillons sans l'avoir assainie, l'utilisateur peut mettre dedans des marque SQL ou du code (comme du script, ou du code machine) par exemple, qui amènera notre programme à réaliser quelque action indésirable (p.ex. supprimer des enregistrements/tables, retourner des données protégées telles que des structures de bases de données/tables, utilisateur et mot de passe, contenu de dossier ou de fichier ou même exécuter un programme sur l'ordinateur).
103103
104104Un exemple d'injection SQL :
105105
106106Entrée d'utilisateur :
107107
108-` SVP, entrez votre nom : a' OR 1=1`
108+```text
109+ SVP, entrez votre nom : a' OR 1=1
110+```
109111
110112Dans le code :
111113
112114``` pascal
113115...
114116Write('SVP, entrez votre nom : ');
115117ReadLn(sName);
116118Query1.SQL.Add('SELECT Password FROM tblUsers WHERE Name='#32 + sName + #32);
117119...
118120```
119121
120122En soumettant cette instruction SQL avec l'entrée de l'utilisateur, il résultera de l'ajout de OR 1=1 dans la requête passée à la base de donnée : dans ce cas, la condition sera toujours vraie et l'utilisateur aura obtenu un éccès au programme et pourra connaître la liste des mots de passe (NdT : on fait l'hypothèse que ces derniers sont enregistrés en clair, mauvaise idée).
121123
122124# Accès à vos données et modifications
123125
124126Ce n'est pas uniquement votre programme qui aura accès aux données qu'il utilise. Si vous stockez de la donnée dans des fichiers ou des bases de données (distantes), un attaquant peut obtenir l'accès à travers le système d'exploitation (et/ou la base de données et/ou la couche réseau/protocole de base de données).
125127
126128## Chiffrement : est-ce suffisant ?
127129
128130Pour contrer la menace décrite ci-dessus, les programmeurs utilise souvent le chiffrement, il peut être utilisé pour fournir :
129131
130132- la protection de la confidentialité des données
131133- la non-répudiation (est-ce que la donnée a été créée par la personne qui le prétend) et l'intégrité (la donnée est-elle inchangée), en utilisant des mécanismes supplémentaires de signature numérique/hachage).
132134
133135ensemble pour
134136
135137- la communication des données
136138- stockage/récupération des données
137139
138140Si vous utilisez ces méthodes, vos données ne sont toutefois pas automatiquement sûres.
139141
140142Il y a de multiples attaques possibles sur les données chiffrées :
141143
142144- attaque sur des algorithmes mal sécurisés ou leur implémentation (p.ex. en utilisant une attaque avec du texte brut connu)
143145- attaque sur les clés de chiffrement (p.ex. en faisant une rétro-analyse de votre programme, si vous stocker des clés dans un fichier ou en dur dans le programme, ou en corrigeant le programme pour intercepter les clés/mots de passe entrés par l'utilisateur).
144146
145147Si vous ne savez pas exactement ce que vous allez faire (et vous ne saurez pas, à moins d'avoir une formation en cryptographie), svp utilisez (par ordre décroissant de préférence) :
146148
147149- des bibliothèques réputées qui sont maintenues/corrigées (p.ex. les bibliothèque internes de FPC, et des bibliothèques telles que DCPCrypt ou des bibliothèques externes comme OpenSSL ou cryptlib) qui utilise des protocoles réputés et largement utilisés qui utilisent des algorithmes réputés et largement utilisés.
148150 - Utilisez p.ex. Trusted Authentication/SSPI pour la connectivité SQL Server/Firebird pour éviter l'envoi de mots de passe a travers le câble (dans Firebird \>= 2.0 : en texte clair !) et s'appuie sur la sécurité du système d'exploitation pour l'authentification.
149151 - Utilisez Cryptlib ou OpenSSL avedc Synapse pour implémenter SSL/TSL au lieu d'une solution personnelle.
150152- des protocoles et APIs réputés et largement utilisés au lieu de solutions personnelles. Ces protocoles doivent utiliser des algorithmes de cryptographie/hachage bien compris et largement employés. Exemples :
151153 - GPG/PGP
152154 - TLS (SSL) avec PKI/CAs (de préférence ne faites pas confiance au CAs dont vous avez besoin, et réalisez des certificats d'authenthification client si votre analyse de la menace l'exige).
153155 - SSH (e.g. avec clé d'authentification publique/privée, si nécessaire avec renforcement par des périphrases pour les clés)
154156 - Dans Windows, utilisez l'API pour obtenir l'utilisateur actuellement authentifié. Si vous mettez en application la sécurité adaptée du système (longueur de mot de passe, modification, accès physiques etc), vous n'aurez pas besoin de gérer votre propore mécanisme de nom de connexion/mot de passe au niveau de l'application.
155157- des algorithmes bien connus de crypto/hachage (tels que AES/Rijndael, 3DES et SHA512). Soyez conservateur dans les algorithmes que vous acceptez (p.ex. MD5 n'est pas sûr dans la signature de message).
156158
157159Le chiffrement est une partie de l'ensemble possible des mesures de sécurité ; l'effort/l'argent dépensé doit être évalué comme faisant partie de l'analyse de la sécurité (voir plus bas).
158160
159161# Mythes et suppositions
160162
161163De nombreux problèmes de sécurité existent à cause de l'ignorance d'importants avertissements et d'information donnés par le compilateur et par la conviction que votre programme ne contient pas de problème exploitable.
162164
163165Voici quelques exemples pour ce type de problème :
164166
165167**Mythes**:
166168
167169- La sécurité par l'obscurité - Quand personne ne connaît un problème, personne ne peut en profiter ; p.ex. utiliser un nom de colonne obscur pour stocker des mots de passe dans votre base de données.
168170- Les langages de programmation sûrs : il y a des langages tels que Perl dont des gens pensent à tort qu'ils sont sûrs face aux débordements de tampon et autres vulnérabilité.
169171- Un mot de passe hachés est sûr - Un fichier qui a un mot de passe haché n'est pas sûr. (non traduit car incompris : ) Hash can only passed one and you can not retrieve the original data. *I don't get this. Does the author mean that a hashed password can be retrieved by a brute force or rainbow table attack and that it therefore needs a salt, or multiple hash rounds? --BigChimp 16:19, 24 July 2011 (CEST)*.
170172- Personne ne peut casser mon programme - Penser que vous êtes le seul programmeur dans le monde qui écrive du code non fautif est sans doute un peu optimiste. Peut-être êtes-vous chanceux et vous avez juste écrit du code qui ne marche bien sans vulnérabilité de sécurité exploitable ...
171173
172174**Suppositions**:
173175
174176- L'équipe qualité va trouver et corriger mes bugs de sécurité.
175177- L'utilisateur (ou quelqu'un d'autre) n'attaquera pas mon programme ni ses données.
176178- Mon programme ne sera utilisé que pour son utilisation prévue.
177179- Toutes les exceptions peuvent rester en l'état (*unhandled*)
178180
179181# Analyse pour comprendre les menaces et la sécurité
180182
181183En général, un programmeur (ou son employeur) devrait réaliser une analyse de toutes les menaces (depuis les accès physiques/attaques jusqu'aux attaques logiques et d'ingénierie sociales) qui devrait être faite sur le système entier (y compris l'infrastructure - système d'exploitation, base de données aussi bien que sur les machines physiques/câblage/batiments/connexions externes) pour analyser si vous n'avez pas laisser ouvert une brêche de sécurité qui est inacceptable (dans une perspective risque/bénéfice).
182184
183185L'extension de cette analyse devrait dépendre de la valeur des données/processus que le système protège. Il est évident que cela est superflu d'analyser à fond la sécurité de votre maison quand vous développez un programme de loisir pout garder la trace de vos scores de bridge.
184186
185187Bénéfices de cette sorte d'analyses :
186188
187189- les risques restants après ces mesures de sécurité deviennent connus et explicites. Souvent, il y a des discussion sur les chances de survenue du risque, ou sur l'impact qui lui associé, mais la fait qu'il subsiste un vecteur d'attaque est au moins clair et les décisions peuvent être rendues basées sur cette information.
188190- vous pouvez loyalement facilement voir que les mesures sont sur-conçues (*overengineered*) ("too secure", gaspillage d'argent) ou sous-conçues ("pas assez sûres"). Si vous ne pouvez pas utiliser cette information maintenant, vous pouvez au moins apprendre d'elle pour d'autres projets, y compris de future maintenance/modification de votre programme.
189191
190192# Solutions spécifiques
191193
192194Maintenant nous connaissons certains problèmes que nous allons rencontrés en développant des programmes, nous devrions apprendre à corriger ces problèmes. Tous les problèmes que nous avons vu au-dessus se manifestent en deux types : suppositions et manque de programmation sûre. Et pour apprendre à les corriger, nous devons d'abord apprendre à penser d'une manière différente que nous avions jusqu'à maintenant.
193195
194196## Débordement
195197
196198Pour corriger le débordement de donnée, comme les tampons ou autre type d'entrée, nous avons besoin avant tout d'identifier le type de donnée dont nous avons besoin :
197199
198200### Débordement de tampon
199201
200202Si nous revenons à notre exemple de :
201203
202204``` pascal
203205var
204206 iNums: array [0..9] of Integer;
205207 ...
206208 FillChar(iNums[-1], 100, #0);
207209 ...
208210 for i := -10 to 10 do
209211 ReadLn(iNums[i]);
210212 ...
211213```
212214
213215Nous voyons là une étendue qui a été dépassée par nos valeurs, sans même vérifier si l'index est correct.
214216
215217Dans les tableaux dynamiques/ouverts de Pascal, nous pouvons connaître les limites de la mémoire allouée. Ainsi, il suffit juste de contrôler si la taille est trop petite ou trop grande pour notre tampon, et de limiter ce qu'elle doit accepter.
216218
217219Ainsi l'exemple devrait être changé en :
218220
219221``` pascal
220222var
221223 iNums: array [0..9] of Integer;
222224
223225 ...
224226 FillChar (iNums[Low(iNums)], High(iNums), #0);
225227 ...
226228
227229 for i := Low(iNums) to High(iNums) do
228230 ReadLn(iNums[i]);
229231 ...
230232```
231233
232234Mais attendez, quelque n'est pas encore juste !
233235
234236La routine ReadLn accepte une quantité illimitée de caractères et rien ne nous promet que cela sera un entier ou de l'étendue que nous pouvons gérer.
235237
236238### Débordement numérique
237239
238240Alors qu'une chaîne en Pascal est un pur tableau (humm humm..pas vraiment, du moins pas en FreePascal, mais nous l'admettrons quelques temps, Ok ?) ainsi *readln* tentera de trouver et voir ce que sont ces limites et ne tentera pas de dépasser l'étendue que nous avons donné à ce type, mais les nombres ne sont pas pareils.
239241
240242Les nombres ont des limites, un ordinateur/compilateur a des limites de toutes sortes concernant la mémoire et les nombres. Il peut attribuer une "petite" quantité de mémoire pour les nombres (virgule flottante et entiers). Et souvent, nous n'avons pas besoin d'une grande étendue de nombre à utiliser (tels que les booléens qui ne demandent que deux valeurs).
241243
242244Dans l'exemples du dessus, nous pouvons avoir un dépassement de tampon qui provoquera une erreur de contrôle d'étendue qui nous donnera un mauvais nombre (problèmes de rappel(*reminder*) de drapeau de retenue... que je n'expliquerai pas ici), et nous avons un effet DoS, car notre programme s'arrêtera à ce point.
243245
244246Donc que pouvons-nous faire pour régler cela ?
245247
246248En premier lieu, nous pouvons désirer travailler avec une variable chaîne qui sera de la taille du nombre le plus grand +1 (pour le signe moins), ou nous pouvons créer notre propre procédure/fonction ReadLn qui se spécialisera avec le type entier.
247249
248250Pour la première option, nous pouvons faire ce qui suit (copié depuis la documentation FPC) :
249251
250252``` pascal
251253Program Example74;
252254
253255{ Program to demonstrate the Val function. }
254256Var
255257 I, Code: Integer;
256258begin
257259 Val(ParamStr(1), I, Code);
258260 If Code <> 0 then
259261 Writeln('Error at position ', code, ' : ', Paramstr(1)[Code])
260262 else
261263 Writeln('Value : ', I);
262264end.
263265```
264266
265267Nous voyons là comment convertir une chaîne en un entier avec une gestion très simple de l'erreur. La fonction *StrToInt* peut aussi faire l'affaire mais il faudra traiter l'exception résultante d'une erreur.
266268
267269Voici un petit exemple pour un petit *readln* comme procédure pour des nombres entiers.
268270
269271``` pascal
270272program MyReadln;
271273uses
272274 CRT;
273275
274276procedure MyIntReadLn(var Param: Integer; ParamLength: Integer);
275277var
276278 Line: string;
277279 ch: char;
278280 Error: Integer;
279281
280282begin
281283 Line := '';
282284
283285 repeat
284286 ch := ReadKey;
285287 if (Length (Line) <> ParamLength) then
286288 begin
287289 if (ch in ['0'..'9']) then
288290 begin
289291 Line := Line + ch;
290292 write (ch);
291293 end
292294 else
293295 if (ch = '-') and (Length(Line) = 0) then
294296 begin
295297 Line := '-';
296298 write (ch);
297299 end;
298300 end;
299301
300302 if (ch = #8) and (Length(Line) <> 0) then // backspace
301303 begin
302304 Line := Copy(Line, 1, Length(Line) - 1);
303305 gotoxy(WhereX - 1, WhereY);
304306 write(' ');
305307 gotoxy(WhereX - 1, WhereY);
306308 end;
307309 until (ch = #13);
308310
309311 val(Line, Param, Error);
310312
311313 if (Error <> 0) then
312314 Param := 0;
313315
314316 writeln;
315317end;
316318
317319var
318320 Num : Integer;
319321
320322begin
321323 Write('Number: ');
322324 MyIntReadLn(Num, 2);
323325 WriteLn('The number is: ', Num);
324326end.
325327```
326328
327329Veuillez noter que vous pouvez la faire mieux, et plus efficace si vous le voulez. C'est seulement un petit exemple pour montrer comment le faire.
328330
329331### Quels sont les risques de sécurité dans les débordement ?
330332
331333Un dépassement de mémoire peut permettre l'exécution d'un code CPU arbitraire et que les utilisateurs peuvent exécuter quelque soit le type de code qu'il désire et rien ne peut les arrêter.
332334
333335## Dénis de service
334336
335337Le deni de service (DoS) est l'un des types d'attaque les plus difficile à empêcher, les raisons sont :
336338
337339- Le déni de service peut même être exécuté sans bug exploitable, comme en utilisant le programme "ping" sur un paquets de machines pour bloquer une machine connectée à Internet.
338340- Toute ressource système peut être la cible d'un possible DoS, comme l'ouverture d'une socket, la lecture de fichiers ou l'allocation de mémoire.
339341- La suppression de fichiers comme un module du noyau peut causer un gros problème. (*I don't get this line --BigChimp 19:32, 24 July 2011 (CEST)*)
340342- Un manque de configuration ou une mauvaise configuration peut provoquer un déni de service s'il permet de mal employer des resources vulnérables.
341343- Trop de permissions ou un manque d'elles (*I don't get that not enough permissions can be a problem. Neither too many, either? Is a security risk, obviously but not a DoS problem. --BigChimp 19:32, 24 July 2011 (CEST)*
342344- Presque tout type d'exploit peut aboutir à un déni de service.
343345
344346Donc comme vous pouvez le voir, un déni de service peut presque être n'importe quoi qui arrête le système dans ce qu'il devrait faire à cause de l'exploitation ou d'un code bugué ou juste un programme qui capture des ressources système.
345347
346348Dans l'exemple de déni de service du dessous :
347349
348350``` pascal
349351procedure Recurse;
350352begin
351353 while (True) do
352354 begin
353355 Recurse;
354356 end;
355357end;
356358```
357359
358360J'ai créé un débordement de pile (un autre type de débordement de tampon), qui amène l'ordinateur à avoir besoin de plus de mémoire pour continuer à exécuter le code.
359361
360362Toute ressource système disponible pour le programme peut être détournée en ne la rendant pas au système lorsque le programme «n'en a plus besoin». La conservation de ressources système comme la mémoire, ou des sockets enlève à d'autres programmes la possibilité d'effectuer certaines de leurs actions. De cette façon, la plupart des programmes arrêteront leur exécution et signaleront une erreur, et certains se bloqueront et continueront à chercher les ressources système.
361363
362364Notez que l'utilisation abusive des ressources système existe à cause d'un bogue dans la programmation, comme l'attente d'un tampon de 150 Ko, alors que le tampon réel n'est que de 2 octets et que le programme cherche toujours le tampon de 150 Ko, une nouvelle demande d'un tampon de 150k est fait, etc. jusqu'à ce que le système ne soit plus en mesure de répondre à aucune des requêtes (c'est un type connu d'attaque).
363365
364366Une bonne solution de contournement pour ce bogue est de limiter le nombre de buffers non complets peuvent être alloués en même temps. Si le tampon n'est pas plein après un délai, il devrait être libre. Toutefois, cette solution entraînera également un déni de service, car la communication s'arrêtera de toute façon à un certain moment, ou une connexion lente peut entraîner la perte de données.
365367
366368## Injection
367369
368370Il y a de nombreuses façons d'injecter certain type de code dans vos programmes. Comme nous pouvons le voir dans l'exemple du dessus.
369371
370372Entrée de l'utilisateur :
371373
372-` SVP, veuillez entrer votre nom : a' OR 1=1`
374+```text
375+ SVP, veuillez entrer votre nom : a' OR 1=1
376+```
373377
374378Inside the code:
375379
376380``` pascal
377381...
378382write(' SVP, veuillez entrer votre nom : ');
379383readln(sName);
380384Query1.SQL.Add('SELECT Password FROM tblUsers WHERE Name='#32 + sName + #32);
381385...
382386```
383387
384388L'injection se rencontre quand nous ne filtrons pas les données entrées dans notre code (assainir est un mot plus professionnel:)) : ceci signifie que nous recevons seulement ce qui a été exactement frappé de l'entrée que nous cherchons et rien d'autre.
385389
386390Par exemple, nous pourrions contrôler si *sName* contient des espaces. Si c'est ainsi, ne pas contrôler le reste de la variable.
387391
388392Ceci aide si le nom d'utilisateur peut être une seul mot contenant des lettres, peut-être une apostrophe et peut-être même un souligné et c'est tout. Si nous entrons un nombre, cela serait illégal.
389393
390394Il ya plusieurs manière d'assainir votre donnée. La moins efficace (mais souvent utilisée) est la suivante :
391395
392396### Désinfection inefficace
393397
394398``` pascal
395399function ValidVar (const S: AnsiString; AllowChars: TCharset): Boolean;
396400var
397401 i: Word;
398402begin
399403 i := 0;
400404 Result := True;
401405
402406 while (Result) and (i <= Length(S)) do
403407 begin
404408 Inc(i);
405409 Result := S[i] in AllowChars;
406410 end;
407411end;
408412```
409413
410414La fonction retourne true si nous avons un contenu correspondant à celui spécifié par *AllowChars* dans la variable *S*. Veuillez noter que cette fonction est seulement une preuve du concept et demande plus de travail pour être pleinement utilisable.
411415
412416Une autre solution pour faire la même chose consiste à utiliser une expression régulière comme suit (c'est une preuve de concept seulement pour Pearl. FPC n'a pas un support complet des expressions régulières qui permet de modifier les chaînes) (NdT : alors pourquoi en parler ?) :
413417
414-`$sName =~ s/[^a-z0-9_\']//gi;`
418+```text
419+$sName =~ s/[^a-z0-9_\']//gi;
420+```
415421
416422L'expression régulière retire tous les caractères invalides de la chaîne et retourne la chaîne purgée. Veuillez noter qu'autant que je le sache, cette expression régulière tournera aussi dans le moteur ereg, mais avec des ajustements minimaux (le drapeau *g* demande à Pearl de remplacer tous les modèles correspondants trouvés. *i* est pour l'insensibilité à la casse).
417423
418424Maintenant nous connaissons que notre entrée est valide, nous devons voir quel est l'utilisation du contenu de la variable. Si la variable va aller dans une base de données, ou un script CGI ou autre chose qui a sa propre syntaxe, nous devons éliminer du contenu les caractères de contrôle ou non permis du langage (p.ex. SQL pour les bases de données).
419425
420426Il y a plusieurs façons d'échapper ce type de contenu. Supposons pour maintenant que ce contenu va aller dans une requête de base de données. Maintenant en premier lieu, nous devons nous assurer que notre échappement n'augmentera pas la taille au dessus de la longueur limite de notre champ de base de données. Parce s'il le font, alors nous passerons d'une injection à une perte de donnée/un déni de service/un débordement de tampon (une base de données respectée généralement tronque la donnée et parfois pas au bon endroit.
421427
422428Généralement, ce que nous faisons pour utiliser une chaîne dans une base de données est seulement d'échapper l'apostrophe (certaines bases de données peuvent avoir des problèmes avec plus de caractères). Ainsi nous devons représenter l'apostrophe d'une façon qu'elle n'ait pas d'effet dans le moteur de la base de données, en le précédant d'une barre de fraction inverse (\\') ou en doublant l'apostrophe (''), ou peut-être même en employant un autre caractère en remplacement dans la requête puis en le faisant le remplacement inverse lors de l'affichage à l'utilisateur.
423429
424430### Restriction des entrées avec les paramètres de requêtes SQL
425431
426432Après nous être assuré du respect des limites, nous pouvons continuer dans nos tentatives. Pour échapper le code, nous pouvons utiliser plusieurs approches. Une approche sympa de moindre débogage, mais une façon sûre d'avoir un échappement correct est d'utiliser la technique des paramètres (NdT : ouf on y est !)
427433
428434``` pascal
429435Query1.SQL.Add('SELECT Password FROM tblUsers WHERE Name=?');
430436Query1.Parameters.Add(sName);
431437if (Query1.Execute) then
432438...
433439```
434440
435441Cette technique permet au moteur de base de données pour échapper le paramètre d'une manière que nous puissions utiliser le contenu sans problème de caractères illégaux. En outre, certaines bases de données ont augmenté les performances pour les appels répétés à ce code, car il peut préparer une déclaration interne avec des paramètres pour cela. Le mauvais côté est que nous ne pourrons jamais déboguer le resultat de la requête. Autrement dit, nous ne pouvons pas voir comment le contenu de *sName* intégré dans l'instruction SQL, et nous ne pouvons jamais voir si notre requête était correcte à cause de cela.
436442
437443De toutes façons, une fois que vous avez testé la requête sans paramètre, l'ajout des paramètres est assez facile, donc en pratique, le problème n'est pas aussi grand qu'il n'y paraît.
438444
439445## Code efficace
440446
441447Les mesures de sécurité mentionnées au dessus compliquent le code si vous avez utilisé le code le plus efficace pour obtenir les fonctionnalités voulues. Heureusement, vous pouvez parfois contourner les complications du code avec un framework/une bibliothèque qui traite cela. Par exemple : dans l'exemple DoS SQL, vous pouvez laisser le moteur de base de données traiter les données d'échappement en utilisant des requêtes paramétrées avec un petit coût pour avoir utiliser des paramètres dans votre code.
442448
443449Toutefois, écrire des programmes efficaces en performance mais vulnérables en sécurité n'aidera personne mis à part des juristes en fiabilité et des experts en forensique.
444450
445451# Au-delà du document
446452
447453Alors que j'ai tenté dans ce document quelques exemples courts et l'information sur la façon de créer un meilleur code, il y ad'autres problèmes qui ne sont pas évoqués dans ce document. Une partie d'entre eux sont les privilèges utilisateur pour l'exécution des programmes, les root kits système et autres problèmes que notre code doit prendre en considération (les variables d'environnement en sont un unique exemple).
448454
449455Veuillez lire plus de ressources techniques telles que :
450456
451457Débordement de tampon :
452458
453459- <http://www.securiteam.com/securityreviews/5QP0L0AFFS.html>
454460- <http://www.securiteam.com/securityreviews/5OP0B006UQ.html>
455461- <http://www.securiteam.com/securityreviews/5IP0G1P8AM.html>
456462- <http://www.securiteam.com/securityreviews/6Q00L00BFI.html>
457463- <http://www.securiteam.com/securityreviews/5UP0B0A60Y.html>
458464
459465Déni de service:
460466
461467- <http://www.securiteam.com/securityreviews/5AP0V0AA1W.html>
462468- <http://www.securiteam.com/securityreviews/6Z00T0K95O.html>
463469
464470Injection SQL :
465471
466472- <http://www.securiteam.com/securityreviews/5DP0N1P76E.html>
467473- <http://www.securiteam.com/securityreviews/5UP010A6AA.html>
468474- <http://www.securiteam.com/securityreviews/5GP0E2K7FO.html>
469475
470476---
471477*From the Free Pascal wiki, page "Secure programming/fr", as it stood on 2020-02-26 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history