33. La sécurité

Il est grand temps de s'occuper de nos failles de sécurité dans notre application

 

Mettre en place la sécurité

J'ai une bonne et une mauvaise nouvelle pour vous : la mauvaise, c'est qu'il faut sécuriser différentes routes de notre application, la bonne c'est qu'on sait déjà quelles routes on va devoir sécuriser... toutes celles qui mènent au BackController.

On va devoir vérifier que l'utilisateur soit connecté pour chacune de ces méthodes. Pour d'autres, on devra s'assurer aussi qu'il ait le rôle d'administration. 

On va créer deux méthodes qui vont vérifier les détails suivants : 

- si l'utilisateur n'est pas connecté, on le renvoie vers la page de connexion avec un message lui indiquant de se connecter

- s'il est connecté, on va vérifier son rôle : s'il n'est pas administrateur et essaie d'accéder à une page qui demande un rôle d'administration, on affichera un message lui indiquant qu'il n'a pas le droit d'accéder à cette page.

Ouvrez votre BackController et ajoutez ces deux nouvelles méthode checkLoggedIn et checkAdmin :

<?php

namespace App\src\controller;

use App\config\Parameter;

class BackController extends Controller
{
    private function checkLoggedIn()
    {
        if(!$this->session->get('pseudo')) {
            $this->session->set('need_login', 'Vous devez vous connecter pour accéder à cette page');
            header('Location: ../public/index.php?route=login');
        } else {
            return true;
        }
    }

    private function checkAdmin()
    {
        $this->checkLoggedIn();
        if(!($this->session->get('role') === 'admin')) {
            $this->session->set('not_admin', 'Vous n\'avez pas le droit d\'accéder à cette page');
            header('Location: ../public/index.php?route=profile');
        } else {
            return true;
        }
    }

    public function administration()
    {
        if($this->checkAdmin()) {
            $articles = $this->articleDAO->getArticles();
            $comments = $this->commentDAO->getFlagComments();
            $users = $this->userDAO->getUsers();

            return $this->view->render('administration', [
                'articles' => $articles,
                'comments' => $comments,
                'users' => $users
            ]);   
        }
    }

    public function addArticle(Parameter $post)
    {
        if($this->checkAdmin()) {
            if ($post->get('submit')) {
                $errors = $this->validation->validate($post, 'Article');
                if (!$errors) {
                    $this->articleDAO->addArticle($post, $this->session->get('id'));
                    $this->session->set('add_article', 'Le nouvel article a bien été ajouté');
                    header('Location: ../public/index.php?route=administration');
                }
                return $this->view->render('add_article', [
                    'post' => $post,
                    'errors' => $errors
                ]);
            }
            return $this->view->render('add_article');
        }
    }

    public function editArticle(Parameter $post, $articleId)
    {
        if($this->checkAdmin()) {
            $article = $this->articleDAO->getArticle($articleId);
            if ($post->get('submit')) {
                $errors = $this->validation->validate($post, 'Article');
                if (!$errors) {
                    $this->articleDAO->editArticle($post, $articleId, $this->session->get('id'));
                    $this->session->set('edit_article', 'L\' article a bien été modifié');
                    header('Location: ../public/index.php?route=administration');
                }
                return $this->view->render('edit_article', [
                    'post' => $post,
                    'errors' => $errors
                ]);

            }
            $post->set('id', $article->getId());
            $post->set('title', $article->getTitle());
            $post->set('content', $article->getContent());
            $post->set('author', $article->getAuthor());

            return $this->view->render('edit_article', [
                'post' => $post
            ]);
        }
    }

    public function deleteArticle($articleId)
    {
        if($this->checkAdmin()) {
            $this->articleDAO->deleteArticle($articleId);
            $this->session->set('delete_article', 'L\' article a bien été supprimé');
            header('Location: ../public/index.php?route=administration');
        }
    }

    public function unflagComment($commentId)
    {
        if($this->checkAdmin()) {
            $this->commentDAO->unflagComment($commentId);
            $this->session->set('unflag_comment', 'Le commentaire a bien été désignalé');
            header('Location: ../public/index.php?route=administration');
        }
    }

    public function deleteComment($commentId)
    {
        if($this->checkAdmin()) {
            $this->commentDAO->deleteComment($commentId);
            $this->session->set('delete_comment', 'Le commentaire a bien été supprimé');
            header('Location: ../public/index.php?route=administration');
        }
    }

    public function profile()
    {
        if($this->checkLoggedIn()) {
            return $this->view->render('profile');
        }
    }

    public function updatePassword(Parameter $post)
    {
        if($this->checkLoggedIn()) {
            if ($post->get('submit')) {
                $this->userDAO->updatePassword($post, $this->session->get('pseudo'));
                $this->session->set('update_password', 'Le mot de passe a été mis à jour');
                header('Location: ../public/index.php?route=profile');
            }
            return $this->view->render('update_password');
        }
    }

    public function logout()
    {
        if($this->checkLoggedIn())
        {
            $this->logoutOrDelete('logout');    
        }
    }

    public function deleteAccount()
    {
        if($this->checkLoggedIn())
        {
            $this->userDAO->deleteAccount($this->session->get('pseudo'));
            $this->logoutOrDelete('delete_account');   
        }
    }

    public function deleteUser($userId)
    {
        if($this->checkAdmin()) {
            $this->userDAO->deleteUser($userId);
            $this->session->set('delete_user', 'L\'utilisateur a bien été supprimé');
            header('Location: ../public/index.php?route=administration');
        }
    }

    private function logoutOrDelete($param)
    {
        $this->session->stop();
        $this->session->start();
        if($param === 'logout') {
            $this->session->set($param, 'À bientôt');
        } else {
            $this->session->set($param, 'Votre compte a bien été supprimé');
        }
        header('Location: ../public/index.php');
    }
}

On a ici trois modifications : 

- la méthode checkLoggedIn va vérifier que l'utilisateur est connecté, sinon, le redirigera vers la page de connexion 

- la méthode checkAdmin, qui fait appel à checkLoggedIn, et va ensuite vérifier que la personne connecté à le rôle admin. Si elle ne l'a pas, elle sera redirigée vers sa page de profil avec un message associé.

- les autres méthodes font appel à nos deux nouvelles méthodes (l'une ou l'autre) pour vérifier que l'on soit connecté (avec le rôle utilisateur) ou administrateur (avec le rôle admin), et nous laisser accéder à la route appelée si tout est bon, ou nous rediriger en conséquence.

Essayez maintenant de supprimer un administrateur en étant déconnecté ou avec un utilisateur classique, ça ne fonctionne pas 😉

 

Et hop, un espace d'administration sécurisé 😁

 

Est-ce qu'on en a fini avec la sécurité ? 

C'est une très bonne question et la réponse associée est... on en a jamais vraiment fini avec la sécurité.

Très régulièrement, de nouvelles failles sont exploitées pour essayer de pirater votre site.

Je vous invite à vous tenir à jour régulièrement des éventuelles failles de sécurité, je vous donne ici une liste de quelques failles connues dont vous devriez vous prémunir : 

- XSS

- SQL

- CSRF

- force brute

- variable de session

Il y en a de nombreuses autres, je vous invite à vous renseigner et vous tenir à jour sur le sujet.