NB1 : xpost fr.comp.lang.php et fu2 fr.comp.securite (les deux sont
modérés).
Après moult tergiversations, je laisse le fu2 sur fr.comp.securite car
on dépasse le cadre du langage PHP et que les failles à débattre sont
majoritairement
humaines et non liées au langage. J'encourage plus que vivement les
habituels lecteurs/contributeurs de fclphp à suivre la discussion sur
fcs (et à le
consulter régulièrement une fois cette bonne habitude prise ;-)...)
Je me porte volontaire pour essayer de faire une synthèse de la
discussion qu'on pourra intégrer dans l'une des deux FAQs et référencer
depuis l'autre.
NB 2 : Cet article étant long et fcs étant modéré, je rappelle aux
contributeurs qui seraient tentés de le citer intégralement que leur
réponse n'a aucune chance d'être publiée. Si vous avez un doute sur la
bonne manière de répondre sur un forum usenet, usez et abusez de
http://www.giromini.org/usenet-fr/repondre.html
Suite aux divers questions/trolls sur la sécurité des applications
écrites en PHP dans une optique web, je lance un petit débat sur les
pratiques de codage en PHP apportant ou non un vrai "plus" de sécurité.
J'entends par "faille de sécurité" une erreur de codage ou de conception
qui permet de passer outre une procédure d'authentification, d'avoir
accès à des données non publiques, ou de modifier/détruire des
données/des scripts, exclusivement dans une optique web, avec php comme
langage dans mon esrit à l'origine, mais on pourra élargir à d'autres
langages/plateformes de web dynamique comme perl, jsp, asp, .net etc...
Les questions sont les suivantes :
Question 1 :
Quelles sont les principales failles existantes dans les scripts PHP que
vous avez rencontrées ? Quels risques induisaient-elles ? Comment les
avez vous corrigées ?
Question 2 :
Quelles sont les principales fausses vérifications de sécurité que vous
connaissez ? Comment peut-on les contourner (indiquer la difficulté
pour y arriver) ou pourquoi ne sont-elles pas fiables ou non applicables
sur le principe même ?
Question 3 :
Pensez vous à des failles théoriques potentielles que vous n'avez pas
encore vérifiées en pratique ?
------------
Je commence bien entendu :
Question 1 (failles existantes):
a) variables non itilialisées en register_globals=On (injection de
variables)
Risque : principalement accès non autorisés, mais tout est possible.
Correction : initialiser ses variables (Sans blague...), ou utiliser des
fonctions/des objets car ils snt insensibles à l'injection de variables.
Piège : croire qu'on est toujours en register_globals=Off et coder comme
un cochon.
Correction : idem.
b) include dynamiques (ex include($toto);)
Risque : exécution sur sa machine de n'importe quel code souhaité par
l'attaquant (installation de back-doors, défigurations, etc....
Correction : ne pas utiliser d'includes dynamiques ou vérifier que le
fichier est bien local si hébergement dédié. Renforcer les restrictions
d'include_path. Attention, depuis php5, file_exists peut éventuellement
renvoyer TRUE sur des fichiers distants (à restester, je n'ai pas poussé
plus loin que le "tip php5" du manuel).
Piège : essayer de se renforcer avec include($toto.'.php');
Contournement : $toto="[target]/script_sans_extension"; par exemple.
c) injection SQL.
Risque : accès non autorisés, corruption de données
Correction : filtrage des variables, échappement de ' et " par le
caractère ad hoc pour la base de données (\ pour mysql, ' pour sybase
etc...)
d) confiance dans les variables venant de l'extérieur. Par exemple,
recalculer une facture à payer en utilisant un prix transmis par un
champ HIDDEN ou calculé en javascript. Ne pas revalider la donnée parce
qu'elle l'a été en JavaScript.
Risque : multiples. Accès non autorisés, corruption de données, etc...
Correction : ne faire confiance qu'à des données conservées côté serveur
(refaire une requête sgbd pour obtenir le prix de l'article, les frais
de port, etc...). Faire avant tout les validations de cohérence des
données côté serveur et non en javascript.
e) uploads de fichiers.
Outre les failles du langage php lui même qui apparaissent parfois à ce
sujet, les tutoriels que j'ai vus n'insistent pas assez sur le besoin de
faire attention aux extensions autorisées par rapport aux extensions
parsées sur le serveur. Si le serveur considère comme du code php le
fichier toto.php.txt, il faut interdire tout nom de fichier contenant
.php. dans son nom. Ceci doit venir en complément d'une liste
restrictive d'extensions explicitement autorisées (.jpg, .gif, .doc
etc...). Je suis plus particulièrement intéressé sur ce point par les
vérification purement serveur permettant de vérifier le type de fichier
traité.
f) utilisation de header("Location:...)
Algo (erronné)
1. vérification de cohérence
2.1 si problème alors header("Location:bad.php"); // jusqu'ici tout va
bien
2.2 si ok alors header("Location:ok.php"); // et plouf dommage, il
suffit d'appeler directement ok.php avec n'importe quels arguments et
tout passe.
Correction :
2.1 si problème require('erreur.php'); exit();
2.2 (sinon) require('traitement.php'); // rappel : toute variable locale
est alors définie dans traitement.php
g) appels systèmes non filtrés
Dans le même genre que les includes dynamiques, passer directement la
saisie de l'utilisateur à exec() ou system(). Personnellement, j'ai
tendance à interdire tout exécution de code directe, filtrée ou par (je
remplace les actions possibles par des cases à cocher et j'exécute ce
qu'il faut). Peut-être est-ce par trop parano et que 'lon peut autoriser
certaines choses.
Risques : donner la main sur votre machine à un attaquant.
Correction : ne jamais passer quoi que ce soit qui vient de l'extérieur
en argument, mais c'est parfois trop restrictif.
Question 2 (fausses vérifications):
a) vérifier que la donnée a bien été transmise par la méthode POST sous
prétexte qu'elle vient d'un formulaire.
Contournement : il suffit d'envoyer une donnée vérolée par post, que ce
soit en modifiant du html ou en utilisant la librairie CURL par exemple
pour de l'attaque massive. C'est le contenu de la donnée qu'il faut
vérifier, pas son mode de transmission.
b) Vérifier que les données viennent bien "de mon site" en utilisant
HTTP_REFERRER.
Une idée (qui n'est pas de moi) et que je n'ai pas réussi à mettre en
oeuvre : injection SQL par des entiers ou plus généralement injection
SQL insensible aux habituelles vérifications sur les quotes.
Soit la requête : "UPDATE .... WHERE id=$i " avec id de type entier
(typiquement : autoincrement)
But de la manip : injecter dans $i une chaîne transformant la requête en
(par exemple):
"UPDATE ... WHERE id=0 OR 1=1"
(requête qui va corrompre les données en impactant tous les rangs de la
table)
Moyen sous mysql : utiliser la fonction mysql CHAR et complèter la
chaîne en hexa. Mais je n'ai pas réussi à le faire, je me prends ou du
syntax error ou une chaîne non interprêtée.
Espérant faire avancer le shimili... le shcibi... le biniou.
- n'y inclure que du code faisant partie de fonctions, et surtout pas de code qui constituerait un main() si le script était appellé directement.
Même si je prêche aussi la séparation "définir-faire", il n'est pas toujours pratique de le faire (exemple typique : les templates d'affichage appelés par le "vrai" code de logique). Comme PHP est insensible à l'injection de constante (fonction define()) on peut aussi commencer tout code ne devant pas être appelé directement par :
<?php if(defined('MA_CONSTANTE')!=TRUE) exit();?>
Ne pas oublier le contrôle des fichiers de backup. Exemples d'extensions à rechercher : '.old', '.bak', '~', '.orig', '.backup', '.bad' Arrgh, j'y pensais plus à celle-ci alors que je me suis déjà fait avoir.
Comme quoi, la non lecture de fcs peut être dangeureuse pour votre santé (et celle de vos applications).
- Seul l'index du BO demande une authentification, accès libre aux autres scripts. Protéger l'accès de TOUS les fichiers du back-office Un grand classique. Mais difficile à détecter sans automatisation sur
une application complexe
Si tu as une fonction ou un script autonome qui fait ça, un bon coup de grep limite la casse. Si tout script "public" devant être protégé commence par : <?php require('check.php');> il est facile de scripter l'obtention de la liste des fichiers ne contenant pas cette chaîne. Celà reste une vérification manuelle et humaine, mais en première approche, ça aide.
a++ JG
Bonjour,
- n'y inclure que du code faisant partie de fonctions, et surtout pas de
code qui constituerait un main() si le script était appellé directement.
Même si je prêche aussi la séparation "définir-faire", il n'est pas
toujours pratique de le faire (exemple typique : les templates
d'affichage appelés par le "vrai" code de logique). Comme PHP est
insensible à l'injection de constante (fonction define()) on peut aussi
commencer tout code ne devant pas être appelé directement par :
<?php if(defined('MA_CONSTANTE')!=TRUE) exit();?>
Ne pas oublier le contrôle des fichiers de backup. Exemples d'extensions
à rechercher : '.old', '.bak', '~', '.orig', '.backup', '.bad'
Arrgh, j'y pensais plus à celle-ci alors que je me suis déjà fait avoir.
Comme quoi, la non lecture de fcs peut être dangeureuse pour votre santé
(et celle de vos applications).
- Seul l'index du BO demande une authentification, accès libre aux
autres scripts. Protéger l'accès de TOUS les fichiers du back-office
Un grand classique. Mais difficile à détecter sans automatisation sur
une application complexe
Si tu as une fonction ou un script autonome qui fait ça, un bon coup de
grep limite la casse. Si tout script "public" devant être protégé
commence par :
<?php require('check.php');>
il est facile de scripter l'obtention de la liste des fichiers ne
contenant pas cette chaîne. Celà reste une vérification manuelle et
humaine, mais en première approche, ça aide.
- n'y inclure que du code faisant partie de fonctions, et surtout pas de code qui constituerait un main() si le script était appellé directement.
Même si je prêche aussi la séparation "définir-faire", il n'est pas toujours pratique de le faire (exemple typique : les templates d'affichage appelés par le "vrai" code de logique). Comme PHP est insensible à l'injection de constante (fonction define()) on peut aussi commencer tout code ne devant pas être appelé directement par :
<?php if(defined('MA_CONSTANTE')!=TRUE) exit();?>
Ne pas oublier le contrôle des fichiers de backup. Exemples d'extensions à rechercher : '.old', '.bak', '~', '.orig', '.backup', '.bad' Arrgh, j'y pensais plus à celle-ci alors que je me suis déjà fait avoir.
Comme quoi, la non lecture de fcs peut être dangeureuse pour votre santé (et celle de vos applications).
- Seul l'index du BO demande une authentification, accès libre aux autres scripts. Protéger l'accès de TOUS les fichiers du back-office Un grand classique. Mais difficile à détecter sans automatisation sur
une application complexe
Si tu as une fonction ou un script autonome qui fait ça, un bon coup de grep limite la casse. Si tout script "public" devant être protégé commence par : <?php require('check.php');> il est facile de scripter l'obtention de la liste des fichiers ne contenant pas cette chaîne. Celà reste une vérification manuelle et humaine, mais en première approche, ça aide.
a++ JG
John Gallet
Re,
Exemple avec une requête où un entier est attendu et où nous n'avons pas droit à " ou ' : http://nicob.net/warsql/level2.html#advanced
Merci pour ce lien, la totalité de la description de l'attaque est d'ailleurs intéressante. J'ai compris mon ânerie dans mes tests : j'essayais de passer outre non pas un entier mais un char. Pour simplifier, (rappelons que le code ascii de ' est 39) je faisais une requête du genre : SELECT .... WHERE colonne_char ='....char(39,......,39).....'; mais je ne m'en apercevais pas aussi facilement.
Sur les différentes familles de XSS "persistant" (aka "par stockage") : http://www.nextgenss.com/papers/SecondOrderCodeInjection.pdf
Merci; vu passé sur security-focus (je crois) récemment, il était dans la pile des "à lire", ça tombe bien donc.
NB : il n'est pas nécessaire de se limiter au Javascript. Prenons le cas de données partagées entre deux sites ayant un niveau de confiance différent (un site web "en vitrine" et l'Intranet sur lequel repose le coeur de métier). On peut arriver à des situations où il est possible d'injecter depuis l'extérieur du Vbscript qui pourra être exécuté sur le LAN ou les agences (l'Intranet étant configuré en tant que 'site de confiance' dans IE) et ainsi hacker des machine en adressage privé, situées derrière 15 pare-feux et un filtrage périmétrique exemplaire (AV sur HTTP et SMTP, pas de P2P, ...).
Principe intéressant, en effet, tout ce qui tourne sur le client est bon à prendre. Quelqu'un a-t-il établit quelque part une règle de filtrage de contenu pour un texte ultra générique à stocker en sgbdr sur lequel un remplacement/filtrage bourrin ne peut pas avoir lieu ? Je m'explique (enfin j'essaie) sur un exemple concret : un textarea de formulaire html qui peut inclure (saisi par l'utilisateur) des balises de mise en form genre gras, souligné, italique. Comment détecter côté serveur tous les langages clients pouvant être embarqués dans cette donnée ? Est-ce que refuser/transormer la chaîne "<?" va suffire ? Dans le même genre est-ce que certains navigateur ne vont pas comprendre son équivalent hexa (par exemple) ?
a++ JG
Re,
Exemple avec une requête où un entier est attendu et où nous n'avons pas
droit à " ou ' :
http://nicob.net/warsql/level2.html#advanced
Merci pour ce lien, la totalité de la description de l'attaque est
d'ailleurs intéressante.
J'ai compris mon ânerie dans mes tests : j'essayais de passer outre non
pas un entier mais un char. Pour simplifier, (rappelons que le code
ascii de ' est 39) je faisais une requête du genre :
SELECT .... WHERE colonne_char ='....char(39,......,39).....'; mais je
ne m'en apercevais pas aussi facilement.
Sur les différentes familles de XSS "persistant" (aka "par stockage") :
http://www.nextgenss.com/papers/SecondOrderCodeInjection.pdf
Merci; vu passé sur security-focus (je crois) récemment, il était dans
la pile des "à lire", ça tombe bien donc.
NB : il n'est pas nécessaire de se limiter au Javascript. Prenons le cas
de données partagées entre deux sites ayant un niveau de confiance
différent (un site web "en vitrine" et l'Intranet sur lequel repose le
coeur de métier). On peut arriver à des situations où il est possible
d'injecter depuis l'extérieur du Vbscript qui pourra être exécuté sur
le LAN ou les agences (l'Intranet étant configuré en tant que 'site de
confiance' dans IE) et ainsi hacker des machine en adressage privé,
situées derrière 15 pare-feux et un filtrage périmétrique exemplaire
(AV sur HTTP et SMTP, pas de P2P, ...).
Principe intéressant, en effet, tout ce qui tourne sur le client est bon
à prendre. Quelqu'un a-t-il établit quelque part une règle de filtrage
de contenu pour un texte ultra générique à stocker en sgbdr sur lequel
un remplacement/filtrage bourrin ne peut pas avoir lieu ? Je m'explique
(enfin j'essaie) sur un exemple concret : un textarea de formulaire html
qui peut inclure (saisi par l'utilisateur) des balises de mise en form
genre gras, souligné, italique. Comment détecter côté serveur tous les
langages clients pouvant être embarqués dans cette donnée ? Est-ce que
refuser/transormer la chaîne "<?" va suffire ? Dans le même genre est-ce
que certains navigateur ne vont pas comprendre son équivalent hexa (par
exemple) ?
Exemple avec une requête où un entier est attendu et où nous n'avons pas droit à " ou ' : http://nicob.net/warsql/level2.html#advanced
Merci pour ce lien, la totalité de la description de l'attaque est d'ailleurs intéressante. J'ai compris mon ânerie dans mes tests : j'essayais de passer outre non pas un entier mais un char. Pour simplifier, (rappelons que le code ascii de ' est 39) je faisais une requête du genre : SELECT .... WHERE colonne_char ='....char(39,......,39).....'; mais je ne m'en apercevais pas aussi facilement.
Sur les différentes familles de XSS "persistant" (aka "par stockage") : http://www.nextgenss.com/papers/SecondOrderCodeInjection.pdf
Merci; vu passé sur security-focus (je crois) récemment, il était dans la pile des "à lire", ça tombe bien donc.
NB : il n'est pas nécessaire de se limiter au Javascript. Prenons le cas de données partagées entre deux sites ayant un niveau de confiance différent (un site web "en vitrine" et l'Intranet sur lequel repose le coeur de métier). On peut arriver à des situations où il est possible d'injecter depuis l'extérieur du Vbscript qui pourra être exécuté sur le LAN ou les agences (l'Intranet étant configuré en tant que 'site de confiance' dans IE) et ainsi hacker des machine en adressage privé, situées derrière 15 pare-feux et un filtrage périmétrique exemplaire (AV sur HTTP et SMTP, pas de P2P, ...).
Principe intéressant, en effet, tout ce qui tourne sur le client est bon à prendre. Quelqu'un a-t-il établit quelque part une règle de filtrage de contenu pour un texte ultra générique à stocker en sgbdr sur lequel un remplacement/filtrage bourrin ne peut pas avoir lieu ? Je m'explique (enfin j'essaie) sur un exemple concret : un textarea de formulaire html qui peut inclure (saisi par l'utilisateur) des balises de mise en form genre gras, souligné, italique. Comment détecter côté serveur tous les langages clients pouvant être embarqués dans cette donnée ? Est-ce que refuser/transormer la chaîne "<?" va suffire ? Dans le même genre est-ce que certains navigateur ne vont pas comprendre son équivalent hexa (par exemple) ?
a++ JG
John Gallet
Bonjour,
Il me semble (ie. c'est ce j'en ai lu sur le Net et mes tests confirment) que les "requêtes préparées" (disponibles au moins en PHP et Perl/DBI) sur un MySQL ne sont pas vulnérables au SQL-Injection. En plus, on peut même avoir un gain en perfs :)
On risque de perdre en portabilité, mais ceci est un autre soucis. En revanche, il me semble avoir lu quelque part dans la couche d'abstraction adodb (couche php multi-sgbdr disponible ou en .php ou en extension C) qu'au contraire les perfs avaient tendance à s'en ressentir. Mais ça doit probablement dépendre "moultement" du SGBDR concerné.
Exemple : $sth = $dbh->prepare("INSERT INTO contacts (name,email) VALUES (?,?)"); Si quelqu'un a la preuve (morceau de code) que ce type d'interrogation de la base protège du SQL-Injection ...
Ca semblerait logique que ça protège (un peu plus seulement ?) si le SGBDR refuse de parser de nouveau le résultat une fois les placeholders remplacés par leur valeur, ce qui est bien le but d'un sql-prepare (ne pas reparser pour ne gagner du temps). Autreent dit, cela "figerait" la requête et considérerait toute variable venant de l'extérieur comme une donnée morte.
Utilisation intéressante, je n'y avais jamais pensé. Mais qu'est-ce que c'est chiant à coder... Enfin, faut savoir ce qu'on veut.
a++ JG
Bonjour,
Il me semble (ie. c'est ce j'en ai lu sur le Net et mes tests confirment)
que les "requêtes préparées" (disponibles au moins en PHP et Perl/DBI)
sur un MySQL ne sont pas vulnérables au SQL-Injection. En plus, on peut
même avoir un gain en perfs :)
On risque de perdre en portabilité, mais ceci est un autre soucis. En
revanche, il me semble avoir lu quelque part dans la couche
d'abstraction adodb (couche php multi-sgbdr disponible ou en .php ou en
extension C) qu'au contraire les perfs avaient tendance à s'en
ressentir. Mais ça doit probablement dépendre "moultement" du SGBDR
concerné.
Exemple :
$sth = $dbh->prepare("INSERT INTO contacts (name,email) VALUES (?,?)");
Si quelqu'un a la preuve (morceau de code) que ce type d'interrogation de
la base protège du SQL-Injection ...
Ca semblerait logique que ça protège (un peu plus seulement ?) si le
SGBDR refuse de parser de nouveau le résultat une fois les placeholders
remplacés par leur valeur, ce qui est bien le but d'un sql-prepare (ne
pas reparser pour ne gagner du temps). Autreent dit, cela "figerait" la
requête et considérerait toute variable venant de l'extérieur comme une
donnée morte.
Utilisation intéressante, je n'y avais jamais pensé. Mais qu'est-ce que
c'est chiant à coder... Enfin, faut savoir ce qu'on veut.
Il me semble (ie. c'est ce j'en ai lu sur le Net et mes tests confirment) que les "requêtes préparées" (disponibles au moins en PHP et Perl/DBI) sur un MySQL ne sont pas vulnérables au SQL-Injection. En plus, on peut même avoir un gain en perfs :)
On risque de perdre en portabilité, mais ceci est un autre soucis. En revanche, il me semble avoir lu quelque part dans la couche d'abstraction adodb (couche php multi-sgbdr disponible ou en .php ou en extension C) qu'au contraire les perfs avaient tendance à s'en ressentir. Mais ça doit probablement dépendre "moultement" du SGBDR concerné.
Exemple : $sth = $dbh->prepare("INSERT INTO contacts (name,email) VALUES (?,?)"); Si quelqu'un a la preuve (morceau de code) que ce type d'interrogation de la base protège du SQL-Injection ...
Ca semblerait logique que ça protège (un peu plus seulement ?) si le SGBDR refuse de parser de nouveau le résultat une fois les placeholders remplacés par leur valeur, ce qui est bien le but d'un sql-prepare (ne pas reparser pour ne gagner du temps). Autreent dit, cela "figerait" la requête et considérerait toute variable venant de l'extérieur comme une donnée morte.
Utilisation intéressante, je n'y avais jamais pensé. Mais qu'est-ce que c'est chiant à coder... Enfin, faut savoir ce qu'on veut.
a++ JG
John Gallet
Bonjour,
Le message publiposté présente des liens et au moindre clic, vous etres fichés avec un ID et une correspondance avec une adresse email, une adresse IP, un FAI, un OS et un navigateur, sans compter les quelques cookies qui seraient en accessibilité globale. [...]
Ces techniques mettent en oeuvre des mécanismes qu'il est facile a implémenter sur plateforme LAMP.
J'ai du mal à comprendre la faille. Qu'est-ce que tu veux qu'un attaquant fasse de mon ip, même fixe, et de mon OS ? Les vers sont capables de scanner tous seuls des segments complets d'adresses, ils n'ont pas besoin d'aller les pêcher sur les newsgroups. Ou alors ils le font déjà, comme pour les boites à spam ?
vol de session: -------------- La clé transmise doit etre assez générique et aléatoire pour ne pas donner l'envie a des utilisateurs malicieux de transmettres d'autres clés. En effet, ça ne fait jamais de mal de le rappeler.
Il existe des mécanismes (librairie Pear) permettant a chaque requete de changer dynamiquement et de maniere transparente la clé attendue pour la prochaine requete. C'est tres pratique et assez sécurisant ...
Un jeton kleenex, si je comprends bien :-)
Si tu as une clef de 30 ou 50 chars "aléatoires" (oui je sais) d'une durée de vie d'une demi-heure d'inactivité, tu ne diminues, me semble-t-il, la probabilité qu'elle soit "devinée" que dans le cas d'une session qui durerait "longtemps". Où pourrait-on situer une barre de durée ? Une heure ? Deux heures ? Plus ?
Théoriquement, la clé qui est neregistrée sous forme de cookie Beurk.
est transmise de maniere systématique quelque soit la requete. Ca oui, dans tous les cas, sinon on risque pas de la comparer à grand
chose.
Au moindre clic sur un site externe, on transmet en meme temps via l'information de type "referer", la clé permettant d'acceder a son propre systeme.
Pas compris. A quoi cela te sert-il de transmettre la provenance (i.e. une de tes pages) à un site externe, le tout via une variable qu'on peut spoofer en une ligne de commande ?
hello, je suis un petit malin : <img src="...site_externe.../script.php" title="c'est un smiley"> il est fort probable que dans certaines circonstance un peu facheuses, le fameux script php soit capable de retrouver des informations contextuelles propres a pénétrer le site.
Là comme ça, je suis curieux de savoir comment. Côté serveur lors de la génération de la page d'affichage du forum ou côté client ?
donc attention aux mails au format html et aux forums embarquant du html. Du html tout court, j'ai du mal à voir, du scripting client, je m'en
doute bien.
Plus précisement, je ne remets pas ta parole en doute, mais j'aimerais comprendre un peu quelles failles (butineur-dependant ?) entrent en jeu.
a++ JG
Bonjour,
Le message publiposté présente des liens et au moindre clic, vous
etres fichés avec un ID et une correspondance avec une adresse email,
une adresse IP, un FAI, un OS et un navigateur, sans compter les quelques
cookies qui seraient en accessibilité globale.
[...]
Ces techniques mettent en oeuvre des mécanismes qu'il est facile a implémenter
sur plateforme LAMP.
J'ai du mal à comprendre la faille. Qu'est-ce que tu veux qu'un
attaquant fasse de mon ip, même fixe, et de mon OS ? Les vers sont
capables de scanner tous seuls des segments complets d'adresses, ils
n'ont pas besoin d'aller les pêcher sur les newsgroups. Ou alors ils le
font déjà, comme pour les boites à spam ?
vol de session:
--------------
La clé transmise doit etre assez générique et aléatoire pour ne pas
donner l'envie a des utilisateurs malicieux de transmettres d'autres clés.
En effet, ça ne fait jamais de mal de le rappeler.
Il existe des mécanismes (librairie Pear) permettant a chaque requete
de changer dynamiquement et de maniere transparente la clé attendue pour
la prochaine requete. C'est tres pratique et assez sécurisant ...
Un jeton kleenex, si je comprends bien :-)
Si tu as une clef de 30 ou 50 chars "aléatoires" (oui je sais) d'une
durée de vie d'une demi-heure d'inactivité, tu ne diminues, me
semble-t-il, la probabilité qu'elle soit "devinée" que dans le cas d'une
session qui durerait "longtemps". Où pourrait-on situer une barre de
durée ? Une heure ? Deux heures ? Plus ?
Théoriquement, la clé qui est neregistrée sous forme de cookie
Beurk.
est transmise de maniere systématique quelque soit la requete.
Ca oui, dans tous les cas, sinon on risque pas de la comparer à grand
chose.
Au moindre clic sur un site externe, on transmet en
meme temps via l'information de type "referer", la clé permettant
d'acceder a son propre systeme.
Pas compris. A quoi cela te sert-il de transmettre la provenance (i.e.
une de tes pages) à un site externe, le tout via une variable qu'on peut
spoofer en une ligne de commande ?
hello, je suis un petit malin : <img src="...site_externe.../script.php" title="c'est un smiley">
il est fort probable que dans certaines circonstance un peu facheuses, le fameux script
php soit capable de retrouver des informations contextuelles propres a pénétrer le site.
Là comme ça, je suis curieux de savoir comment. Côté serveur lors de la
génération de la page d'affichage du forum ou côté client ?
donc attention aux mails au format html et aux forums embarquant du html.
Du html tout court, j'ai du mal à voir, du scripting client, je m'en
doute bien.
Plus précisement, je ne remets pas ta parole en doute, mais j'aimerais
comprendre un peu quelles failles (butineur-dependant ?) entrent en jeu.
Le message publiposté présente des liens et au moindre clic, vous etres fichés avec un ID et une correspondance avec une adresse email, une adresse IP, un FAI, un OS et un navigateur, sans compter les quelques cookies qui seraient en accessibilité globale. [...]
Ces techniques mettent en oeuvre des mécanismes qu'il est facile a implémenter sur plateforme LAMP.
J'ai du mal à comprendre la faille. Qu'est-ce que tu veux qu'un attaquant fasse de mon ip, même fixe, et de mon OS ? Les vers sont capables de scanner tous seuls des segments complets d'adresses, ils n'ont pas besoin d'aller les pêcher sur les newsgroups. Ou alors ils le font déjà, comme pour les boites à spam ?
vol de session: -------------- La clé transmise doit etre assez générique et aléatoire pour ne pas donner l'envie a des utilisateurs malicieux de transmettres d'autres clés. En effet, ça ne fait jamais de mal de le rappeler.
Il existe des mécanismes (librairie Pear) permettant a chaque requete de changer dynamiquement et de maniere transparente la clé attendue pour la prochaine requete. C'est tres pratique et assez sécurisant ...
Un jeton kleenex, si je comprends bien :-)
Si tu as une clef de 30 ou 50 chars "aléatoires" (oui je sais) d'une durée de vie d'une demi-heure d'inactivité, tu ne diminues, me semble-t-il, la probabilité qu'elle soit "devinée" que dans le cas d'une session qui durerait "longtemps". Où pourrait-on situer une barre de durée ? Une heure ? Deux heures ? Plus ?
Théoriquement, la clé qui est neregistrée sous forme de cookie Beurk.
est transmise de maniere systématique quelque soit la requete. Ca oui, dans tous les cas, sinon on risque pas de la comparer à grand
chose.
Au moindre clic sur un site externe, on transmet en meme temps via l'information de type "referer", la clé permettant d'acceder a son propre systeme.
Pas compris. A quoi cela te sert-il de transmettre la provenance (i.e. une de tes pages) à un site externe, le tout via une variable qu'on peut spoofer en une ligne de commande ?
hello, je suis un petit malin : <img src="...site_externe.../script.php" title="c'est un smiley"> il est fort probable que dans certaines circonstance un peu facheuses, le fameux script php soit capable de retrouver des informations contextuelles propres a pénétrer le site.
Là comme ça, je suis curieux de savoir comment. Côté serveur lors de la génération de la page d'affichage du forum ou côté client ?
donc attention aux mails au format html et aux forums embarquant du html. Du html tout court, j'ai du mal à voir, du scripting client, je m'en
doute bien.
Plus précisement, je ne remets pas ta parole en doute, mais j'aimerais comprendre un peu quelles failles (butineur-dependant ?) entrent en jeu.
a++ JG
Th. Boudet
Nicob wrote:
Ne pas oublier le contrôle des fichiers de backup. Exemples d'extensions à rechercher : '.old', '.bak', '~', '.orig', '.backup', '.bad'
Il y a aussi les fichiers de travail de l'éditeur de texte qui
sont situés dans le répertoire courant, parfois cachés, et qui restent là en cas de sortie brutale de l'éditeur. Par exemple, Vim génère ce genre de fichier, dans lequel on trouve le texte pratiquement en clair.
:~/Essais/Demo/Divers $ ls -a ./ ../ .gencodearticle.php.swp gencodearticle.php
Nicob wrote:
Ne pas oublier le contrôle des fichiers de backup. Exemples d'extensions
à rechercher : '.old', '.bak', '~', '.orig', '.backup', '.bad'
Il y a aussi les fichiers de travail de l'éditeur de texte qui
sont situés dans le répertoire courant, parfois cachés, et qui
restent là en cas de sortie brutale de l'éditeur. Par exemple,
Vim génère ce genre de fichier, dans lequel on trouve le texte
pratiquement en clair.
tboudet@mackerel:~/Essais/Demo/Divers $ ls -a
./ ../ .gencodearticle.php.swp gencodearticle.php
Ne pas oublier le contrôle des fichiers de backup. Exemples d'extensions à rechercher : '.old', '.bak', '~', '.orig', '.backup', '.bad'
Il y a aussi les fichiers de travail de l'éditeur de texte qui
sont situés dans le répertoire courant, parfois cachés, et qui restent là en cas de sortie brutale de l'éditeur. Par exemple, Vim génère ce genre de fichier, dans lequel on trouve le texte pratiquement en clair.
:~/Essais/Demo/Divers $ ls -a ./ ../ .gencodearticle.php.swp gencodearticle.php
Cedric Blancher
Le Tue, 23 Nov 2004 06:10:21 +0000, Fabien LE LEZ a écrit :
Et c'est un fichier dont le nom est difficile à trouver ?
Sécurité par l'obscurité, pouah caca... Après, il suffit qu'on exporte malencontreusement une fonctionnalité malheureuse de son serveur Web (genre extensions pour développeurs) et on se retrouve à attaquer des journalistes au tribunal :)
-- 1h23 pour télécharger MRJ, j'espère qu'à cette vitesse ton accès au câble est offert sans abonnement ! -+- TM in Guide du Macounet Pervers : Les paquets passent la douane -+-
Le Tue, 23 Nov 2004 06:10:21 +0000, Fabien LE LEZ a écrit :
Et c'est un fichier dont le nom est difficile à trouver ?
Sécurité par l'obscurité, pouah caca... Après, il suffit qu'on exporte
malencontreusement une fonctionnalité malheureuse de son serveur Web
(genre extensions pour développeurs) et on se retrouve à attaquer des
journalistes au tribunal :)
--
1h23 pour télécharger MRJ, j'espère qu'à cette vitesse ton accès au
câble est offert sans abonnement !
-+- TM in Guide du Macounet Pervers : Les paquets passent la douane -+-
Le Tue, 23 Nov 2004 06:10:21 +0000, Fabien LE LEZ a écrit :
Et c'est un fichier dont le nom est difficile à trouver ?
Sécurité par l'obscurité, pouah caca... Après, il suffit qu'on exporte malencontreusement une fonctionnalité malheureuse de son serveur Web (genre extensions pour développeurs) et on se retrouve à attaquer des journalistes au tribunal :)
-- 1h23 pour télécharger MRJ, j'espère qu'à cette vitesse ton accès au câble est offert sans abonnement ! -+- TM in Guide du Macounet Pervers : Les paquets passent la douane -+-
John Gallet
Re,
Remplacement des " par " et ' par ' : - contournable en mettant ", transformé en " et donc en "
Miardidiou, j'avions point pensé à celle là. Faut que je regarde comment je gère certains types de champs avant de voir si je suis immunisé ou pas.
- si on utilise sa propre fonction de protection contre les quotes, il faut garder un contexte
J'ai plusieurs types de données mappés sur des listes de caractères autorisés. Si je demande $toto=fx_input('toto','ENTIER'); j'aurais ou '' dans $toto si elle était pas définie dans $_REQUEST ou alors exclusivement des chiffres parce que tout autre caractère sera filtré. Si je traite un indicateur internet (genre : &action=new ou &action=update) j'ai un type 'CHAINE_SIMPLE' qui admet exclusivement des lettres et des chiffres (et peut-êter aussi _ je crois, sais plus).Mais quand on doit gérer une zone de textarea ou l'utilisateur peut saisir, dans le cours normal du fonctionnement de l'application, n'importe quoi, y compris par exemple une URL, on peut pas filtrer comme des bourrins. Et là clairement, j'ai du mal à voir un algo de filtrage intelligent. Ca se rapproche du filtrage de code type jsp/aspx/vb etc...
Ajout d'une extension avant include() ou assimilés : - contourné avec un null-byte (%00) si "magic_quotes_gpc = Off"
Tiens une idée qui me vient comme ça en lisant ceci. Serait-il possible de faire de l'injection de constantes prédéfinies ou que l'on sait définies dans un include/require... Genre : include($toto.'.php'); et toto=chaine.CONSTANTE_EXISTANTE.'.php'); et on tripatouille la valeur de la constante depuis l'extérieur parce qu'elle est systématiquement définie par le langage ? Faudra que j'essaie.
Il est de toute façon suicidaire de permettre l'upload en dessous de la web-root. Et que ce soit en PHP, en ASP ou en JSP :
Affirmation à laquelle j'adhère sans réserve, mais comme "l'ennemi c'est l'utilisateur (tm)", si tu as besoin d'écrire dans une webapp un gestionnaire d'upload de photos parce que... c'est dans le cahier des charges, il va bien falloir que lesdites photos soient accédées d'une manière ou d'une autre. Et là, j'ai du mal à voir quel mécanisme employer pour afficher mes 72 .jpg .gif etc... sur la même page html sans les rendre accessibles directement par un GET. Je me vois mal faire un passthru('cat /secure/toto.jpg'); pour aller lire les binaires et espérer que ça s'affiche correctement...
Il pouurait sembler être une bonne idée d'utiliser la commande 'file' pour valider le type de fichier, mais j'ai déjà vu des scripts valides qui étaient considérés par 'file' comme des images.
Gênant :-) de même, "on" (Salut Laurent ;-)) me suggérait récemment d'utiliser les fonctions de la GD-LIB pour vérifier le type de fichier, mais je ne suis pas allé regarder leur mécanisme (i.e. s'ils ne font que lire les octets 156 à 187 du fichier, c'est loin d'être bullet-proof).
a++ JG
Re,
Remplacement des " par " et ' par ' :
- contournable en mettant ", transformé en \" et donc en "
Miardidiou, j'avions point pensé à celle là. Faut que je regarde comment
je gère certains types de champs avant de voir si je suis immunisé ou
pas.
- si on utilise sa propre fonction de protection contre les quotes, il
faut garder un contexte
J'ai plusieurs types de données mappés sur des listes de caractères
autorisés. Si je demande $toto=fx_input('toto','ENTIER'); j'aurais ou ''
dans $toto si elle était pas définie dans $_REQUEST ou alors
exclusivement des chiffres parce que tout autre caractère sera filtré.
Si je traite un indicateur internet (genre : &action=new ou
&action=update) j'ai un type 'CHAINE_SIMPLE' qui admet exclusivement des
lettres et des chiffres (et peut-êter aussi _ je crois, sais plus).Mais
quand on doit gérer une zone de textarea ou l'utilisateur peut saisir,
dans le cours normal du fonctionnement de l'application, n'importe quoi,
y compris par exemple une URL, on peut pas filtrer comme des bourrins.
Et là clairement, j'ai du mal à voir un algo de filtrage intelligent. Ca
se rapproche du filtrage de code type jsp/aspx/vb etc...
Ajout d'une extension avant include() ou assimilés :
- contourné avec un null-byte (%00) si "magic_quotes_gpc = Off"
Tiens une idée qui me vient comme ça en lisant ceci. Serait-il possible
de faire de l'injection de constantes prédéfinies ou que l'on sait
définies dans un include/require... Genre : include($toto.'.php'); et
toto=chaine.CONSTANTE_EXISTANTE.'.php'); et on tripatouille la valeur de
la constante depuis l'extérieur parce qu'elle est systématiquement
définie par le langage ? Faudra que j'essaie.
Il est de toute façon suicidaire de permettre l'upload en dessous de la
web-root. Et que ce soit en PHP, en ASP ou en JSP :
Affirmation à laquelle j'adhère sans réserve, mais comme "l'ennemi c'est
l'utilisateur (tm)", si tu as besoin d'écrire dans une webapp un
gestionnaire d'upload de photos parce que... c'est dans le cahier des
charges, il va bien falloir que lesdites photos soient accédées d'une
manière ou d'une autre. Et là, j'ai du mal à voir quel mécanisme
employer pour afficher mes 72 .jpg .gif etc... sur la même page html
sans les rendre accessibles directement par un GET. Je me vois mal faire
un passthru('cat /secure/toto.jpg'); pour aller lire les binaires et
espérer que ça s'affiche correctement...
Il pouurait sembler être une bonne idée d'utiliser la commande 'file'
pour valider le type de fichier, mais j'ai déjà vu des scripts
valides qui étaient considérés par 'file' comme des images.
Gênant :-) de même, "on" (Salut Laurent ;-)) me suggérait récemment
d'utiliser les fonctions de la GD-LIB pour vérifier le type de fichier,
mais je ne suis pas allé regarder leur mécanisme (i.e. s'ils ne font que
lire les octets 156 à 187 du fichier, c'est loin d'être bullet-proof).
Remplacement des " par " et ' par ' : - contournable en mettant ", transformé en " et donc en "
Miardidiou, j'avions point pensé à celle là. Faut que je regarde comment je gère certains types de champs avant de voir si je suis immunisé ou pas.
- si on utilise sa propre fonction de protection contre les quotes, il faut garder un contexte
J'ai plusieurs types de données mappés sur des listes de caractères autorisés. Si je demande $toto=fx_input('toto','ENTIER'); j'aurais ou '' dans $toto si elle était pas définie dans $_REQUEST ou alors exclusivement des chiffres parce que tout autre caractère sera filtré. Si je traite un indicateur internet (genre : &action=new ou &action=update) j'ai un type 'CHAINE_SIMPLE' qui admet exclusivement des lettres et des chiffres (et peut-êter aussi _ je crois, sais plus).Mais quand on doit gérer une zone de textarea ou l'utilisateur peut saisir, dans le cours normal du fonctionnement de l'application, n'importe quoi, y compris par exemple une URL, on peut pas filtrer comme des bourrins. Et là clairement, j'ai du mal à voir un algo de filtrage intelligent. Ca se rapproche du filtrage de code type jsp/aspx/vb etc...
Ajout d'une extension avant include() ou assimilés : - contourné avec un null-byte (%00) si "magic_quotes_gpc = Off"
Tiens une idée qui me vient comme ça en lisant ceci. Serait-il possible de faire de l'injection de constantes prédéfinies ou que l'on sait définies dans un include/require... Genre : include($toto.'.php'); et toto=chaine.CONSTANTE_EXISTANTE.'.php'); et on tripatouille la valeur de la constante depuis l'extérieur parce qu'elle est systématiquement définie par le langage ? Faudra que j'essaie.
Il est de toute façon suicidaire de permettre l'upload en dessous de la web-root. Et que ce soit en PHP, en ASP ou en JSP :
Affirmation à laquelle j'adhère sans réserve, mais comme "l'ennemi c'est l'utilisateur (tm)", si tu as besoin d'écrire dans une webapp un gestionnaire d'upload de photos parce que... c'est dans le cahier des charges, il va bien falloir que lesdites photos soient accédées d'une manière ou d'une autre. Et là, j'ai du mal à voir quel mécanisme employer pour afficher mes 72 .jpg .gif etc... sur la même page html sans les rendre accessibles directement par un GET. Je me vois mal faire un passthru('cat /secure/toto.jpg'); pour aller lire les binaires et espérer que ça s'affiche correctement...
Il pouurait sembler être une bonne idée d'utiliser la commande 'file' pour valider le type de fichier, mais j'ai déjà vu des scripts valides qui étaient considérés par 'file' comme des images.
Gênant :-) de même, "on" (Salut Laurent ;-)) me suggérait récemment d'utiliser les fonctions de la GD-LIB pour vérifier le type de fichier, mais je ne suis pas allé regarder leur mécanisme (i.e. s'ils ne font que lire les octets 156 à 187 du fichier, c'est loin d'être bullet-proof).
a++ JG
Erwann ABALEA
On Tue, 23 Nov 2004, Simon Marechal wrote:
loufoque wrote:
Il suffit de faire intval($i).
Ou d'utiliser des bindings: On prépare: 'SELECT toto FROM mabase WHERE id=:id' et on fournit plus tard la valeur de :id à l'exécution.
-- Erwann ABALEA - RSA PGP Key ID: 0x2D0EABD5 ----- JR> Vous êtes toujours d'accord avec moi, parfois vous ne le savez pas. Je suis peut-être toujours d'accord avec vous, mais je suis loin d'être toujours d'accord avec ce que vous dites... -+-ED in GNU : On ne prête (de mauvaises intentions) qu'au JR -+-
On Tue, 23 Nov 2004, Simon Marechal wrote:
loufoque wrote:
Il suffit de faire intval($i).
Ou d'utiliser des bindings:
On prépare: 'SELECT toto FROM mabase WHERE id=:id'
et on fournit plus tard la valeur de :id à l'exécution.
--
Erwann ABALEA <erwann@abalea.com> - RSA PGP Key ID: 0x2D0EABD5
-----
JR> Vous êtes toujours d'accord avec moi, parfois vous ne le savez pas.
Je suis peut-être toujours d'accord avec vous, mais je suis loin d'être
toujours d'accord avec ce que vous dites...
-+-ED in GNU : On ne prête (de mauvaises intentions) qu'au JR -+-
Ou d'utiliser des bindings: On prépare: 'SELECT toto FROM mabase WHERE id=:id' et on fournit plus tard la valeur de :id à l'exécution.
-- Erwann ABALEA - RSA PGP Key ID: 0x2D0EABD5 ----- JR> Vous êtes toujours d'accord avec moi, parfois vous ne le savez pas. Je suis peut-être toujours d'accord avec vous, mais je suis loin d'être toujours d'accord avec ce que vous dites... -+-ED in GNU : On ne prête (de mauvaises intentions) qu'au JR -+-
Nicolas George
Nicob wrote in message :
La solution, c'est de : - leur donner une extension ".php" pour que leur contenu ne soit pas renvoyé vers le client mais interprété par le serveur - n'y inclure que du code faisant partie de fonctions, et surtout pas de code qui constituerait un main() si le script était appellé directement.
Il me semblerait encore plus fiable d'interdire qu'ils soient servis au client, ou mieux (si c'est possible avec PHP), les placer en dehors de l'arborescence publiée.
Nicob wrote in message
<pan.2004.11.22.22.29.53.31429@I.hate.spammers.com>:
La solution, c'est de :
- leur donner une extension ".php" pour que leur contenu ne soit pas
renvoyé vers le client mais interprété par le serveur
- n'y inclure que du code faisant partie de fonctions, et surtout pas de
code qui constituerait un main() si le script était appellé directement.
Il me semblerait encore plus fiable d'interdire qu'ils soient servis au
client, ou mieux (si c'est possible avec PHP), les placer en dehors de
l'arborescence publiée.
La solution, c'est de : - leur donner une extension ".php" pour que leur contenu ne soit pas renvoyé vers le client mais interprété par le serveur - n'y inclure que du code faisant partie de fonctions, et surtout pas de code qui constituerait un main() si le script était appellé directement.
Il me semblerait encore plus fiable d'interdire qu'ils soient servis au client, ou mieux (si c'est possible avec PHP), les placer en dehors de l'arborescence publiée.
Nicob
On Tue, 23 Nov 2004 09:11:46 +0000, John Gallet wrote:
[...] au contraire les perfs avaient tendance à s'en ressentir.
Mes tests (à l'époque en Perl/DBI) montraient un gain vraiment important en utilisant les placeholders, dans le cas où la même requête était appelée en boucle.
Utilisation intéressante, je n'y avais jamais pensé. Mais qu'est-ce que c'est chiant à coder... Enfin, faut savoir ce qu'on veut.
Je ne trouve pas ça très ch*ant à coder, surtout en rapport du gain que l'on peut en tirer (perfs, code d'exécution de la requête ultra-lisble et sécurité).
De toute façon, ce n'est qu'une seule ligne supplémentaire par requête.
Nicob
On Tue, 23 Nov 2004 09:11:46 +0000, John Gallet wrote:
[...] au contraire les perfs avaient tendance à s'en ressentir.
Mes tests (à l'époque en Perl/DBI) montraient un gain vraiment important
en utilisant les placeholders, dans le cas où la même requête était
appelée en boucle.
Utilisation intéressante, je n'y avais jamais pensé. Mais qu'est-ce
que c'est chiant à coder... Enfin, faut savoir ce qu'on veut.
Je ne trouve pas ça très ch*ant à coder, surtout en rapport du gain que
l'on peut en tirer (perfs, code d'exécution de la requête ultra-lisble
et sécurité).
De toute façon, ce n'est qu'une seule ligne supplémentaire par requête.
On Tue, 23 Nov 2004 09:11:46 +0000, John Gallet wrote:
[...] au contraire les perfs avaient tendance à s'en ressentir.
Mes tests (à l'époque en Perl/DBI) montraient un gain vraiment important en utilisant les placeholders, dans le cas où la même requête était appelée en boucle.
Utilisation intéressante, je n'y avais jamais pensé. Mais qu'est-ce que c'est chiant à coder... Enfin, faut savoir ce qu'on veut.
Je ne trouve pas ça très ch*ant à coder, surtout en rapport du gain que l'on peut en tirer (perfs, code d'exécution de la requête ultra-lisble et sécurité).
De toute façon, ce n'est qu'une seule ligne supplémentaire par requête.