#204 XSS Protection in Rails 3
- Download:
- source codeProject Files in Zip (156 KB)
- mp4Full Size H.264 Video (11.8 MB)
- m4vSmaller H.264 Video (8.63 MB)
- webmFull Size VP8 Video (21 MB)
- ogvFull Size Theora Video (15.1 MB)
Dans l'épisode 27 [regarder, lire], nous avons vu le cross-site scripting. C'est un sujet important que tout développeur web doit comprendre. Un cas dans lequel un site est vulnérable aux attaques XSS est lorsque ce denier affiche des informations saisies par les utilisateurs. Il est donc important d'échapper toute information générée par un utilisateur lorsque celle-ci est affichée. Dans une application Rails, cette action est, en général, effectuée à l'aide de la méthode h
.
<%= h comment.content %>
Utilisation de la méthode h pour échapper les affichages
Dans Rails 3 cependant, les affichages sont automatiquement échappés, nul besoin donc d'utiliser la méthode h
dans vos vues. Dans cet épisode, nous allons vous montrer comment Rails 3 gère l'échappement des affichages.
Pour démontrer l'échappement des affichages, nous allons utiliser une simple application de blog écrite avec Rails 3. Dans cette application, nous avons des articles et chaque article a un certain nombre de commentaires. Pour voir comment le système de commentaire réagit à une tentative d'attaque XSS, nous allons saisir <script>alert('I steal cookies!')</script>
dans chaque champ du formulaire de commentaire et soumettre notre commentaire diabolique.
Lorsque nous ajoutons notre commentaire et qu'il est affiché sur la page, nous voyons que Rails 3 a automatiquement échappé les balises HTML dans les champs que nous avons soumis. Jetons maintenant un œil sur la façon dont Rails 3 réalise cet échappement.
Le code qui affiche chaque commentaire est contenu dans un partial et si l'on regarde le code, on peut constater qu'aucun affichage n'est échappé.
<div class="comment"> <strong><%= link_to comment.name, comment.url %></strong> <p><%= comment.content %></p> </div>
Avec Rails 2, cela aurait signifié que les messages d'alerte auraient été affichés, mais tous les affichages du partial sont échappés avec Rails 3, même lorsque nous les passons aux helpers comme link_to, nul besoin, donc, d'utiliser la méthode h ici.
Que se passe-t-il, par contre, si nous convertissons une application Rails 2 vers Rails 3 et que nous échappons nos sorties avec h
? Nous pouvons le découvrir en échappant les affichages dans le partial ci-dessous et en rechargeant la page.
<div class="comment"> <strong><%= link_to h(comment.name), comment.url %></strong> <p><%= h comment.content %></p> </div>
Lorsque nous rechargeons la page, nous pouvons voir qu'elle n'a pas changé et que les affichages n'ont pas été doublement échappés. Rails est malin ; même si nous utilisons la méthode h
il n'échappera les balises script qu'une seule fois.
Il pourrait sembler que la méthode h
ne fait juste rien en Rails 3 mais ce n'est pas le cas. Elle a toujours un but, nous vous le montrerons dans la suite. Mais avant, nous allons voir une fonctionnalité associée. Bien que ce soit une bonne chose que les affichages soient échappés automatiquement, il peut arriver que l'on ait besoin d'afficher le texte tel quel. Si nous avons confiance dans le contenu fourni par l'utilisateur, s'ils sont par exemple administrateurs, et que nous voulions afficher exactement ce qui a été saisi, nous pouvons utiliser la nouvelle méthode raw
.
<div class="comment"> <strong><%= link_to comment.name, comment.url %></strong> <p><%= raw comment.content %></p> </div>
Si nous rechargeons la page, le JavaScript que nous avons saisi est maintenant exécuté.
Donc, avec Rails 3, chaque fois où nous voulons afficher le contenu tel quel, non échappé, nous pouvons utiliser la méthode raw
. Mais comment cela fonctionne-t-il ? Rails 3 semble bien malin sur le fait d'échapper ou non. Nous allons voir comment tout cela fonctionne.
Nous allons démontrer l'échappement dans la console, que nous pouvons invoquer via la commande rails c
.
$ rails c Loading development environment (Rails 3.0.0.beta) ruby-1.9.1-p378 >
Rails 3 apporte un concept de chaines HTML-safe. Cela signifie que nous pouvons vérifier si une chaine peut être affichée sous forme HTML de manière sécurisée grâce à la méthode html_safe?
.
> "foo".html_safe? => false
Nous pouvons spécifier qu'une chaine est valide avec la méthode html_safe
.
> safe = "safe".html_safe => "safe" > safe.html_safe? => true
Aucun échappement n'est effectué ici. Tout ce qui est changé, c'est un booléen dans la chaine permettant de déterminer si un échappement doit être effectué ou non.
Comment cela s'applique-t-il dans nos vues ? Rails regarde chaque morceau d'affichage et vérifie s'il est HTML-safe. Pour ceux qui ne le sont pas, Rails va automatiquement les échapper au moment de leur affichage. Pour ceux qui le sont, ils sont simplement affichés tels quels. Si nous utilisons la méthode h
pour échapper une chaine, elle va procéder à l'échappement et marquer la chaine comme HTML-safe. Cela signifie que Rails 3 va voir que la chaine est sécurisée et ne va pas l'échapper à nouveau.
Lorsque la méthode raw
est utilisée sur une chaine, elle sera marquée comme sécurisée mais ne sera pas échappée, permettant à son contenu d'être passé en sortie sans être échappé.
Il est important de comprendre ceci quand vous utilisez des helpers. Nous allons l'expliquer en créant un helper appelé strong
qui entoure tout ce qui lui est passé dans des balises <strong>
. Nous l'utiliserons dans nos templates comme ceci :
<div class="comment"> <%= strong link_to(comment.name, comment.url) %> <p><%= raw comment.content %></p> </div>
Nous allons créer la méthode strong
dans ApplicationHelper
:
module ApplicationHelper def strong(content) "<strong>#{content}</strong>" end end
Lorsque nous rechargeons la page, nous pouvons voir que cela n'a pas marché comme nous nous y attendions.
L'échappement automatique de Rails 3 a échappé les balises <strong>
. Cela est dû au fait que notre helper ne crée pas une chaine sécurisée.
Il y a deux règles simples à suivre lorsque l'on crée un helper qui retourne du code HTML. Premièrement, nous devons nous assurer que que toute chaine retournée est marquée comme sécurisée.
module ApplicationHelper def strong(content) "<strong>#{content}</strong>".html_safe end end
Cela corrige le problème des balises <strong>
échappées mais en faisant cela, le contenu entre les balises ne sera pas échappé. Nous pouvons résoudre ce souci en échappant le contenu avec h
:
module ApplicationHelper def strong(content) "<strong>#{h(content)}</strong>".html_safe end end
De cette façon, tant que l'on oublie pas d'échapper toutes les saisies avec h
et que l'on marque la chaine résultante avec html_safe
, ce sera affiché correctement. Si nous rechargeons la page des commentaires, nous constatons que les balises <strong>
ne sont pas échappées mais que le deuxième commentaire, qui contient le JavaScript potentiellement dangereux, est échappé.
C'est tout pour cet épisode. L'échappement automatique est une addition bienvenue dans les vues de Rails 3. Cela rend inutile le besoin de se souvenir d'échapper tous les morceaux d'affichage avec h
. Cela réduit les risques que notre application soit victime de cross-site scripting.