Ajax et XSS : autoriser les requêtes grâce au CORS

Lorsqu’on développe une application RESTful exploitant des webservices disponibles sur un autre domaine, on est rapidement confronté à des questions de sécurité, notamment le cross-site scripting (XSS).

Le problème

Le cas typique dans lequel on rencontre cette problématique est celui d’un site mobile « m.domaine.com » qui récupère des données sur le site desktop « domaine.com ». Toutes les requêtes Ajax partant de « m.domaine.com » vers « domaine.com » seront bloquées par la règle de sécurité Same Origin Policy.

La solution

La solution à cette problématique est le mécanisme du Cross-origin resource sharing (CORS) spécifié par le W3C et utilisable dans Apache et dans la plupart des navigateurs modernes.

La configuration Apache

Le vhost du domaine cible des requêtes (« domaine.com » dans notre exemple) doit spécifier des directives « Access-Control-Allow » :

<VirtualHost *:80> 
    ServerName domaine.com

    Header set Access-Control-Allow-Origin "http://m.domaine.com"
    Header set Access-Control-Allow-Credentials true
    Header set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT"
    Header set Access-Control-Allow-Headers "content-type, accept, set-cookie"
</VirtualHost>

Astuce

Grâce à la directive « Access-Control-Allow-Headers », on peut indiquer quels entêtes HTTP seront transmis. En autorisant « set-cookie », on peut récupérer, sur « m.domaine.com », le cookie d’une session ouverte sur « domaine.com ». Ainsi, on réalise facilement un petit SSO maison !

Les requêtes Ajax

Avec jQuery, la requête Ajax devra contenir le flag withCredentials à true dans les paramètres xhrFields (voir également la doc de XMLHttpRequest pour les autres implémentations).

$.ajax({
    url: 'http://domaine.com',
    xhrFields: {
        withCredentials: true
    }
});

Attention à la subtilité !

On trouve très souvent la syntaxe ci-dessous :

Header set Access-Control-Allow-Origin "*"

Cette directive ne fonctionne pas lorsqu’on passe le flag withCredentials à true dans les paramètres xhrFields de la requête Ajax. Dans ce cas, il faut préciser explicitement le domaine autorisé :

Header set Access-Control-Allow-Origin "http://m.domaine.com"

RequireJS et ParsleyJS : utiliser les shims pour traduire vos contrôles de formulaires

ParsleyJS est une librairie Javascript permettant de contrôler la saisie de ses formulaires. Elle est livrée avec de nombreuses traductions de ses messages d’erreurs. Si vous gérez les dépendances de votre projet avec RequireJS, voici comment charger élégamment les traductions de Parsley.

Configuration des dépendances avec RequireJS

On indique à RequireJS le path vers les modules « parsley », « parsleyfr » et « parsleyfrextra ». Puis, on utilise les shims pour définir 2 nouvelles dépendances du module « parsley » :

  • parsleyfr
  • parsleyfrextra
require.config({
    paths: {
        "jquery":           "libs/jquery/dist/jquery",
        "underscore":       "libs/underscore/underscore",
        "backbone":         "libs/backbone/backbone",
        "parsley":          "libs/parsleyjs/dist/parsley",
        "parsleyfr":        "libs/parsleyjs/src/i18n/fr",
        "parsleyfrextra":   "libs/parsleyjs/src/i18n/fr.extra",
    },
    shim: {
        "parsley": {
            deps: ["parsleyfr", "parsleyfrextra"]
        },
    }
});

Déclaration d’une dépendance à Parsley

Ensuite, dans nos modules qui dépendent de Parsley, on indique normalement la dépendance dans la fonction « define ».

define([
        "backbone",
        "underscore",
        "parsley"
    ],
    function(Backbone, _) {

    }
);

Grâce aux shims, RequireJS va charger les modules « parsleyfr » et « parsleyfrextra » avant le module « parsley ». Vous pourrez ensuite changer la locale de vos contrôles de formulaires en appelant la méthode « setLocale » de ParsleyJS.

