Catégories
PHP Symfony 2

Ajouter une librairie Tierce à Symfony 2

Je tente d’intégrer la librairie « getID3() » dans mon projet d’apprentissage de Symfony 2.

Pour faire selon les préconisations de Symfony 2, les aplications tierces se placent dans le dossier vendor des sources du projet.
Pour les librairies récentes ( au moins développé en PHP 5.3 ) et qui suivent le standard RP-0, cela se ferait directement, seulement ici ce n’est pas la cas. Il va donc falloir rusé un peu, mais rien de bien sorcier non plus.

Mode d’emploi :

On commence par préparer le terrain en créant les répertoires nécessaires :

1
/vendor/getid3/getID3/src

et on y place les sources de getID3()

1
2
3
4
<?php
# vendor/getid3/getID3/getID3.php
require_once __DIR__.'/src/getid3/getid3.php';
class getID3_getID3 extends getID3 {}

On renseigne ensuite l’autoloader de Symfony 2

1
2
3
4
5
6
# app/autoload.php

$loader->registerPrefixes(array(
   // … others lines
   'getID3_'            => __DIR__.'/../vendor/getid3',
));

et on peu dès lors l’utilisé normalement :

1
2
3
// …
$getID3 = new \getID3_getID3();
// …

En espérant que cela aide.

Ressources :

Catégories
PHP

Sessions

Désactiver les identifiants de sessions dans les URLS

En activant « session.use-only-cookies », vous éviterez les attaques qui utilisent des identifiants de sessions dans les URLS.

Le système de gestion des sessions par URL pose un risque supplémentaire de sécurité : un utilisateur peut envoyer son URL avec l’identifiant de session par email à un ami, ou bien le mettre dans ses signets. Cela diffusera alors l’identifiant de session. On le désactive donc.

1
2
3
ini_set('session.use_only_cookies', 1);
ini_set('session.use_trans_sid');', 0);
session_start();

Initialiser les sessions

Session fixation

Quelques explications : http://en.wikipedia.org/wiki/Session_fixation

1
2
3
4
5
6
7
// Session fixation
// On vérifie qu'une valeur connue de nous même (ici "no_fixation") est présente 
// en session, sinon on regénère la session.
if (!isset($_SESSION['no_fixation'])) {
    session_regenerate_id(true); 
    $_SESSION['no_fixation'] = true;
}

Session hijacking

Quelques explications : http://en.wikipedia.org/wiki/Session_hijacking

1
2
3
4
5
6
7
// Session hijacking
$signature = md5($_SERVER['HTTP_USER_AGENT'] .  $_SERVER['HTTP_ACCEPT_CHARSET'] . SALT);
if (!isset($_SESSION['signature'])) {
    $_SESSION['signature' ] = $signature;
} elseif ($_SESSION['signature'] !== $signature) {
    die('Erreur de session ' );
}

Attention !
J’ai remarqué que sous certains navigateurs l’entête Accept n’est pas forcément consistant d’une page à l’autre, notamment en actualisant une page. C’est donc un entête à éviter pour la signature.

Catégories
PHP

CSRF et QuickForm de PEAR

J’utilise encore beaucoup QuickForm de PEAR pour gérer mes formulaires, une classe pour disposer automatiquement d’une « protection » contre les CSRF trouvée à l’adresse : http://shiflett.org/articles/cross-site-request-forgeries#comment-66

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<?php
 
/**
 * @uses HTML_QuickForm
 * @desc Add automatic CSRF mitigation to all forms by incorporating a token that must be matched in the session and forcing the use of POST method
 */
require_once "QuickForm.php";
class HTML_QuickFormS extends HTML_QuickForm {
 
    /**
     * @property string $_sessionTokenKey The name of the session variable containing the token
     */
    private $_sessionTokenKey;
 
