web-dev-qa-db-fra.com

Comment et où appliquer la protection XSS à Laravel?

Je me demande comment (le cas échéant) la protection XSS est fournie à Laravel. Je n'ai rien trouvé à ce sujet dans la documentation.

Problème

J'utilise la méthode Eloquent _create() pour insérer des données dans la base de données (les propriétés $fillable$guarded sont définies dans les modèles). Il se trouve que je peux librement mettre quelque chose comme ceci dans la saisie de texte de n'importe quel formulaire:

<script>alert('Hacking Sony in 3...2...')</script>

et la valeur sera insérée dans la base de données. Ensuite, lorsque echoing it - l'alerte est affichée.

_/ Solutions possibles

Maintenant, Laravel est un framework vraiment agréable, donc je suppose que doit avoir quelque chose pour empêcher XSS de sortir de la boîte. Cependant, je ne peux pas savoir ce que c'est.

Si je me trompe, quel est le moyen optimal de gérer le problème?

  • Est-ce que j'utilise une validation regex sophistiquée pour interdire des caractères spécifiques?
  • Est-ce que j'utilise mysql_real_escape_string() sur chaque Input::get() que j'utilise?
  • Est-ce que je strip_tags()?

L'échappement au niveau de la vue n'est pas suffisant

Je sais que je peux utiliser les triples accolades de Blade pour échapper des chaînes dans les vues, mais ce n'est pas le problème. Cela me semble beaucoup plus logique de ne pas laisser ces bâtards sournois dans la base de données en premier lieu.

Quelqu'un a déjà fait face à ce problème?

11
lesssugar

Cela me semble beaucoup plus logique de ne pas laisser ces bâtards sournois dans la base de données en premier lieu.

En fait, ce n'est pas vrai. 

La raison pour laquelle XSS est uniquement gérée par la lame est que les attaques XSS sont un problème de output. Il n'y a pas de risque de sécurité si vous stockez <script>alert('Hacking Sony in 3...2...')</script> dans votre base de données - il ne s'agit que de texte - cela ne veut rien dire.

Mais dans le contexte de la sortie HTML - le texte a alors une signification, et c'est donc à cet endroit que le filtrage doit avoir lieu.

En outre, il est possible que l'attaque XSS soit une attaque réfléchie dans laquelle les données affichées ne proviennent pas de la base de données, mais d'une autre source. c'est-à-dire un fichier téléchargé, une URL, etc. Si vous ne parvenez pas à filtrer tous les emplacements d'entrée, vous risquez de manquer quelque chose.

Laravel vous encourage à échapper à la sortie all, quelle que soit son origine. Vous ne devez afficher explicitement les données non filtrées que pour une raison spécifique - et uniquement si vous êtes certain que les données proviennent d'une source fiable (c'est-à-dire de votre propre code, jamais de la saisie de l'utilisateur).

p.s. Dans Laravel 5, le {{ }} par défaut échappera à toutes les sorties - ce qui en souligne l’importance.

Edit: voici une bonne discussion avec des points supplémentaires sur la raison pour laquelle vous devriez filtrer la sortie, pas la saisie: html/XSS échappe sur entrée vs sortie

28
Laurence

Autant que je sache, la position "officielle" de Laravel est la suivante: La meilleure pratique en matière de prévention XSS est d'échapper à output . Ainsi, {{{ }}}.

Vous pouvez compléter la sortie qui s'échappe par input assainissement avec Input::all(), strip_tags() et array_map():

$input = array_map('strip_tags', \Input::all());
5
bishop

J'ai examiné le code de protection Laravel {{{...}}} contre l'attaque xss. Il utilise simplement la fonction htmlentities() de la manière suivante: htmlentities('javascript:alert("xss")', ENT_QUOTES, 'UTF-8', false); Ceci vous protège contre xss uniquement si vous l'utilisez correctement signifie ne pas l'utiliser dans certaines balises HTML car cela entraînerait une attaque XSS. Par exemple:

$a = htmlentities('javascript:alert("xss")', ENT_QUOTES, 'UTF-8', false); 
echo '<a href="'.$a.'">link</a>';

Dans ce cas, il est vulnérable à xss.

3
Robert Apollo

Le paquet laravelgems/blade-escape étend Blade en ajoutant différentes stratégies/directives d'échappement - @text, @attr, @css, @js, @param

Exemple:

<style>
.userPrefix:before { content: "@css($content)"; }
</style>
<div>
    <label class="userPrefix">@text($label)</label>
    <input type="text" name="custom" value="@attr($value)"/>
</div>
<a href="/profile?u=@param($username)">Profile</a>
<button onclick="callMyFunction('@js($username)');">Validate</button>
<script>
    var username = "@js($username)";
</script>

Lisez leur fichier README . XSS est très difficile, il y a beaucoup de contextes et d’approches.

Page de test - http://laragems.com/package/blade-escape/test

2
Leonid Shumakov

Vous pouvez également filtrer les entrées avant validation, comme d’abord, créez /app/Common/Utility.php

<?php
namespace App\Common;
use Illuminate\Support\Facades\Input;

class Utility {
    public static function stripXSS()
    {
        $sanitized = static::cleanArray(Input::get());
        Input::merge($sanitized);
    }
    public static function cleanArray($array)
    {
        $result = array();
        foreach ($array as $key => $value) {
            $key = strip_tags($key);
            if (is_array($value)) {
                $result[$key] = static::cleanArray($value);
            } else {
                $result[$key] = trim(strip_tags($value)); // Remove trim() if you want to.
            }
       }
       return $result;
    }
}

Et utiliser dans votre contrôleur comme ça

use App\Common\Utility;
public function store()
{
    Utility::stripXSS();
    // Remaining Codes
}

Ce code va nettoyer votre entrée avant validation 

2
Balachandran
class XSSProtection
{
    /**
     * The following method loops through all request input and strips out all tags from
     * the request. This to ensure that users are unable to set ANY HTML within the form
     * submissions, but also cleans up input.
     *
     * @param Request $request
     * @param callable $next
     * @return mixed
     */
    public function handle(Request $request, \Closure $next)
    {
        if (!in_array(strtolower($request->method()), ['put', 'post'])) {
            return $next($request);
        }

        $input = $request->all();

        array_walk_recursive($input, function(&$input) {
            $input = strip_tags($input);
        });

        $request->merge($input);

        return $next($request);
    }
}
0
Carlos Sanchez