Développement
La sécurité du web passera-t-elle par vous ?
Cet article est la traduction de l'article Web Security: Are You Part Of The Problem? écrit par Chris Heilmann et initialement publié dans Smashing Magazine. La sécurité des sites web est un sujet des plus critiques, qui devrait concerner toute personne présente sur le web. Une sécurité défaillante conduit généralement à tout ce que nous haïssons sur le web : le spam, les virus, et l'usurpation d'identité, pour ne citer que ceux là. Le problème avec la sécurité sur le web, c'est qu'elle est aussi complexe à mettre en oeuvre qu'elle est importante. Je suis persuadé que certains d'entre-vous font déjà partie à votre insu d'un réseau de piratage informatique, ou que votre serveur envoie du spam sans que vous n'en sachiez rien. Votre adresse email et vos mots de passe ont été récupérés et revendus à des gens persuadés que vous avez besoin d'une nouvelle montre, d'un emprunt à bas taux ou d'un élongateur de pénis suédois à pompe. Le fait est que vous êtes partie intégrante du problème, sans même savoir ce que vous avez fait pour en arriver là. Il faut dire que les experts en sécurité n'aiment parler ni de ce qu'ils font, ni des causes aux problèmes ; ils peuvent également être particulièrement arrogants quand ils exposent leur point de vue. C'est le résultat de générations n'ayant pas pris la sécurité au sérieux, et n'ayant jamais pris les précautions minimum, comme ne pas utiliser "toto" ou "password" en guise de mot de passe. La faute en incombe également à tous ces didacticiels qui vous apprennent comment "faire un truc en cinq minutes", tout en négligeant les implications de leurs conseils. Si ça vous parait trop simple pour être vrai, ça l'est probablement. Le parfait exemple est cette application PHP utilisant un fichier pour le stockage des données, et vous demandant de donner les droits en écriture à tout le monde. C'est facile à mettre en place, mais cela signifie aussi que n'importe quel spammeur peut écrire dans ce fichier. Attention : ce dont nous allons parler dans cet article ne fera pas de vous un expert en sécurité, pas plus qu'acheter un couteau suisse ne fera de vous un as du crochetage ou acheter un fouet ne fera de vous un dompteur de lions. Mon but est de vous faire prendre conscience de l'importance de la sécurité, et peut-être de rendre ce charabia un peu moins incompréhensible à vos yeux. Quelques chiffres intéressants sur la sécurité web La société de sécurité Cenzic a publié un rapport détaillant les chiffres et tendances du premier semestre 2009. Un PDF de ce rapport est disponible, et les chiffres parlent d'eux-même. Les vulnérabilités les plus critiques étaient le path traversal, le cross-site scripting (XSS), le cross-site request forgery (CSRF) et les injections SQL. N'étaient pas mentionnées les nouvelles attaques comme le clickjacking ou le phishing. Vous serez confronté à toutes celles-ci dès lors que vous manipulez PHP, HTML, CSS ou Javascript. Vous courrez d'ailleurs des risques même si vous n'utilisez pas de PHP. Vous pouvez d'ailleurs être une ressource importante en termes de sécurité même si vous ne développez pas, rendant le web plus sûr en faisant en sorte que vos utilisateurs comprennent les problèmes de sécurité. Nous allons maintenant voir tout cela, et expliquer comment ça fonctionne. La première chose que vous devez savoir est comment fonctionnent les URIs. Les URIs, premières sources d'attaque d'un service web URIs: The Main Way To Attack A Web Service L'adresse de tout document (par exemple un fichier sur Internet) est défini par son Identifiant de Ressource Universel (URI). C'est ce que vous tapez dans la barre d'adresse de votre navigateur afin d'accéder à un document, et ce que vous embarquez dans du code afin de pointer vers ce même document. L'adresse de mon site, par exemple, est http://icant.co.uk, et le document que vous affichez en réalité dans votre navigateur est http://icant.co.uk/index.php (le serveur vous redirige automatiquement vers ce document). L'image du logo se trouve à l'URI http://icant.co.uk/iconslogo.png, et ma photo se trouve une sur machine totalement différente, à l'URI http://farm4.static.flickr.com/3172/3041842192_5b51468648.jpg. Le fait que vous accédiez à ces URI ne pose pas de problèmes. Cependant, certaines d'entre elles comportent des informations qui ne devraient pas être accessibles à tout le monde. Par exemple, le fichier /etc/password de votre serveur contient les informations de vos utilisateurs et leurs mots de passe. Il ne devrait donc pas être accessible sur Internet. Toutes les URI peuvent également contenir des paramètres. Ce sont des instructions que vous pouvez envoyer au script situé à cette URI, et qui sont ajoutés à cette URI avec le préfix ?, et séparés par des esperluettes. Si vous voulez chercher des chiots sur Google, vous utiliserez l'URI http://www.google.com/search?q=chiots, et si vous voulez chercher au-delà des 50 premiers résultats, vous utiliserez http://www.google.com/search?q=puppies&start=50. Ces paramètres ne sont normalement pas ajoutés par les utilisateurs finaux, mais viennent de l'interface du site. Si vous regardez dans le code source de la page d'accueil de Google et en supprimez le superflu, vous devriez voir : Ce formulaire envoie le contenu de tous ces champs à l'URI search, en les y ajoutant. Au final, cela donne : http://www.google.com/search?hl=en&source=hp&q=chiots&aq=f&oq=&aqi= quand vous validez le formulaire. Notez au passage que le paramètre btnG est absent, car j'ai utilisé la touche Enter afin de valider ce formulaire. Sur la page des résultats de votre recherche, vous pouvez voir les liens vers les liens de pagination (les 1, 2, 3... sous le logo Gooooooogle). Ces liens envoient très exactement vers la même URI, mais en y ajoutant le paramètre start. 5 Vous pouvez envoyer des paramètres à un script avec l'URI via les champs d'un formulaire, un lien, ou n'importe quel élément HTML contenant une URI : images, liens, frames, tout ce qui peut prendre l'attribut src ou href. Si un attaquant peut surcharger n'importe lequel d'entre eux, ou ajouter une nouvelle image à votre HTML sans que vous vous en rendiez compte, ils peuvent alors pointer vers leur propre URI et envoyer leurs propres paramètres. Faites toujours attention au contenu de vos paramètres, et à l'endroit vers lequel ils pointent, ce qui peut être le serveur d'un tiers (afin d'avoir du code supplémentaire), ou des éléments de votre serveur que vous ne voulez pas rendre publics. Différents types d'attaques ? Qu'est-ce que ça veut dire ? Commençons par étudier rapidement les différents éléments mentionnés dans le diagramme ci-dessus, afin de comprendre à quoi ils correspondent. SQL Injection Avec une attaque de type SQL injection, une personne mal intentionnée peut envoyer des commandes SQL à votre serveur via l'URI ou les champs du formulaire. On peut facilement s'en prévenir en nettoyant les données envoyées par les utilisateurs. En revanche, les négliger peut être fatal à votre site web, comme le montre ce XKCD : Le Cross-Site Scripting (XSS) Le XSS est sans doute la vulnérabilité la plus importante et le plus fréquemment rencontrée. Avec elle, une personne mal intentionnée peut injecter du Javascript dans votre document, en l'ajoutant à la fin de l'URI ou dans un des champs de votre formulaire. Admettons que vous vouliez être sympa en permettant à vos visiteurs de personnaliser certaines couleurs de votre page. Cela se fait facilement en PHP : #intro{ /* color is set by PHP */ color:; /* background is set by PHP */ background:; font-family:helvetica,arial,sans-serif; font-size:200%; padding:10px; } Cool intro block, customizable, too! Jusque là, tout va bien, et nous n'utilisons même pas de style inline! Si vous enregistrez ce ficher et l'appelez dans votre navigateur depuis votre serveur web, par exemple à l'URL http://example.com/test.php, vous obtiendrez le texte d'introduction en noir sur fond blanc. Les variables $_GET[] viennent des paramètres de l'URI, et comme nous n'en avons pas passés, rien ne bouge. Si vous voulez avoir du rouge ou du rose, vous pouvez faire : http://example.com/test.php?color=red&background=pink. Mais comme vous autorisez les variables à prendre n'importe quelle valeur, une personne mal avisée pourrait envoyer : http://example.com/test.php?color=green&background=alert(String.fromCharCode(88,83,83)) Cela fermerait le bloc de style prématurément et ajouterait un script au document. Dans cet exemple, tout ce que nous faisons est afficher le mot CSS, mais nous pourrions faire tout ce dont JavaScript est capable. Vous pouvez le voir dans la capture d'écran ci-dessous : Dès lors que vous serez parvenu à injecter du JavaScript, vous pourrez lire le contenu des cookies, ouvrir les formulaires demandant aux utilisateurs d'entrer leur mot de passe ou leur numéro de carte de crédit, exécuter des virus, ou des vers à télécharger... tout ça ! La raison en est que javascript n'est lié à aucun modèle de sécurité ; tous les scripts embarqués sur une page ont les mêmes droits, quelle que soit leur provenance. C'est un gros problème avec Javascript, sur lequel des gens brillants se sont attelés. Les failles XSS sont un problème très fréquent. Des sites comme XSSED.org dévoilent publiquement combien de sites y sont vulnérables : Le seul remède aux XSS est une paranoïa de tous les instants concernant ce qui vient des formulaires ou de l'URI. Vous devez également vous assurer que votre installation de PHP est configurée correctement, mais nous en reparlerons un peu plus tard. Path traversal Permettre de traverser l'arborescence des répertoires de votre serveur est une idée incroyablement stupide. Cela reviendrait à autoriser n'importe qui à faire la liste de vos répertoires, et à naviguer de l'un à l'autre. Cela donne accès à des répertoires contenant des informations sensibles à toute personne mal intentionnée, et de s'y amuser. La capture d'écran ci-dessous montre l'accès à la bases de données d'une sandwicherie, l'envoi d'un email depuis leur serveur et la lecture de leur historique de commandes : J'ai pu accéder à toutes ces données simplement en accédant à leur répertoire cgi-bin qui n'était pas protégé. Au lieu de me rendre sur http://example.com, je suis allé sur http://example.com/cgi-bin. Je savais que quelque chose n'allait pas dans leur super site en Flash quand j'ai cliqué sur un élément du menu. Ce dernier a ouvert une nouvelle fenêtre, qui pointait sur une URI du type : http://www.example.com/cgi/food_db/db.cgi?db=default&uid=default&Category=Sandwiches&Subcategory=Sandwiches&Product=Chicken%20and%20Bacon&Soup_size=&Drinks_milk_type=&ww=on&view_records=yes me donnant toutes les informations nécessaires pour m'amuser un peu. Rendre la structure de vos répertoires accessible à tous pose un autre problème : cette dernière peut être indexée par les outils de recherche qui deviennent alors des outils de hacking. En effet, le serveur crée une page avec pour titre le nom du répertoire, ce dernier étant indexé par Google. Vous pouvez chercher, par exemple, index of /ebooks, ou index of /photos afin de trouver des e-books ou des photos en ligne. Jetez donc un coup d'oeil à Google, a dream come true, qui en listait une bonne partie en 2003(!). Cette méthode fonctionnait bien mieux par le passé. Pas parce que les gens protègent mieux leurs serveurs web, mais parce que les spammers, qui offrent de faux produits illégaux, ont réalisé que les gens faisaient ce genre de recherches et on mis en place de faux répertoires de ce genre, afin d'optimiser leurs résultats dans les moteurs de recherche. Le Cross-Site Request Forgery Le Cross-site request forgery (CSRF) exploite les navigateurs qui autorisent les fonctionnalités à être appelées sans vérifier qu'un utilisateur réel les a lancées. Admettons que votre site web propose ce formulaire qui envoie des données à votre base de données en GET (ça ne devrait jamais arriver, NDT) : Name email Comment Les formulaires peuvent être envoyés de deux manières : GET ajoute tous les paramètres à l'URI, et ces derniers sont visibles dans la barre d'adresse de votre navigateur. Au contraire, POST les envoie sous le capot. Accessoirement, POST vous permet d'envoyer bien plus de données que GET. C'est évidemment très simplifié, mais c'est tout ce que vous avez besoin de savoir à ce stade. Si le script qui ajoute les informations dans votre base de données ne valide pas que le formulaire a bien été envoyé depuis votre serveur, je peux y ajouter une image simplement en faisant : N'importe quelle personne venant sur mon site web ajouterait alors un commentaire dans votre base de données. Je pourrais faire ça avec une image, un lien CSS, un script, ou n'importe quel élément autorisant l'utilisation d'une URI, et chargé dans le navigateur lors du rendu HTML. En CSS, cela pourrait être une image de fond. Les CSRF sont encore plus dangereuses quand vous êtes authentifié sur un site quelconque. Une image ouverte dans un autre onglet de votre navigateur pourrait valider un transfert d'argent, lire vos emails et les envoyer à quelqu'un d'autre, ou n'importe quelle autre saloperie du genre. Un exemple de CSRF très intéressant s'est produit en 2006, quand Google a publié son maintenant défunt Google Web Accelerator (GWA). L'idée était de pré charger les sites web liés au document en cours, afin d'accélérer votre parcours. Tout allait bien jusqu'au moment où vous vous retrouviez avec des lienrs de suppression du type :
Optimisez les performances de vos applications Ruby on Rails
Avec le passage de Google à son nouvel algorithme Caféine, la performance des sites web devient une problématique encore plus aiguë qu'elle pouvait l'être par le passé. Aux problématiques de confort de l'utilisateur, souvent laissée de côté au profit de l'esbroufe visuel vient s'ajouter celle du référencement, toujours plus vendeuse. Le framework Ruby on Rails dispose d'un nombre intéressant d'options afin de vous permettre d'améliorer vos performances sans nécessiter de modifications en profondeur des applications existantes. Ces optimisations spécifiques au framework viennent s'ajouter aux recommandations prodiguées sur des sites comme le blog Performances Web, ou permettre leur réalisation. Parmi elles, nous allons plus particulièrement nous intéresser à : Servir des fichiers statiques. Créer un serveur d'assets. Diminuer la quantité de fichiers servis. Mettre en place un système de cache statique La génération de pages dynamiques peut prendre beaucoup de temps, et être une grosse consommatrice de ressources serveur. Heureusement, Ruby on Rails supporte nativement la création de pages HTML statiques, qui seront ensuite servies par votre serveur web, sans qu'il soit besoin de faire appel au framework. Dans chacun des contrôleurs que vous souhaitez voir cachés, ajoutez simplement la directive caches_page, suivie de la liste des actions à cacher. caches_page :index, :show Pour une utilisation plus fine de caches_page, je vous recommande également la lecture de Comprendre et améliorer le cache statique de vos applications Rails Mise en place d'un serveur d'assets Ruby On Rails propose en standard des options assez avancées de gestion des assets, et notamment des fichiers images, Javascript et CSS. Il est facile de mettre ces optimisations en place sur une application existante sans pour autant devoir réécrire plus de quelques lignes de code, ce qui est bien, voir top. Pourquoi mettre en place des serveurs d'assets ? 1. Ils vous permettront de pallier la limite des 2 téléchargements simultanés sur un même hôte sur IE6. Les versions suivantes font à peine mieux. 2. Sur des applications à gros trafic, ils vous permettront de répartir la charge sur plusieurs machines. Le code ci-dessous est tiré de la documentation de ActionView::Helpers::AssetTagHelper. Éditez le fichier de configuration de l'environnement de production, soit config/environments/production.rb. Le plus simple est de définir un seul serveur d'assets : ActionController::Base.asset_host = "assets.example.com" Désormais, tous les assets appelés depuis les helpers Rails standards le seront depuis assets.example.com : image_tag('toto.jpg') # appelle http://assets.example.com/images/toto.jpg stylesheet_link_tag('style') # appellera http://assets.example.com/stylesheets/style.css javascript_include_tag('toto.js') # appellera http://assets.example.com/javascripts/toto.js Il est également possible de mettre en place une architecture un peu plus sophistiquée, avec de la répartition de charge ou de la répartition par type (ou les deux). Cependant, cette méthode n'est pas compatible avec la mise en place d'un cache statique. Ici, vous allez choisir au hasard entre 4 serveurs d'assets, numérotés de 1 à 4 : ActionController::Base.asset_host = Proc.new { |source| "http://assets#{rand(4) + 1}.example.com" } Enfin, vous allez servir les images depuis une source, et les autres fichiers depuis une autre : ActionController::Base.asset_host = Proc.new { |source| if source.starts_with?('/images') "http://images.example.com" else "http://assets.example.com" end } Diminuer la quantité de fichiers servis Diminuer la quantité de fichiers servis fait partie des premières mesures à prendre quand on veut améliorer les performances de son site. Cela passe évidemment par la mise en place de sprites CSS, mais nous ne traiterons pas ce point car il ne relève pas directement de Ruby On Rails. Nous allons en revanche vois comment concaténer tous vos fichiers CSS d'une part, et Javascript d'autre part, afin de ne plus en servir qu'un de chaque. Là encore les helpers stylesheet_link_tag et javascript_include_tag gèrent cela très bien grâce à l'option :cache. Pour vos fichiers Javascript, vous avez le choix entre 2 syntaxes : Appeler les fichiers à assembler nominativement. javascript_include_tag 'toto.js', 'tata.js', 'tutu.js', :cache => true Appeler tous les fichiers Javascript disponibles d'un coup javascript_include_tag :all, :cache => true Et même le faire récursivement (fear!) : javascript_include_tag :all, :cache => true, :recursive: => true Et ça marche aussi pour les fichiers CSS : Appeler nominativement les fichiers CSS à inclure stylesheet_link_tag "toto.css", "tata.css", "tutu.css", :cache => true Appeler tous les fichiers CSS à inclure : stylesheet_link_tag :all, :cache => true Et même récursivement : stylesheet_link_tag :all, :cache => true, :recursive => true Elle n'est pas belle la vie ? Ah non, en fait, puisque toutes ces jolies méthodes ne réduisent pas la taille des fichiers avant de les envoyer, par exemple par obfuscation. Ça tombe bien, je ne suis personnellement pas super pour, ça a tendance à entraîner des erreurs. Votre serveur web doit en revanche envoyer les fichiers compressés, avec mod_gzip sous Apache 1.3 et mod_deflate sous Apache 2. Et voilà, c'est à peu près tout pour ce soir. J'espère que cette documentation vous aura été utile, au moins dans la mise en places des méthodes d'optimisation les plus évidentes, sans pour autant avoir à réinventer la roue, puisque votre framework favori le fait en standard, notamment grâce à quelques options mal connues de certains des helpers les plus utilisés. Comme quoi ça a du bon de lire le f$#@ manual de temps en temps.
Comprenez et améliorez le cache statique de vos applications Rails
Le framework de développement web Ruby on Rails offre, depuis sa toute première version, la possibilité de mettre en cache tout ou partie d'une page. Cela va du cache de fragments de page à la création d'un bon vieux fichier HTML statique. Pour les sites dont le contenu reste relativement stable, cette dernière méthode est particulièrement puissante : en effet, une fois votre cache généré, Apache, votre serveur web favori pourra y accéder directement sans faire appel à votre application Rails. Vous y gagnerez ainsi largement en termes de performances et d'économie de ressources.
10 raisons pour lesquelles les failles de sécurité des sites web ne sont jamais corrigées
En publiant tous mes bookmarks locaux en retard sur Diigo – dont je vous recommande chaudement l'usage aussi bien que la toute nouvelle interface – je suis tombé sur cet compilation des raisons pour lesquelles les vulnérabilités de sécurité des applications web ne sont jamais corrigées publiée par Jeremiah Grossman et augmentée par ses lecteurs. Je vous propose aujourd'hui une traduction en français d'excellentes excuses qui pourraient être drôles si elles n'étaient pas un facteur d'échec trop important pour faire de l'humour.
Le bug des labels implicites sous IE6 et 7
Je suis tombé ce week-end (je ne sais plus où, mais si vous trouvez, merci de me donner le lien) sur la description d'un bug sous IE 6/7 qui m'avait posé pas mal de problèmes à une époque, et je ne pense pas être le seul à l'avoir subi : la répétition du style des labels sur les input, qui se traduisait le plus notamment par un incompréhensible doublement des marges intérieures et extérieures. Ce symptôme se produit quand vous cherchez à imbriquer le label et l'input afin de faire du labeling implicite :
À quoi sert HTML5 si mes clients ne peuvent pas l'utiliser ?
Je discutais hier soir avec un ami développeur C++, récemment passé au web par nécessité, qui se lamentait à propos des nombreux défauts du couple HTML / CSS / Javascript, au premier rang desquels le positionnement, la difficulté d'avoir un rendu similaire sous tous les navigateurs, ou un Javascript qui ne fasse pas geler votre Internet Explorer à tous bouts de champs. Le développement système n'est pas exempt de problèmes – allocation mémoire, format string, limitation à une seule plate-forme, mais il est vrai qu'ils sont moins mystiques – au moins pour ceux qui en connaissent les arcanes.
Pour s'y retrouver entre HTML5 et XHTML5
XHTML2 est mort lâchement assassiné sur l'autel de la paresse par le groupe de travail sur HTML5. Ce fait étant acquis il ne vous reste plus le choix qu'entre HTML5 et... XHTML5. Si vous aussi avez l'impression de ne rien y comprendre, voici quelques points qui devraient vous aider à vous y retrouver dans toute cette jungle.
Un système de plugins avancé pour vos applications Rails
Disclaimer Ce qui va suivre est (probablement) très particulièrement sale. Il existe certainement d'autres manières beaucoup plus propre d'arriver au même résultat de manière simple, mais je ne les ai pas trouvées. Tout ce que vous pourrez lire par la suite a été écrit sous la menace des deux inséparables compagnes Grey Goose et Red Bull et la responsabilité ne saurait m'être imputée de quelque manière que ce soit. Enfin, petit rappel : ne le faite pas chez vous, à moins de savoir ce que vous faites. Ceci étant dit, passons aux choses sérieuses.
Le dernier sprint meeting d'Hitler, chef de produits agile
Beaucoup de projets informatiques connaissent un échec retentissant parce qu'à un moment clé, une des parties a eu un énorme coup de flemme et a choisi de contourner la difficulté... par exemple en désactivant le lancement des tests unitaires dans le processus d'intégration continue, histoire de ne pas avoir à réparer ceux qui plantent. C'est exactement ce qui arrive à Hitler, reconverti dans le rôle de chef de produit agile dans un énième détournement de la scène principale du film La Chute. À hurler de rire.
20 mauvaises pratiques de développement quand on développe avec Ruby on Rails
Le 30 mars, Chad Fowler a demandé sur Twitter Rails programmers: what's an example of one thing you find in other people's Rails code that you (almost) always consider to be wrong?. Les réponses ont fusé, donnant une liste de 20 mauvaises pratiques à destination des développeurs Ruby on Rails, mais également de tous ceux qui développent avec un framework MVC.
L'ergonomie web, l'utilisabilité et la qualité des logiciels sont trois grandes passions mises au services de ma profession.