    /**
     * @method HTML_QuickFormS
     * @desc Override the method to always use post and pass it on to the parent constructor. Create a session key for the token based on the form name.
     * @param string $formName
     * @param string $method
     * @param string $action
     * @param string $target
     * @param mixed $attributes
     * @param boolean $trackSubmit
     */
    public function HTML_QuickFormS($formName='', $method='post', $action='', $target='', $attributes=null, $trackSubmit=false){
        $this->_sessionTokenKey = "QuickFormS_".md5($formName);
        parent::HTML_QuickForm($formName, 'post', $action, $target, $attributes, $trackSubmit);
    }
 
    /**
     * @method display
     * @desc Create a token if necessary and place a hidden field in the form before displaying
     * @return void
     */
    public function display(){
 
        //A token hasn't been created so do so
        if(!isset($_SESSION[$this->_sessionTokenKey])){
            $_SESSION[$this->_sessionTokenKey] = md5(uniqid(rand(), true).session_id()); //requires the session id to be known in order to add extra difficulty to compromising
        }
 
        //Hide the token at the end of the form
        $this->addElement("hidden", "qfS_csrf", $_SESSION[$this->_sessionTokenKey]);
        parent::display();
    }
 
    /**
     * @method validate
     * @desc Check if the passed token matches the session before allowing validation
     * @return boolean
     */
    public function validate(){
 
        //The token was not passed or does not match
        if(!isset($this->_submitValues['qfS_csrf']) || $this->_submitValues['qfS_csrf']!=$_SESSION[$this->_sessionTokenKey]){
            $this->setElementError("qfS_csrf", "Anti-CSRF token does not match");
        }
 
        return parent::validate();
    }
 
}
 ?>
Catégories
PHP Trucs et astuces

Protection de vos scripts PHP : validation des données, XSS, CSRF,…

Aujourd’hui je commence une série d’articles sur quelques points de sécurité et de bon sens avec PHP.
Ces articles n’ont et n’auront rien de bien original par rapport à ce que l’on peut glaner de ci de là sur Internet, mais ils pourront me ou vous servir d’aide mémoire ou de piqûre de rappel !

Validation et filtrage des entrées

Un maître mot : « Ne jamais faire confiance aux données étrangères » !
Chaque donnée reçue doit être validée pour s’assurer qu’elle corresponde à ce que l’on attend réellement.

En PHP il existe de très nombreux outils de validation des données :

  1. Les opérateur de comparaison, de taille (chaînes, tableaux),…
  2. L’utilisation de liste de valeurs autorisées (« white-list ») : isset($hash[$var]) ... in_array($var, $allowed)
  3. À l’aide d’expression régulières : preg_match(‘/…/’ , $var);
  4. Extension ctype : ictype_digit($var); qui va vérifier que $var ne contient que des chiffres
  5. Les fonctions is_* : is_scalar($var);
  6. Depuis l’extension PHP 5.2, l’utilisation de l’extension Filter est recommandée.
    Exemple d’utilisation  :

    1
    2
    
    $clean['param1'] = filter_input(INPUT_POST, 'param1', FILTER_VALIDATE_BOOLEAN);
    $clean['email'] = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
  7. Pour Zend l’utilisation des classes Zend_Validate_* ainsi que la création de vos propres validateurs.