window.Parsley.setLocale('fr');

Un peu de lecture

BackboneJS : écouter le router au chargement de l’application

Dans une application BackboneJS, si vous avez besoin d’écouter l’événement route déclenché par votre router, pensez à procéder dans le bon ordre :

// 1 - Instanciation du Router
App.router = new Router();

// 2 - Instanciation des écouteurs
App.menu = new MenuView(); // écoute l'événement "route" du router

// 3 - Démarrage de la navigation
App.history = Backbone.history.start();

Le router ne démarre pas au moment de son instanciation. En réalité, c’est l’historique qui démarre le router ( Backbone.history.start ).
Donc si vous lancez l’historique avant d’instancier vos écouteurs, vous n’écouterez pas l’événement route déclenché au chargement de votre application, mais seulement l’événement route déclenché aux changements de route, lors de la navigation des utilisateurs.

Nemo : rétablir la gestion des archives dans le menu contextuel

Nemo est le gestionnaire de fichier de l’environnement de bureau Cinnamon. Pour information, c’est un fork de Nautilus.

Il m’est arrivé de perdre les actions de gestion des fichiers d’archives dans le menu contextuel (affiché au clic droit) en désinstallant Nautilus. Ces actions sont quand même bien pratiques pour extraire ou créer des archives rapidement. Voici comment les remettre en service.

1 – Vérifiez que vous avez installé les paquets « File Roller » et « Nemo File Roller » :

sudo apt-get install file-roller
sudo apt-get install nemo-fileroller

2 – Rendez-vous dans le dossier « ~/.local/share/nemo/actions/ » :

cd ~/.local/share/nemo/actions/

3 – Créez le fichier « compress.nemo_action », collez-lui le contenu ci-dessous puis sauvegardez-le :

[Nemo Action]
Active=true
Name=Compress...
Comment=compress %N
Exec=file-roller -d %F
Icon-Name=gnome-mime-application-x-compress
Selection=Any
Extensions=any;
Quote=double

4 – Créez le fichier « extracthere.nemo_action », collez-lui le contenu ci-dessous puis sauvegardez-le :

[Nemo Action]
Active=true
Name=Extract here
Comment=Extract here
Exec=file-roller -h %F
Icon-Name=gnome-mime-application-x-compress
Selection=Any
Extensions=zip;7z;ar;cbz;cpio;exe;iso;jar;tar;tar;7z;tar.Z;tar.bz2;tar.gz;tar.lz;tar.lzma;tar.xz;tgz;
Quote=double

5 – Créez le fichier « extractto.nemo_action », collez-lui le contenu ci-dessous puis sauvegardez-le :

[Nemo Action]
Active=true
Name=Extract to...
Comment=Extract to...
Exec=file-roller -f %F
Icon-Name=gnome-mime-application-x-compress
Selection=any
Extensions=zip;7z;ar;cbz;cpio;exe;iso;jar;tar;tar;7z;tar.Z;tar.bz2;tar.gz;tar.lz;tar.lzma;tar.xz;tgz;
Quote=double

C’est fini ! Vous devriez avoir 3 nouvelles actions dans le menu contextuel de Nemo. Si ce n’est pas le cas, redémarrez votre session.

Sources

 

MySQL : obtenir la taille des bases de données en ligne de commande

Requête

SELECT table_schema AS "Database name", SUM(data_length + index_length) / 1024 / 1024 AS "Size (MB)"
FROM information_schema.TABLES
GROUP BY table_schema

Résultat

+--------------------+--------------+
| Database name      | Size (MB)    |
+--------------------+--------------+
| database 1         | 607.70312500 |
| database 2         | 647.92187500 |
| information_schema |   0.00878906 |
| database 3         | 417.16526890 |
| database 4         | 567.17187500 |
+--------------------+--------------+