Skip to content

Mois : juin 2020

Mikrotik sur VPS freeheberg

Un petit article pour ceux qui auraient besoin d’installer RouterOS sur un VPS Freeheberg (https://www.firstheberg.com/fr/vps-kvm-ssd-windows-linux). Tout d’abord, je n’ai aucunes actions, ni de contrat chez eux. Si je les ai choisis, c’est que je cherchais un VPS à prix abordable, dont les IP (et l’AS) n’étaient pas forcément reconnu comme hébergeur, et donc leurs ip reconnu comme VPN. A priori, des tests que j’ai fait, c’est OK. A voir avec le temps.

Je voulais pouvoir sortir avec un IP française, et pour cela, plusieurs options. Soit je montait une usine avec un Wireguard, mais cela m’obligeait à mettre en place un client de mon coté, et de faire un gros travail de routage. L’autre solution, beaucoup plus simple pour moi, est de mettre en place une distribution que je maîtrise (RouterOS), et de monter un tunnel entre mon installation, et le VPS. Par défaut, Freeheberg ne propose pas routerOS comme distribution. Par contre, ils proposent de booter leurs VPS en rescue, et la, on a plein de possibilités ;).

Pour ce test, j’ai pris une gamme GP1. Un autre avantage de RouterOS, est que l’on a pas besoin de beaucoup de puissance, que ce soit cpu ou RAM. 20GO de SSD, 1 Go de RAM et 2vcpu a 2,4Ghz, c’est plus que suffisant.

Après avoir commandé le vps, et qu’il soit livré (assez rapidement), il suffit de se rendre sur son profil, et de changer le boot du VPS en Rescue:

Une fois rebooté, vos recevez les accès par mail, et vous pouvez vos connecter au VPS en rescue. A partir de la, rien de très compliqué (il faudra par contre extraire le zip du chr de routerOS sur un hébergement pour pouvoir le télécharger, pas sur que unzip soit installé en rescue. a tester):

root@rescue:~# wget http://example.com/chr-6.47.img
root@rescue:~# dd if=chr-6.47.img of=/dev/sda

Et on reboot. Et…

