Option de cache des objets statiques avec apache2

Lorsque l’on modifie le CSS d’un site il est important de rafraichir la page sans quoi celle-ci est affichée avec le CSS ancienne version … résultats déplorables garantis !

Pour contourner celà, il est tout à fait possible de forcer un rafraichissement plus régulier de certains éléments comme les feuilles de style. Pour se faire, il faut ajouter à la config d’Apache quelques lignes que voici :

ExpiresActive On
ExpiresDefault “access plus 1 hours”
ExpiresByType text/css “access plus 1 hours”
ExpiresByType text/html “access plus 1 hours”
ExpiresByType image/gif “access plus 1 days”
ExpiresByType image/jpeg “access plus 1 days”
ExpiresByType image/png “access plus 1 days”

Bien sûr  il y a différentes façon de faire, et le paramétrage est à votre guise…
Attention toute fois, si l’on suit le modèle ci-dessus, les pages dynamiques (jsp, php) seront cachées elles-aussi ce qui peut vous poser des problèmes de raffrachissement ! Elles sont en effet identifiées sous le type text/html.
Une autre configuration peut être : ExpiresActive On
ExpiresDefault “access plus 1 hours”
ExpiresByType text/css “access plus 1 hours”
ExpiresByType text/html “now”
ExpiresByType image/gif “access plus 1 days”
ExpiresByType image/jpeg “access plus 1 days”
ExpiresByType image/png “access plus 1 days”

Des listes modifiables par drag & drop

Une des grosse fonctionnalité d’Ajax est d’offrir une interface dynamique de type client lourd dans un navigateur, nous avons déjà parlé de la communication en tâche de fond qui est le coeur d’Ajax, mais ce qui se passe au niveau du front end est tout aussi important. De nombreux site utilise cette technique de drag & drop pour permettre aux utilisateur de composer eux-même leur interface à leur gout. La première implémentation que nous avons pu en voir il y a quelque années était ici ; depuis les choses ont évoluées …

L’occasion de ce petit billet est un article décrivant en détail le fonctionnement de cette technique en liaison avec un base de donnée. Ce tutoriel pour php est plutôt bien fait, reprenant point par point la liaison à la base de donnée, l’utilisation des css et enfin les fonctions javascript de manipulation et  drag & drop. L’article sur les listes triées dynamiques avec ajax.

Pour ceux qui en outre souhaiterai voir une implémentation plus complète, vous trouverez un bon exemple sur Auverblog.info

Patch du driver rt2570 pour permettre le changement d’adresse MAC

Note : depuis mon patch à été ajouté directement dans les drivers natif …

Le drivers rt2570, correspondant aux chip USB ralink souffre d’un petit bug, à moins qu’il ne s’agisse d’une fonctionnalité, je ne sais pas ! il n’est pas possible de changer leur adresse MAC.

Après analyse du problème, il s’avère que lorsque l’on remonte le driver par un ifconfig rausb0 up celui-ci effectue une réinitialisation complète du périphérique incluant donc le rechargement de l’adresse MAC d’origine et venant donc écraser celle configurée précédemment par le ifconfig rausb0 hw ether ….

La solution a ce problème est assez simple, lors de l’init que l’on trouve dans rtusb_main.c il suffit de tester si l’adresse MAC du net_dev vaut 00, auquel cas on charge celle de la carte (premier appel) sinon, on conserve la valeur du net_dev qui correspond à celle forcée.
Ce qui se traduit par :

Dans la fonction usb_rtusb_open, ligne 1231 environ
RTUSBCmd_kill =0;
CreateThreads(net_dev);
memcpy(pAdapter->net->dev_addr, pAdapter->CurrentAddress, pAdapter->net->addr_len);
// Clear Reset Flag before starting receiving/transmitting
RTMP_CLEAR_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS);

Va devenir:

RTUSBCmd_kill =0;
CreateThreads(net_dev);
// at every open handler, copy mac address.
// PATCH >>>>>>>>>>>>>>>>>>
if ( net_dev->dev_addr[0] == 0 && net_dev->dev_addr[1] == 0 && net_dev->dev_addr[2] == 0 &&
net_dev->dev_addr[3] == 0 && net_dev->dev_addr[4] == 0 && net_dev->dev_addr[5] == 0 ) {
// First time initialization
memcpy(pAdapter->net->dev_addr, pAdapter->CurrentAddress, pAdapter->net->addr_len);
} else {
// Next time “la vérité est ailleurs!”
memcpy(pAdapter->CurrentAddress, pAdapter->net->dev_addr, pAdapter->net->addr_len);
}
// <<<<<<<<<<<<<<<<< PATCH