Ces validations doivent s’appliquer sur les données reçues par : $_GET, $_POST, $_REQUEST, $_COOKIES, $_FILES et certaines en provenance de $_SERVER ($_SERVER['PHP_SELF'] par exemple.

Échappement des sorties

Une fois vos données validées, il reste à échapper les sorties afin d’éviter les attaques XSS (Cross-site scripting) : détournement de formulaires, modification de l’affichage, vols de cookies, de sessions, etc.

De même que pour la validation des données PHP contient tout le nécessaire pour effectuer ces opérations :

  • Protéger les caractères sensibles : htmlspecialchars($var);
  • Protéger tous les caractères : htmlentities($var,...) et mb_htmlentities($var,...). Le deuxième paramètre, ENT_COMPAT|ENT_QUOTES|ENT_NOQUOTES est parfois important.
  • Enlever les balises HTML : striptags($text);
  • Encodage spécique pour URL : urlencode($var);
  • L’extension Filter peut non seulement valider comme vu au-dessus, mais aussi filtrer en sortie avec FILTER_SANITIZE_*
  • Pour Zend l’utilisation des classes Zend_Filter_* est tout aussi aisée, avec la possibilité de créer ses propres filtres suivant ses besoins

Attention au jeu de caractères, en particulier pour htmlentities() : problème d’affichage, voire de sécurité.
Pour les charsets multi-octets (comme UTF-8), mb_htmlentities() est plus fiable.

Protection des formulaires

S’assurer que les champs cachés ne sont pas modifiés

Pour cela il suffit d’envoyer en parallèle un hash contrôlant la valeur du champ caché.

1
2
3
4
5
6
<?php $idhash = md5($id . SALT); ?>
<form action="edit.php" method="POST">
<input type="hidden" name="id" value="<?php echo $id ?>" />
<input type="hidden" name="idhash" value="<?php echo $idhash ?>" />
<input type="submit" value="Valider" />
</form>

Et à la réception des données, vérifier que le hash correspont bien à la valeur attendue :

1
2
3
4
5
$id = filter_input(INPUT_POST, 'id', FILTER_VALIDATE_INT);
$idhash = filter_input(INPUT_POST, 'idhash', FILTER_VALIDATE_INT, FILTER_FLAG_ALLOW_HEX);
if ($idhash !== md5($id . SALT) {
die('Le formulaire est louche ! ' );
}

Se prémunir des CSRF (Cross-Site Request Forgery)

Les attaques CSRF consistent à faire exécuter des commandes involontaires aux utilisateurs accrédités d’un site.

Quelques astuces pour s’en prémunir ou au moins en limiter grandement la portée, certaines évidentes et facile à mettre en place, d’autres plus subtiles…

Demander des confirmations à l’utilisateur pour les actions critiques

Par exemple systématiquement demander une confirmation du style « Êtes vous certain de vouloir … » sur des actions sensibles comme la suppression, ou redemander de saisir le mot de passe lors de la modification de la configuration de votre site internet.

Utiliser des jetons de validité dans les formulaires

Le principe est simple : lorsqu’un utilisateur affiche un formulaire, on lui génère une clé. Cette clé sera valide pour un certain temps (quelques minutes, le temps de remplir le formulaire), et est liée uniquement au couple utilisateur/formulaire. Cette clé devra automatiquement être transmise avec le formulaire pour que celui ci puisse être validé !

Dans le framework Zend il existe un élément de formulaire dédié à cet usage : Zend_Form_Element_Hash, son utilisation est aisée :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Mon_Formulaire_anti_csrf extends Zend_Form {
  public function init() {
    $this->setMethod('post');
    $this->addElement( 'submit'
                     , 'submit'
                     , array( 'ignore'   => true
                     , 'label'    => 'Soumettre'
                     ,)
                     );
    $form->addElement( 'hash'
                       , 'no_csrf'
                       , array( 'salt' => 'unique')
                       ); 
}

Le hash généré est stocké en session et sera ajouté à la chaîne de validation du formulaire : s’il est différent de celui stocké, il y aura une erreur d’émise.

Éviter d’utiliser des requêtes HTTP GET pour effectuer des actions

Passer systématiquement par POST pour toutes les actions autres que celles de consultation de ressource : insertion, mise à jour ou suppression de données.
Cette mesure va vous prémunir des attaques simples basées sur les images, mais pas de requêtes HTTP POST forgée en JavaScript par exemple.

Quelques liens pour aller plus loin :

  1. http://fr.wikipedia.org/wiki/Cross-site_request_forgery
  2. Zend_Form_Element_Hash
  3. http://bigornot-fr.blogspot.com/2008/07/csrf-sea-surf-and-zend.html
  4. http://truffo.fr/2010/03/les-filtres-php/
  5. http://zendframework.com/manual/fr/zend.filter.html
  6. http://zendframework.com/manual/fr/zend.validate.html
  7. Extension Filter
Catégories
Linux MySQL Programmation Trucs et astuces

Utilisation de mysqlsniffer

But et utilité :

Pour pouvoir − en temps réel − visualiser et analyser et/ou capturer les requêtes effectuées sur un serveur ce petit logiciel est quasiment indispensable.
Il permet d’afficher en détails les requêtes effectuées, les résultats de ces dernières,…

Il est disponible sur le site : http://hackmysql.com/mysqlsniffer

Installation :

Sous Debian, il faut au préalable installer libpcap-dev : aptitude install libpcap-dev.
Puis :

  1. mkdir mysqlsniffer
  2. cd mysqlsniffer
  3. wget http://hackmysql.com/code/mysqlsniffer.tgz
  4. tar zxvf mysqlsniffer.tgz
  5. gcc -O2 -lpcap -o mysqlsniffer mysqlsniffer.c packet_handlers.c misc.c

Utilisation :

Attention ! La connexion à « écouter » doit se faire en TCP, il faut mettre 127.0.0.1 au lieu de localhost dans la configuration du client pour avoir un résultat !

Ensuite il suffit de lancer la commande mysqlsniffer et de lire le résultat dans la console ou le stocker dans un fichier pour une analyse ultérieure.

Exemple de dump :

Une simple requête (SELECT) qui récupère des préférences :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
127.0.0.1.47254 > server: ID 0 len 26 COM_QUERY: SELECT * FROM preferences
server > 127.0.0.1.47254: ID 1 len 1 6 FIELDS
        ID 2 len 76 FIELD: preferences.categorie <TYPE var string (509) SIZE 50>
        ID 3 len 66 FIELD: preferences.type <TYPE var string (509) SIZE 50>
        ID 4 len 62 FIELD: preferences.id <TYPE var string (1021) SIZE 255>
        ID 5 len 82 FIELD: preferences.defaultvalue <TYPE BLOB (4604) SIZE 65535>
        ID 6 len 68 FIELD: preferences.label <TYPE var string (509) SIZE 255>
        ID 7 len 80 FIELD: preferences.description <TYPE BLOB (4604) SIZE 65535>
        ID 8 len 5 END <warnings 0>
        ID 9 len 119 || diagnostic | text | departement_favori | 57 | Département par défaut | Doit être un des départements français (format numérique) ||
        ID 10 len 49 || synchro | text | login | XXX | Votre compte utilisateur |  ||
        ID 11 len 61 || divers | text | nb_clients_par_page | 30 | Nombre de clients listés |  || 
        ID 12 len 61 || divers | text | nb_projets_par_page | 30 | Nombre de projets listés |  ||
        ID 13 len 48 || synchro | String | password | XXX | Votre mot de passe |  ||
        ID 14 len 66 || diagnostic | text | rapport_pcs_2_m3 | 10.6 | Taux de conversion PCS->M3 |  ||
        ID 15 len 60 || synchro | text | sapid | xxx | Votre identifiant de compte (SAPID) |  ||
        ID 16 len 5 END <warnings 0>

Une autre façon de récupérer toutes les requêtes exécutées sur le serveur en écoute : TCPDUMP

Cette méthode ne permet pas de récupérer les infos complètes

1
2
3
4
5
6
7
8
9
tcpdump -i lo -s 0 -l -w - dst port 3306 | strings | perl -e '
while(&lt;&gt;) { chomp; next if /^[^ ]+[ ]*$/;
if(/^(SELECT|UPDATE|DELETE|INSERT|SET|COMMIT|ROLLBACK|CREATE|DROP|ALTER|SHOW)/i) {
if (defined $q) { print "$q\n"; }
$q=$_;
} else {
$_ =~ s/^[ \t]+//; $q.=" $_";
}
}'

On peut trouver de nombreux autres outils pour MYSQL sur le site : http://hackmysql.com/tools avec notamment mysqlreport

Catégories
Programmation

Subversion – Création d’une archive d’une ou plusieurs révisions

Un première version du script : Permet de créer un zip d’un intervalle de révisions pour un export.
Il reste des améliorations à faire c’est sûr, mais aujourd’hui cela répond à mes besoins du moment !

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/bin/sh
# svndiff2zip.sh
 
# Vérifications
if [ ! $1 ];then echo "svndiff2zip : Pas de dépôt spécifié - obligatoire";exit;fi
if [ ! $2 ];then echo "svndiff2zip : Pas de révision de début spécifiée - obligatoire";exit;fi
if [ ! $3 ];then echo "svndiff2zip : Pas de révision de fin spécifiée - obligatoire";exit;fi
if [ ! $4 ];then echo "svndiff2zip : Pas de destination spécifiée - obligatoire";exit;fi
 
if [ -d $4 ];then echo "svnxport : le répertoire '$4' existe déjà : supprimer ou autre.";exit;fi
 
 
echo "Processing : source($1), revision start($2), revision end($3), target_directory($4)"
 
# Traitement
for myfile in `svn diff -r $2:$3 --summarize $1 | grep -e '^M ' -e '^A ' -e '^AM '`
do
if  [  "$myfile" = "M"  -o  "$myfile" = "AM" -o "$myfile" = "A" -o "$myfile" = "." -o -d $myfile ]
then
 continue
else 
 outfile=`echo $myfile |sed "s|$1||g"`
 dir="$4/$outfile"
 mkdir -p $(dirname $dir)
 
 svn export --force $myfile $4/$outfile &gt;&gt; /dev/null
 echo "export $4/$outfile "
 
 zip -r "$4.zip" $4 &gt;&gt; /dev/null
 
fi
done
Catégories
Programmation

Subversion – Importer un dépôt dans un autre

Problématique :

Il peut arriver d’avoir à réunir deux projets initialement dans deux dépôts SVN distincts pour n’en former plus qu’un. Voici une solution facile à mettre en œuvre et efficace.

Solution :

  1. Création d’un dump complet du site à importer.
    svnadmin dump <path-repository> > file.dump
  2. Préparer le dépôt à recevoir :
    svn mkdir <url-repository>/<new-rep> -m "Nouveau répertoire d'accueil"
  3. Importer l’ancien dépôt :
    svnadmin load --parent-dir <new-rep> <path-repository> < file.dump

Les « commit » sont alors ajoutés dans l’ordre. Par contre les numéros de commit ne sont pas conservés. Cela peut être problématique si dans certains commentaires, pages de blog, des liens vers des commits particuliers ont été indiqués comme cela est possible dans des outils comme Trac, Redmine, …

Catégories
Programmation

Recommendations (X)HTML + CSS + DOM

(X)HTML

  1. HTML 4.01 Specification (Traduction: http://www.la-grange.net/w3c/html4.01/)
  2. XHTML 1.0 The Extensible HyperText Markup Language (Traduction: XHTML 1.0)
  3. XHTML Basic (Traduction: XHML Basic )
  4. XHTML Élémentaire (Traduction: XHTML Élémentaire)
  5. http://www.w3.org/QA/2002/04/valid-dtd-list.html

CSS

  1. Cascading Style Sheets, level 1, Traduction : Recommandation CSS1 du W3C en version française
  2. Cascading Style Sheets, level 2, Traduction : Recommandation CSS2 du W3C en version française

DOM

  1. Document Object Model Level 1 Specification, traduction Modèle Objet de Documents Spécification niveau 1
  2. http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/
  3. Document Object Model Level 2 Views Specification
  4. Document Object Model Level 2 Events Specification
  5. Document Object Model Level 2 Style Specification
  6. Document Object Model Level 2 Traversal and Range Specification
  7. Document Object Model Level 2 HTML Specification

SITES UTILES

  1. http://www.mentalized.net/cssdepot/
  2. http://centricle.com/ref/css/filters/
  3. http://web-graphics.com/
  4. http://bclary.com/2004/11/25/html-entities
  5. http://www.glish.com/

DIVERS

  1. Liens et nouvelle fenêtre (XHTML1.1)
Catégories
Programmation

Accessibilté des sites internet

Vidéo sur l’accessibilite à l’université du Wisconsin

La vidéo sur l’accessibilite à l’université du Wisconsin

Quelques liens :

Quelques exemples, tutoriels :

Des documents à télécharger :