Il ne vous reste plus qu’a changer le mot de passe (par défaut, je vous rappel qu’il n’y a pas de mot de passe. Pour info, voila ce qui s’est passé, après avoir rebooté la VM. moins de 90s entre le boot et les premières tentatives de connexions!

A partir de la, vous avez un router Mikrotik, sur Internet, avec une IP française. Il ne vous reste plus qu’a vous connecter dessus, monter un vpn ou autre! Bon amusement !

Procédure stockée et Trigger sous mysql

Que sont les procédures stockées? A quoi servent-elles?

Si je prends l’exemple de la programmation traditionnelle, une procédure stockée pourra être attribuée à une fonction. Plutôt que de réecrire sans arrêt la même chose, je crée une procédure stockée qui va me faire mon travail. Je peux lui passer des paramètres (ou non). Par contre, ma procédure ne me retournera rien. Elle se contente de faire ce que je lui demande (a contrario d’une function sous mysql qui elle pourra me retourner 1 ou plusieurs enregistrement)

Un exemple basic, tiré de la documentation MySQL:

delimiter //
CREATE PROCEDURE simpleproc (OUT param1 INT)
BEGIN
SELECT COUNT(*) INTO param1 FROM t;
END //
delimiter ;

Il suffira de l’appeler (call simpleproc(@toto)) pour récupérer le retour du count. Notez les 2 commandes “delimiter” avant et après la création de la procédure stockée. C’est nécessaire afin de pouvoir disposer du ; de fin de requete dans la procédure, sinon mysql ne sait pas faire la différence entre le code dedans et dehors (il interpréterais le ; comme étant la fin du CREATE, et donc génère une erreur).

Et le trigger maintenant?

Pour ceux qui ont des notions d’éléctronique, le trigger est un élément qui réagit à un changement de statut (par exemple, on mets un trigger sur un état de sortie, et quand cet état change, on envois un signal. Il réagit donc non pas sur un état 0 ou 1, mais bien sur le changement d’état, de 0 VERS 1). Sous MySQL, c’est la même chose, ou presque. Le trigger va réagir à un update, insert ou delete d’une table bien précise, et va exécuter du code lorsque cela arrive.

L’utilité? par exemple mettre a jour par MySQL une table liée en MyISAM (cela évite que le développeur l’oublie dans son code PHP). Ou, et c’est à cela que je voulais en venir, mettre à jour une table intermédaire en MEMORY… Car c’est bien la que se trouve la puissance d’une optimisation de base de données… Réussir à mettre ensemble tout les outils mis à notre disposition…

Pour cela, et ce sera l’objet d’un autre billet, nous allons intégrer 3 outils de MySQL en une action:
– Une table MEMORY
– Un trigger
– Une procédure stockée

L’objectif? Disposer d’une table contenant de nombreuses données, ou des donnée provenant de multiples tables, disposant d’un temps d’accès très faible (je compte en 100 et 1000 fois plus rapide la récupération de donnée d’une table MEMORY a une table MyISAM…), mais en permanence à jour…

Mais, et ce sera la conclusion de ce billet, pourquoi ne pas utiliser une view, certains me diront? Effectivement, tant que les cas restent simples, avec peu de donnée, une view est efficace, mais quand on doit synthétiser des données venant de plusieurs tables, avec des if, des sous-requêtes, des jointures multiples, des opérations, on se retrouve rapidement à passer de tables a 10’000 données a plusieurs milliards dans la requête (table temporaire)!

Configurer le raid sur un HG 2011 hybrid by OVH

Attention cet article date de 2011 et n’a pas encore été remis a niveau!

Après des très long mois sans post, me voici de retour, avec un nouveau joujou, un HG 2011 Hybrid de chez OVH. Un véritable monstre:

  • Intel Bi Xeon E5630 2x4x2(HT)x2.53+ GHz
  • 48 Go DDR3 ECC
  • 64 bits
  • 2x 120 Go -Intel SSD 320 + 2x 1000 Go – SAS
  • Mega RAID 6 Gb/s avec batterie de secours – RAID HARD 0/1/5/6/10/50/60
  • 10 Gbps Lossless

Bref, de quoi faire un très joli serveur de virtualisation, entre autre. Il faut maintenant le configurer, et le préparer pour qu’il soit pleinement fonctionnel. En effet, une fois livré, l’installation ne se fait que sur les disques SSD. Il faut donc configurer les disques SAS.

De plus, comme j’utilise proxmox pour ma virtualisation, je vais préparer mon infrastructure, afin d’avoir:

  • 90 Go pour mon / sur sda1 (SSD)
  • 30Go pour le SWAP sur sda2 (SSD)
  • 1To pour les VM (/var/lib/vz) sur sdb1 (SAS)

Cette configuration permets d’avoir un SWAP très rapide, et donc pouvoir virtualiser la RAM très facilement, en limitant les pertes. pareil pour le serveur principal, qui sera sur le SSD, donc très rapide et fiable. Sachant que tant sda que sdb seront en raid 1 (pour le moment, je passerais sdb en raid 5 ou 6 le jour ou j’aurais besoin de plus d’espace, ce que permets les HG d’OVH).

Nous allons donc configurer notre sdb afin qu’il soit utilisable sur notre système.

On commence par faire une mise à jour du système

aptitude update && aptitude safe-upgrade

On utilise ensuite parted pour formater le disque

aptitude install parted # parted /dev/sdb GNU Parted 1.8.8 Using /dev/sdb Welcome to GNU Parted! Type 'help' to view a list of commands. (parted) #mklabel New disk label type? [gpt]? #gpt (parted) #mkpart Partition name? []? #vz File system type? [ext2]? #ext3 Start? #0 End? #-1 (parted) #set 1 lvm on (parted) #p Model: LSI MR9260-4i (scsi) Disk /dev/sdb: 1000GB Sector size (logical/physical): 512B/512B Partition Table: gpt Number Start End Size File system Name Flags 1 17,4kB 1000GB 1000GB vz lvm (parted) #quit

Maintenant que nous avons notre partition qui est prête, nous devons la monter, et la préparer pour LVM (je me suis aidé du blog de Toorop pour cette partie: http://blog.toorop.fr/howto-openvz-ovh-hybrid-ssd/, avec cependant quelques différences, liée au système utilisé).
On commence par créer le volume logique (sda étant le raid SSD, nous utilisons sdb pour nos disques SAS):

pvcreate /dev/sdb1

Puis le groupe de volume:

vgcreate vzvg /dev/sdb1

On vérifie que ce soit bien fait, et on valide l’espace que l’on a disponible:

vgdisplay

Affiche chez moi:

vgdisplay
— Volume group —
VG Name vzvg
System ID
Format lvm2
Metadata Areas 1
Metadata Sequence No 5
VG Access read/write
VG Status resizable
MAX LV 0
Cur LV 1
Open LV 1
Max PV 0
Cur PV 1
Act PV 1
VG Size 931,00 GB
PE Size 4,00 MB
Total PE 238335
Alloc PE / Size 230400 / 900,00 GB
Free PE / Size 7935 / 31,00 GB
VG UUID 8MCCFR-xccN-WFdz-rTyc-Bg57-73y7-ue0TSY

Pas mal la bête… On va donc utiliser 900Go pour notre partition:

lvcreate -L 600G -n vz vzvg

On formate en ext3 (choix personnel. Vous pouvez faire du reiserfs, ou autre. J’aurais préféré ext4, mais dans Lenny, c’est galère…):

mkfs.ext3 /dev/vzvg/vz -l vz

Il nous reste plus qu’a monter notre partition au bon endroit (ce qui signifie cependant récupérer nos fichier précédent):

mkdir /mnt/tmp
mount /dev/sysvg/vz /mnt/tmp
cp -pr /var/lib/vz/* /mnt/tmp/
unlink /vz
rm -rf /var/lib/vz/*

On ajoute les données dans fstab:

/dev/vzvg/vz       /var/lib/vz     ext3    defaults        1       2

On monte le tout:

mount -a

Et on supprime ce qui n’est plus nécessaire:

umount /mnt/tmp
rm -Rf /mnt/tmp

On recrée le lien symbolic pour Opnevz:

ln -s /var/lib/vz /vz

Il nous reste plus qu’a tester le tout:

vzctl create 101 --ostemplate debian-5.0-minimal_5.0_i386
Creating container private area (debian-5.0-minimal_5.0_i386)
Performing postcreate actions
Container private area was created
vzctl start 101
Starting container ...
Container is mounted

Et voila… Un petite bête de course entre les mains… Il ne reste plus qu’a tout configurer et transférer ?

Récupérer fichiers récursif via ftp en ligne de commande

Oula, ca fait un titre long… Je ne savais pas comment l’expliciter mieux… J’avais un besoin particulier, récupérer un site d’environ 20Go sur un serveur distant, depuis un de mes serveurs… C’est à dire pas d’interface disponible, et uniquement un accès ftp (certains hébergeurs ne connaissent pas le SSH chroot…). Ok, soit. Je test mget… Pas de bol, je dois faire chaque répertoire à la main…

Et la, la commande magique…

wget -r -N -l 100 ftp://user:pass@url...

Et ca fonctionne, et plutôt pas mal J’ai eu un pic a 60Mbps au début, et la, je suis redescendu à 30Mbps. Surement une limitation de l’hébergeur distant (ayant une carte 10Gbps et 1Gbps de bande passante sur mon dédié, je doute que ce soit moi…). Reste plus qu’a patienter…

Edit Maj. J’ai modifié un peu ma commande, en rajoutant -N -l 100 dans les paramètres. -N me permets de ne transférer que les fichiers mis à jour, et -l lui dit de naviguer sur 100 niveau. Cela me permets de mettre a jour un site de 5Go en moins de 10min (ayant peu de modification, évidemment)

PHP-IDS, ou comment protéger son site web

Attention. Cet article a été écrit en février 2009, et n’a pas encore été réactualisé !

Il y a quelques temps, j’ai découvert un outil indispensable, et qui plus est open source… Il n’en faut pas plus pour que je m’y jette dessus à corps perdus.

PHP-IDS, qu’est-ce que c’est?
Il s’agit d’un système de détection d’intrusion en php. Il s’interpose entre les pages du site, et les données entrées par l’utilisateur, et détecte les tentatives d’injection, que ce soit SQL, XSS ou autres. Utilisant un système de “points”, il va donner un poids a chaque détection, et si le total dépasse la norme tolérée, il interdit la poursuite de l’affichage de la page du site.

Attention, il ne s’agit pas pour autant d’une solution miracle! Il reste nécessaire de bien coder afin d’éviter des problèmes. Mais il fournit une protection suplémentaire au site sur lequel il est configuré.

Mise en place

  1. On récupère les sources sur le site officiel : http://php-ids.org/downloads/
  2. On décompresse nos sources
  3. On mets à jour les fichiers default_filter.xml et converter.php afin d’avoir des données le plus a jour possible
  4. https://svn.php-ids.org/svn/trunk/lib/IDS/default_filter.xml
  5. https://svn.php-ids.org/svn/trunk/lib/IDS/Converter.php
  6. On place le répertoire lib/IDS dans les librairies de notre projet
  7. On configure le fichier IDS/Config/Config.ini
; PHPIDS Config.ini

; General configuration settings

; !!!DO NOT PLACE THIS FILE INSIDE THE WEB-ROOT
; IF DATABASE CONNECTION DATA WAS ADDED!!!

[General]

    ; basic settings - customize to make the PHPIDS work at all
    filter_type     = xml
    filter_path     = /chemin/vers/lib/IDS/default_filter.xml
    tmp_path        = /chemin/vers/lib/IDS/tmp
    scan_keys       = false

    ; in case you want to use a different HTMLPurifier source, specify it here
    ; By default, those files are used that are being shipped with PHPIDS
    HTML_Purifier_Path  = IDS/vendors/htmlpurifier/HTMLPurifier.auto.php
    HTML_Purifier_Cache = IDS/vendors/htmlpurifier/HTMLPurifier/DefinitionCache/Serializer

    ; define which fields contain html and need preparation before
    ; hitting the PHPIDS rules (new in PHPIDS 0.5)
    html[]          = __wysiwyg

    ; define which fields shouldn't be monitored (a[b]=c should be referenced via a.b)
    exceptions[]    = __utmz
    exceptions[]    = __utmc

    ; PHPIDS should run with PHP 5.1.2 but this is untested - set
    ; this value to force compatibilty with minor versions
    ;min_php_version = 5.1.6
    min_php_version = 5.1.2

; If you use the PHPIDS logger you can define specific configuration here

[Logging]

    ; file logging
    ; non necessaire si log via DB
    path            = /chemin/vers/lib/IDS/tmp/phpids_log.txt

    ; email logging

    ; note that enabling safemode you can prevent spam attempts,
    ; see documentation
    recipients[]    = test@test.com.invalid
    subject         = "PHPIDS detected an intrusion attempt!"
    header          = "From: <PHPIDS> info@php-ids.org"
    safemode        = true
    allowed_rate    = 15

    ; database logging

    wrapper         = "mysql:host=localhost;port=3306;dbname=phpids"
    user            = phpids_user
    password        = phpids
    table           = intrusions

; If you would like to use other methods than file caching you can configure them here

[Caching]

    ; caching:      session|file|database|memcached|none
    caching         = memcached
    expiration_time = 600

    ; file cache
    path            = /chemin/vers/lib/IDS/tmp/default_filter.cache

    ; database cache
    wrapper         = "mysql:host=localhost;port=3306;dbname=phpids"
    user            = phpids_user
    password        = 123456
    table           = cache

    ; memcached
    host           = localhost
    port           = 11211
    key_prefix     = PHPIDS
    tmp_path       = /chemin/vers/lib/IDS/tmp/memcache.timestamp
  1. La base de donnée n’est nécessaire que si l’on désire stocker les logs dedans. On peut en effet choisir si on désire un simple fichier de log, syslog, base de donnée, ou rien. Si vous désirez utiliser une base de donnée, il est nécessaire de créer la base seon les infos fournies dans le fichier de conf. POur la création de la table:
CREATE TABLE `intrusions` (
  `id` int(11) unsigned NOT NULL auto_increment,
  `name` varchar(128) NOT NULL,
  `value` text NOT NULL,
  `page` varchar(255) NOT NULL,
  `userid` int(11) unsigned NOT NULL,
  `session` varchar(32) NOT NULL,
  `ip` varchar(15) NOT NULL,
  `reaction` tinyint(3) unsigned NOT NULL COMMENT '0 = log; 1 = mail; 2 = warn; 3 = kick;',
  `impact` int(11) unsigned NOT NULL,
  `created` datetime NOT NULL,
  PRIMARY KEY  (`id`)
);
  1. Une fois configurer, il ne reste plus qu’a l’inclure dans nos sites. Pour cela, je vous conseille de créer un fichier prepend, et de configurer le htaccess pour le charger en priorité. Voici un exemple du fichier de traitement. A vous de l’adapter selon vos besoins:
<?php

// On rajoute le chemin de la lib
set_include_path(
    get_include_path()
    . PATH_SEPARATOR
    . '/chemin/vers/lib/'
);

// Inclusion de PHP-IDS
require_once 'IDS/Init.php';

/*
 * Un exemple d'utilisation consiste à utiliser try()
 * afin de récupérer d'éventuelles erreurs
 */
try {
    // Attention à l'ordre des variables EGPCS
    $request = array_merge_recursive($_GET, $_POST, $_COOKIE);
    $init = IDS_Init::init(APPLI_ROOT.'/lib/IDS/Config/Config.ini');

    // lancement de l'IDS
    $ids = new IDS_Monitor($request, $init);
    $result = $ids->run();

    // Decision...
    if (!$result->isEmpty()) {
        /*
         * Pour le DEBUG il suffit de faire
         * echo $result;
         */
        // Exemple d'interpration : on affiche un msg d'erreur
        echo "Sorry, but it seems your browser has sent incorrect data.<br>";

        // On loggue l'attaque
        /*
         * Dans le cas d'un fichier de log :
         * require_once 'IDS/Log/File.php';
         */
        require_once 'IDS/Log/Database.php';
        require_once 'IDS/Log/Composite.php';

        $compositeLog = new IDS_Log_Composite();
        $compositeLog->addLogger(IDS_Log_Database::getInstance($init));
        /*
         * Dans le cas d'un fichier de log
         * $compositeLog->addLogger(IDS_Log_File::getInstance($init));
         */

        $compositeLog->execute($result);
        die();
    } else {
        // On peut afficher quelque chose pour dire que PHPIDS tourne
        //echo '<a href="?test=%22><script>eval(window.name)</script>">No attack detected - click for an example attack</a>';
        echo "PHPIDS is running";
    }
} catch (Exception $e) {
    printf(
        'An error occured: %s',
        $e->getMessage()
    );
}
  1. Il ne reste plus qu’a tester l’application! Vous pouvez avoir un exemple de ce qui doit se passer ici: http://demo.php-ids.org/

Remarque: PPH-IDS nécessite au minimum PHP 5.1.2 pour fonctionner. De plus, si vous désirez logguer les données dans une base mysql, vous devrez avoir activer PDO et PDO Mysql

Backup journalier serveur – script

Attention… Cet article a été écrit en février 2009 – Je ne l’ai aps encore réactualisé, juste transféré !

Quand on a un serveur dédié, ou même un poste sous Linux, on désire effectuer des sauvegardes, de manière régulière.

Je vous propose ici le script que j’utilise se mes serveurs dédiés, afin d’effectuer une sauvegarde journalière de mes sites, ainsi que de la base de donnée concernée. Le script permets de garder un historique de 7 jours des fichiers et des bases de données. Il ne s’agit pas d’un backup incrémentiel, mais bien total. Pourquoi? Par simplicité, pour éviter d’éventuels problèmes de perte de données intermédiaires, et parce que le backup que j’utilise (backup fournis avec mon dédié chez OVH) ne me permets que de faire du ftp => pas de rsync.

Le script effectue 2 sauvegardes. Tout d’abords il récupère un dump de la base de donnée (dump complète), puis il compresse chaque répertoire séparément. Finalement, il effectue un backup complet directement sur le ftp. Il faut prévoir suffisament de place sur le disque. D’autant que le script garde en local une copie des backups des 7 jours. Il est possible de les supprimer, pour cela, il suffit de faire un rm -rf du répertoire du jour (1-7) et de le recréer.

Néanmoins, je vous proposerais prochainement un script plus perfectionner, permettant de faire à la fois du rsync sur un serveur distant, et du ftp. Il s’agit d’un script sans grandes prétentions, mais qui permets d’avoir un backup fiable et simple à mettre en place!

N’oubliez pas d’adapter les informations de configuration en haut du script, de lui donner les droits d’exécution, et de le placer dans le crontab! Parmis les outils nécessaires au fonctionnement du script, pensez à installer ncftp (aptitude install ncftp), afin de disposer du programme ncftput.

#!/bin/bash



# Les constantes
ftp_login=”’
ftp_pwd=”
ftp_host=”
bdd_login=”
bdd_pwd=”
path_site=”
path_bkp=”
path_ftp=”
email_log=”
date=`date`

# erreurs de ncftput
declare -a CDERR
CDERR[1]=”Could not connect to remote host.”
CDERR[2]=”Could not connect to remote host – timed out.”
CDERR[3]=”Transfer failed.”
CDERR[4]=”Transfer failed – timed out.”
CDERR[5]=”Directory change failed.”
CDERR[6]=”Directory change failed – timed out.”
CDERR[7]=”Malformed URL.”
CDERR[8]=”Usage error.”
CDERR[9]=”Error in login configuration file.”
CDERR[10]=”Library initialization failed.”
CDERR[11]=”Session initialization failed.”
CDERR[142]=”Delai depasse pour la connexion.”

start=”file debut : $date — ”
id=`date +%u`

`mysqldump -u $bdd_login -p$bdd_pwd –all-database > $path_bkp/$id/mysqldump_$id.sql`
for site in `ls $path_site`
do
`rm -Rf $path_bkp/$id/$site”_”$id.tgz`
`tar czf $path_bkp/$id/$site”_”$id.tgz $path_site/$site`
done

`tar –create –gzip –file – $id | ncftpput -v -u $ftp_login -p $ftp_pwd -c $ftp_host $path_ftp/$id.tgz`

res_ftp=$?
if [ $res_ftp != "0" ]; then
`echo ${CDERR[$res_ftp]} | mailx -s “ERREUR LORS DU BACKUP DES FICHIERS !!!” $email_log`
fi

date=`date`
echo $start “fin: $date”

`ls -la $path_bkp/$id/ | mailx -s “Backup du $date” $email_log`

Générateur de mots de passe

Petit script permettant de générer de manière aléatoire des mots de passes sécurisés. Je l’utilise quand j’ai besoin d’une chaine de mot de passe. Vous pouvez l’utiliser a votre convenance, sachez que:

  1. Les mots de passes ne sont pas sauvegardés (pas plus que votre IP ou autre)
  2. Le code est accessible ci-dessous, pour vérification (full javascript)
  3. Vous pouvez le réutiliser a votre convenance (je l’ai repris de ce site: http://www.blazonry.com/javascript/password.php)
Mot de pass généré:

Nbr de caractère

Sans caractères spéciaux
Taille aléatoire (6 - 12)