Assez souvent, je vois des développeurs Laravel utiliser $request->all()
dans les méthodes de contrôleur. C’est peut-être un problème de sécurité, laissez-moi vous montrer pourquoi.
Pourquoi $request->all() n’est pas sécurisé
Imaginons que vous ayez un formulaire d’inscription standard :
Ce formulaire est soumis à cette méthode de contrôleur :
public function store(StoreUserRequest $request) {
User::create($request->all());
return redirect()->route('dashboard');
}
Nous utilisons une classe Form Request avec validation, donc cela ne semble pas dangereux, n’est-ce pas ? Il devrait enregistrer le nom, l’e-mail et le mot de passe, n’est-ce pas ?
Avis: Je sais que le mot de passe doit être crypté, mais dans cet article, supposons que le cryptage est effectué ailleurs, comme dans Observer ou Mutator.
Maintenant, regardons le $fillable
tableau dans le modèle User.
class User extends Authenticatable
{
protected $fillable = [
'name',
'email',
'password',
'is_admin',
];
Regarde ça is_admin
colonne? Il est utilisé pour attribuer le rôle d’administrateur, et ce champ ne doit être rempli que par d’autres administrateurs, sous une autre forme que l’inscription, dans un panneau d’administration séparé.
Mais que se passe-t-il si j’essaie d’appeler cet enregistrement à soumettre en ajoutant un hidden
champ appelé is_admin
directement depuis mon navigateur, comme les outils de développement Chrome, en cliquant sur Inspecter ?
Devinez quoi : le is_admin
sera enregistré avec succès, et je réussirai à m’enregistrer en tant qu’administrateur, sans l’autorisation de personne.
Donc, pour “pirater” le système, tout ce dont j’aurais besoin est de deviner les champs non visuels de la base de données : il peut s’appeler is_admin
c’est possible role_id
juste role
, ou quoi que ce soit d’autre. Pas si difficile d’écrire un script pour automatiser l’essai de toutes les options possibles.
Cela se produit parce que $request->all()
ne filtre ni ne valide rien, c’est juste littéralement all()
.
Alors, que faire à la place ?
Option 1. Demande de formulaire et validé()
Si vous utilisez la classe Form Request pour la validation, vous avez la rules()
méthode ici:
class StoreUserRequest extends FormRequest
{
public function rules()
{
return [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'email', 'string', 'max:255'],
'password' => ['nullable', 'string', 'confirmed', 'min:8'],
];
}
}
Ensuite, dans le contrôleur, vous devez utiliser la requête filtré après cette validation. Pour cela, il suffit de remplacer $request->all()
avec $request->validated()
.
public function store(StoreUserRequest $request) {
User::create($request->validated());
return redirect()->route('dashboard');
}
Ainsi, il ne remplira que les champs qui sont présents dans le rules()
méthode.
Gardez à l’esprit que dans ce cas, vous devez ajouter tous les champs nécessaires dans le rules()
tableau, même s’il ne nécessite pas de validation spécifique, ajoutez-les simplement comme nullable
ou string
.
Option 2. $request->only()
Bien sûr, une autre option consiste à spécifier les champs exacts à utiliser. L’une des options consiste à utiliser $request->only()
:
public function store(StoreUserRequest $request) {
User::create($request->only('name', 'email', 'password'));
return redirect()->route('dashboard');
}
Option 3. Champ par champ
Enfin, la bonne vieille méthode de spécification champ par champ. Le code semble plus long, mais peut-être plus lisible, avec moins d’informations “cachées”.
public function store(StoreUserRequest $request) {
User::create([
'name' => $request->name,
'email' => $request->email,
'password' => $request->password,
]);
return redirect()->route('dashboard');
}
Les trois options ci-dessus sont valables, c’est juste votre préférence personnelle, qui peut également dépendre de la forme ou de la situation exacte. L’essentiel est de ne pas utiliser $request->all()
oubliez simplement l’existence de cette méthode, pour votre sécurité.