// Clear Reset Flag before starting receiving/transmitting
RTMP_CLEAR_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS);

Après on recompile, et la solution a l’air de fonctionner …. ??? et bien en fait non elle ne fonctionne pas !! oups.. j’aurais dû un peu plus tester … j’avais un petit oubli … voila qui est corrigé ! merci à larbig d’avoir complété le boulo.
Il semble en effet que l’adresse MAC doit être la même entre le pAdapter et le net_dev sans quoi les trames ne sont pas emises dans l’air … ennuyeux. voici donc le patch complet et cette fois testé !! sisi !! Les modifications sont cette fois dans rtusb_init.c où il faut modifier la fonction NICReadEEPROMParameters de la façon suivante :

VOID    NICReadEEPROMParameters(
        IN      PRT2570ADAPTER  pAdapter)
{
        USHORT                  i;
        int                     value;
        UCHAR                   TmpPhy;
        EEPROM_TX_PWR_STRUC     Power;
        EEPROM_ANTENNA_STRUC    Antenna;//blue
//      EEPROM_VERSION_STRUC    Version;

        DBGPRINT(RT_DEBUG_TRACE,"--> NICReadEEPROMParameters ");

        //Read MAC address.
        RTUSBReadEEPROM(pAdapter, EEPROM_MAC_ADDRESS_BASE_OFFSET, pAdapter->PermanentAddress, ETH_LENGTH_OF_ADDRESS);
        DBGPRINT_RAW(RT_DEBUG_TRACE,"MAC address ReadEEPROM : ");
        for (i = 0; i < ETH_LENGTH_OF_ADDRESS; i++)
                DBGPRINT_RAW(RT_DEBUG_TRACE,"%02x ", pAdapter->PermanentAddress[i]);
        DBGPRINT_RAW(RT_DEBUG_TRACE," ");

        if (pAdapter->PortCfg.bLocalAdminMAC != TRUE)
        {
                pAdapter->CurrentAddress[0] = pAdapter->PermanentAddress[0];
                pAdapter->CurrentAddress[1] = pAdapter->PermanentAddress[1];
                pAdapter->CurrentAddress[2] = pAdapter->PermanentAddress[2];
                pAdapter->CurrentAddress[3] = pAdapter->PermanentAddress[3];
                pAdapter->CurrentAddress[4] = pAdapter->PermanentAddress[4];
                pAdapter->CurrentAddress[5] = pAdapter->PermanentAddress[5];
        }

devient

VOID    NICReadEEPROMParameters(
        IN      PRT2570ADAPTER  pAdapter, struct net_device *net_dev)
{
        USHORT                  i;
        int                     value;
        UCHAR                   TmpPhy;
        EEPROM_TX_PWR_STRUC     Power;
        EEPROM_ANTENNA_STRUC    Antenna;//blue
//      EEPROM_VERSION_STRUC    Version;

        DBGPRINT(RT_DEBUG_TRACE,"--> NICReadEEPROMParameters ");

        //Read MAC address.
        RTUSBReadEEPROM(pAdapter, EEPROM_MAC_ADDRESS_BASE_OFFSET, pAdapter->PermanentAddress, ETH_LENGTH_OF_ADDRESS);
        DBGPRINT_RAW(RT_DEBUG_TRACE,"MAC address ReadEEPROM :");
        for (i = 0; i < ETH_LENGTH_OF_ADDRESS; i++)
                DBGPRINT_RAW(RT_DEBUG_TRACE,"%02x ", pAdapter->PermanentAddress[i]);
        DBGPRINT_RAW(RT_DEBUG_TRACE,"");

        if (pAdapter->PortCfg.bLocalAdminMAC != TRUE)
        {

           if ( net_dev->dev_addr[0] == 0 && net_dev->dev_addr[1] == 0 && net_dev->dev_addr[2] == 0 &&
             net_dev->dev_addr[3] == 0 && net_dev->dev_addr[4] == 0 && net_dev->dev_addr[5] == 0    ) {
                // Startup time ... read the original MAC
                pAdapter->CurrentAddress[0] = pAdapter->PermanentAddress[0];
                pAdapter->CurrentAddress[1] = pAdapter->PermanentAddress[1];
                pAdapter->CurrentAddress[2] = pAdapter->PermanentAddress[2];
                pAdapter->CurrentAddress[3] = pAdapter->PermanentAddress[3];
                pAdapter->CurrentAddress[4] = pAdapter->PermanentAddress[4];
                pAdapter->CurrentAddress[5] = pAdapter->PermanentAddress[5];
           } else {
                // Next time, get the MAC from net_dev->dev_addr
                printk(KERN_INFO "net_dev supplies MAC, activating this one :%02x:%02x:%02x:%02x:%02x:%02x.",
                        net_dev->dev_addr[0], net_dev->dev_addr[1], net_dev->dev_addr[2],
                        net_dev->dev_addr[3], net_dev->dev_addr[4], net_dev->dev_addr[5]);
                memcpy(pAdapter->CurrentAddress, pAdapter->net->dev_addr, pAdapter->net->addr_len);
           }
        }

La mécanique est axactement la même que celle faite précédemment : lors du premier appel on fait comme si de rien n’etait et on recupère l’adresse en EEPROM, pour les appels suivant on choisit la MAC du net_dev à la place.
Pour que ca fonctionne il reste deux petites modifications, modifier le header de cette fonction : dans rt2570sw.h

VOID  NICReadEEPROMParameters(
      IN  PRT2570ADAPTER       pAdapter);

devient :

VOID  NICReadEEPROMParameters(
      IN  PRT2570ADAPTER       pAdapter, 
      struct net_device *net_dev);

enfin il reste l’appel de la fonction de lecture à modifier, dans rtusb_main.c:

   NICReadEEPROMParameters(pAdapter, net_dev);

Ca y est !!

Taille maximum d’un fichier en PHP

Par défaut la taille maximale d’un fichier uploadé depuis PHP est fixée à 2Mo, Pour augmenter cette taille, il faut modifier le fichier /etc/php.ini et indiquer la nouvelle taille en renseignant la variable upload_max_filesize. La taille peut être indiquée en Méga : = 10M par exemple.

Configuration impression avec mozilla et KDE

Comme il arrive que l’impression par défaut configurée par Mozilla déconne un peu, il est possible d’utiliser l’impression KDE.
Pour ce faire, afficher l’écran de propriété de l’imprimante sous Mozilla (après avoir obtenu la fenetre d’envoie d’un impression) puis remplacer la ligne lpr ${MOZ_PRINTER_NAME … par kprinter –stdin

Parsing XML à l’aide de la commande sed

Suite un petit problème pour traiter une flux xml avec sed, je vous livre une solution …
Le problème est le suivant : lorsque l’on a une suite de champs que l’on souhaite remplacer comme suite: (le < > sont remplacés par % pour simplifier l’ecriture de l’article)
de:
%tag1% valeur1 %etag1% %tag1% valeur2 %etag1%
à:
valeur1 valeur2

On pourrait avoir l’approche suivante :
sed -e ‘s/%tag1%(.*)%etag1%/1/g’
Mais le résultat est le suivant:
valeur1 %etag1% %tag1% valeur2

En effet, sed va matcher la plus longue pattern possible ce qui va donner le résultat précédent. Ce qui évidemment n’est pas adapté au traitement de flux XML. La solution est de ne pas utiliser sed mais perl qui va prendre, elle, la plus petite pattern possible pour peu qu’on le lui precise de la façon suivante:
perl -p -e ‘s/%tag1%(.*?)%etag1%/1/g’
Le résultat sera alors:
valeur1 valeur2
C’est l’ajout du “?” à la suite de .* qui précise que perl doit chercher le motif le plus court.

Création d’espace crypté sous Linux

Lorsque l’on souhaite crypter des données avec Linux, il est assez simple de créer une partition cryptée, celle-ci est montée au démarrage ou à la demande ; le disque seul, sans mot-de-passe, devient inutilisable.
Toutefois, cette solution ne permet pas bien, ni la sauvegarde des données cryptées, ni le déplacement physique de ces données, ni leur copie lors d’une réinstallation qui devient alors une étape critique.

La solution à ces problèmes est l’utilisation d’un fichier crypté plutot que d’une partition cryptée. Le fichier en question sera une parition logique cryptée ou cryptofile. La partition logique ainsi crée est en réalité un fichier qui pourra donc être manipulé comme tel.
La création passe par plusieurs étapes :

  • Créer une partition logique initialisée aléatoirement de sorte à faire du bruit.
    dd if=/dev/urandom of=systFile1 bs=1k count=300000
    Cette commande initialise un fichier systFile1 de 300000 blocs de 1ko. Le nombre et la taille des blocs est à votre discretion.
  • Il faut ensuite associer ce fichier à un périphérique loop qui va permettre, non seulement de considérer le fichier comme un périphérique et de le traiter, donc, comme une partition physique, mais aussi de gérer le cryptage / décryptage des informations.
    losetup -e twofish256 -T /dev/loop0 systFile1
    twofish256 est le cryptage retenu, l’option -T va demander 2 fois la saisie du mot de passe, /dev/loop0 correspond au périphérique loop, il est possible de choisir loop1, loop2… enfin on trouve le fichier précédemment créé.
  • Il reste à formater la partition :
    mkfs -t ext2 /dev/loop0
  • Enfin, la partition peut être montée comme n’importe quelle autre à l’aide de mount :
    mount -t ext2 /dev/loop0 mnt/

Cette solution fonctionne parfaitement, toutefois, en cas de saisie d’un mot de passe erroné, le système à tendence à bloquer n’arrivant pas à monter la partition. Des options permettent sans doute d’eviter cela… si vous le connaissez, donnez-les mois ;o).
Petite remarque enfin, n’oubliez pas de monter le module loop_fish2

Mots de passe, attaque brute force, sécurité

A la question votre mot de passe est-il sûr, la réponse est … vérifiez-donc !

Je me posais cette question depuis quelque temps ce qui est l’occasion de faire un petit article sur la chose. La recherche de mots de passe ne se déroule pas comme dans les films, en testant sur le site tous les mots de passe possible ; on ne trouve pas non plus les digit un à un ; effet cinématographique mais mathématiquement idiot …
La recherche de mots-de-passe est généralement possible à partir du moment où celui qui veut le cracker va le posséder. Pas évident me direz-vous mais combien t’entre nous utilisent le même password pour la maison, le travail, l’internet… autant d’opportunités pour un pirate éventuel de se le procurer. D’où la première règle : à son environnement son propre mot-de-passe ; ou en posséder plusieurs par classe de sécurité.

Bref obtenir des passwords n’est pas très compliqué, toutefois, ceux-ci sont cryptés selon des méthodes non réversibles, c’est à dire qu’il ne sera pas possible de décrypter le mot de passe lu. Par ailleurs, la version cryptée ne permet pas de présager du nombre de lettres ni du type de lettres. Le décryptage se fait donc par comparaison, il suffit donc d’essayer toutes les combinaisons possibles, de les crypter et de comparer le résultat obtenu avec celui recherché. Si les deux chaines cryptées sont identique le mot-de-passe courant sera le bon. Simple donc !

C’est là que les math entre en jeu. Combien de temps faut-il pour trouver la chaîne initiale ? Tout celà dépend du nombre de combinaisons possibles, lors d’une attaque brutale c’est le nombre de [caractères différents] à la puissance [nombre de caractères de la chaîne]. Le temps est donc fonction de la taille de la chaine et des caractères utilisés. Voici quelques exemples :

Sur un Athlon XP 2400@1.5GHz :
Chaine numérique pure :

  • 7 digits : 5 secondes
  • 8 digits : 1 minute

Chaine alphabétique en minuscules:

  • 6 digits : 6 secondes
  • 7 digits : 2 minutes
  • 8 digits : 14 minutes

Chaine alpha_num minuscules/majuscules:

  • 4 digits : 7 secondes
  • 5 digits : 8 minutes
  • 6 digits : 84 minutes

Chaine tous caractères:

  • 4 digits : 38 secondes
  • 5 digits : 1 heure
  • 6 digits : 100 heures

Suivant ses résultats, je tire deux conclusion, l’usage de chaines composée d’une maj, d’un symbol spécial suffit pour obliger l’usage d’une recherche tous caractères et c’est dans ce cas que les performances sont vraiment amoindries. Car la logique veut que l’attaquant essayes les combinaisons les plus simples en premier avant le mode tout caractère vu l’ecart significatif dans les temps de traitement.
La seconde conclusion concerne la taille, il est evident qu’une chaîne avec une longueur inférieur à 5 est une pure folie !

Suis-je alors sauvé si mon mot de passe fait plus de 8 digits ?
Et bien non, tout simplement car l’usage veut que l’on utilise des mots de passe simplement mémorisable, souvent nom, prenoms, date de naissance, nom commun… Cet usage est facilement compréhensible, la mémoire humaine ayant ses liminites. Les outils de recherche ont donc pris en compte cet aspect de la nature humaine et utilisent des dictionnaires. C’est une simple liste de mots communs qui servira de référence : plutot que de chercher parmi toutes les chaînes, cherchons parmi celles que notre mémoire nous conduira à favoriser. Le programme sera capable de composer des variantes classiques à partir de cette liste : ajout de majuscules, chiffres, caractères spéciaux. Alors, combien de temps faut-il pour trouver un mot de passe commun ?

Sur un Athlon XP 2400@1.5GHz, avec un dictionnaire de 237000 mots français et des règles de transformation standard, comptez moins de 5 minutes pour tester toutes les possibilités.

Et ce, bien sure, quelque soit la taille de la chaîne choisie. Cette méthode étant la plus efficasse, c’est la principale utilisée.

Donc, que va faire (logiquement) un pirate qui souhaitera connaitre votre mdp ?

  • 1. Lancer une attaque par dictionnaire
  • 2. Lancer une attaque par date (8 digits)
  • 3. Lancer une attaque alpha lower (7 digits)<.LI>
  • 4. Lancer une attaque alpha upper (7 digits).
  • 5. Lancer une attaque alpha (5 digits)

Un pirate qui ne vous en veut pas particulièrement à vous devrait grosso-modo s’en arrêter là car il trouvera sans doute 30 à 40% de mots de passe en suivant ces règles. Et ce dans un temps d’environ 10 minutes. Pour éviter ce genre d’attaque, les règles pour choisir un bon mot de passe sont donc les suivantes :

  • Utiliser au moins 1 digit + 1 symbol spécial + 1 majuscule.
  • Utliser une logueur d’au moins 8 caractères
  • Banir les mots usuels

Alors comment avec celà tourver un mot qui soit mémorisable facilement … Je vous propose une solution simple : utiliser la phonétique choisissons par exemple le prénom paulcomme base :

  • Ne pas le trouver dans le dico : pol
  • Augmenter la taille et complexifier : pPoOlL
  • Ajouter des carcatères spéciaux : [pPoOlL]

Voila 8 digit plutot simple à mémoriser surtout si le mot de base est familier. Pour augmenter la taille il suffit de choisir un mot plus long. Votre cerveau doit alors mémoriser la méthode et non le mot-de-passe en lui même.

Si maintenant vous devez vous protéger de quelqu’un qui cherche à vous ataquer personnellement, le choix du mot de passe est plus compliqué, mais basé sur le même principe, toutefois, il y a des règles supplémentaires à prendre en compte tout d’abord imaginez : le temps qu’il pourra y consacrer et ses ressources : s’il me faut 100h pour trouver un mot quelconque de 6 caractères, ce calcul peut etre très simplement distribué permettant de transfomer ces 100h en 100 fois 1 heure en utilisant 100 machines… Par rapport à celà, vous devez donc prévoir de modifier votre mot de passe au moins 1 fois dans ce temps de calcul qui dépend donc des ressources du pirate. Si vous ne le changez que tous les mois, il aura un mois pour calculer. A partir de là, 8 digits quelconque est à peine fiable ; 10 ou 12 semblent être une meilleure solution. Reprenons un exemple simple à mémoriser : vacances devient : [vVaAcCaAnNcCeEsS] avec 18 caractères ; plutot simple à retenir non ?!?

Face à celà, vous n’etes cependant pas à l’abrit, la dernière methode employable et l’analyse sociale : si vous utilisez la méthode ci-dessus, votre mot-de-passe ne vaudra rien : étant publié, il peut être employé comme motif dans une attaque par dictionnaire. Plus généralement, si vous passez ou avez reçu des consignes dans votre entreprise pour la création de mot-de-passe, il suffira au pirate de se renseigner sur ces consignes, les exemples donnés pour appuyer sa recherche. Bref, la methode de construction étant la clef, elle doit vous être propre. L’avantage ensuite et que vous pouvez changer le mot chaque mois sans changer la methode… par éxemple : janvier2006 devient *janvieR!2006, simple et correct ; adaptable chaque mois.

Les erreurs à ne pas commettre :

  • Les mots-de-passe aléatoires qui finissent sur un post-it sous le clavier
  • Le donner à qui que ce soit : la méthode (clef du mot-de-passe) devient publique
  • Ne pas diffuser un mot de passe critique sur un autre média que celui pour lequel il est prévu : ne pas utiliser le mdp du travail pour s’inscrire sur un site Internet : c’est rendre public le mot de passe ET la methode

Bref, il faut des methodes différentes selon les contextes. Ensuite, il existe des tas d’autre façon de générer/utiliser de très long mots de passe : biometrie ou classeur de mdp sur carte à puce …

Pour finir, vous pouvez tester vous même la fiabilité du mot-de-passe choisi avec des outils comme John-The-Ripper (JTR) avec ou sans KMD5, unhash … facilement téléchargeables sur internet, dictionnaires y compris.