Securiser une application Rails : un tutoriel approfondi
Pourquoi Securiser une application Rails ?
Securer une application Rails est essentiel pour prévenir les attaques et protéger l'information des utilisateurs. Dans un monde où la sécurité est devenue une priorité, même une petite faille peut avoir des conséquences graves.
Un cas d'usage concret : Imaginez que vous développez un site e-commerce qui collecte des informations personnelles et financières des clients. Une faille de sécurité pourrait permettre aux pirates informatiques d'accéder à ces données sensibles, entraînant des dommages financiers, une perte de confiance de vos clients et même des poursuites judiciaires.
Prerequis
- Connaissances en Ruby et Rails
- Familiarité avec les bases de données SQL
- Compréhension du concept d'authentification et d'autorisation
- Installation de Ruby, Rails, PostgreSQL (ou une autre base de données SQL)
- Installation de Git pour le versionnement du code
Concepts fondamentaux
1. Authentification et Autorisation
Authentification est la vérification des identités des utilisateurs. Il s'agit de savoir qui est quelqu'un.
Autorisation est la détermination des actions qu'un utilisateur peut effectuer sur l'application. Par exemple, un utilisateur normal ne devrait pas avoir accès à certaines fonctionnalités réservées aux administrateurs.
## app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
log_in user
flash[:success] = 'Connexion réussie'
redirect_to root_url
else
flash.now[:danger] = 'Identifiants invalides'
render 'new'
end
end
def destroy
log_out if logged_in?
flash[:success] = 'Déconnexion réussie'
redirect_to root_url
end
end
2. Hashing des mots de passe
Le mot de passe d'un utilisateur ne devrait jamais être stocké en clair dans la base de données. C'est pourquoi nous utilisons un algorithme de hachage pour stocker les mots de passe.
## app/models/user.rb
class User < ApplicationRecord
has_secure_password
end
3. Cookies sécurisés
Les cookies doivent être sécurisés pour éviter que des attaques comme le man-in-the-middle ne puissent accéder aux informations stockées.
## config/initializers/session_store.rb
Rails.application.config.session_store :cookie_store, key: '_your_app_session', expire_after: 90.minutes, secure: Rails.env.production?
4. Protection contre les Cross-Site Scripting (XSS)
L'XSS est une attaque où un attaquant injecte du code malveillant dans une page web pour être exécuté par d'autres utilisateurs.
<%= sanitize @comment.content %>
5. Protection contre les Cross-Site Request Forgery (CSRF)
Le CSRF est une attaque où un attaquant force l'utilisateur à effectuer des actions non voulues sur votre site web.
## app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
end
6. Gestion des erreurs
Il est important de gérer les erreurs avec prudence pour éviter des informations sensibles d'être révélées aux utilisateurs.
## app/controllers/users_controller.rb
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
rescue ActiveRecord::RecordNotFound
flash[:danger] = 'Utilisateur non trouvé'
redirect_to root_url
end
end
Mise en pratique : projet fil rouge
Mini-projet : Gestionnaire de tâches
Créer un nouveau projet Rails
rails new task_manager -d postgresql cd task_managerGénérer le modèle User
rails generate model User name:string email:string password_digest:password rake db:migrateGénérer le contrôleur Sessions
rails generate controller Sessions new create destroyAjouter les routes pour les sessions
# config/routes.rb resources :sessions, only: [:new, :create, :destroy] get 'logout', to: 'sessions#destroy'Implémenter l'authentification
# app/controllers/sessions_controller.rb class SessionsController < ApplicationController def new; end def create user = User.find_by(email: params[:session][:email].downcase) if user && user.authenticate(params[:session][:password]) log_in user flash[:success] = 'Connexion réussie' redirect_to root_url else flash.now[:danger] = 'Identifiants invalides' render 'new' end end def destroy log_out if logged_in? flash[:success] = 'Déconnexion réussie' redirect_to root_url end private def user_params params.require(:user).permit(:email, :password) end endAjouter la vue pour les sessions
<!-- app/views/sessions/new.html.erb --> <%= form_for @session do |f| %> <div class="form-group"> <%= f.label :email %> <%= f.text_field :email, class: 'form-control' %> </div> <div class="form-group"> <%= f.label :password %> <%= f.password_field :password, class: 'form-control' %> </div> <div class="form-group"> <%= f.submit 'Connexion', class: 'btn btn-primary' %> </div> <% end %>Ajouter la vue pour les tâches
<!-- app/views/tasks/new.html.erb --> <%= form_for @task do |f| %> <div class="form-group"> <%= f.label :name %> <%= f.text_field :name, class: 'form-control' %> </div> <div class="form-group"> <%= f.submit 'Ajouter', class: 'btn btn-primary' %> </div> <% end %>Générer le modèle Task
rails generate model Task name:string description:text user_id:integer rake db:migrateAjouter la relation entre User et Task
# app/models/user.rb class User < ApplicationRecord has_secure_password has_many :tasks end # app/models/task.rb class Task < ApplicationRecord belongs_to :user endGénérer le contrôleur Tasks
rails generate controller Tasks new create index show edit update destroyAjouter les routes pour les tâches
# config/routes.rb resources :tasks, except: [:new, :edit]Implémenter l'index et le show des tâches
# app/controllers/tasks_controller.rb class TasksController < ApplicationController before_action :logged_in_user def index @tasks = current_user.tasks.order(created_at: :desc) end def show @task = current_user.tasks.find(params[:id]) rescue ActiveRecord::RecordNotFound flash[:danger] = 'Tâche non trouvée' redirect_to root_url end private def logged_in_user unless logged_in? store_location flash[:danger] = 'Veuillez vous connecter pour accéder à cette page.' redirect_to login_url end end endAjouter les vues pour l'index et le show des tâches
<!-- app/views/tasks/index.html.erb --> <h1>Mes tâches</h1> <ul> <% @tasks.each do |task| %> <li><%= task.name %> - <%= link_to 'Détails', task_path(task) %></li> <% end %> </ul> <%= link_to 'Nouvelle tâche', new_task_path %> erb <!-- app/views/tasks/show.html.erb --> <h1><%= @task.name %></h1> <p><%= @task.description %></p> <%= link_to 'Retour', tasks_path %>
Erreurs frequentes et debugging
1. ActionController::ParameterMissing
Cause : L'erreur se produit lorsqu'un paramètre est attendu mais pas présent dans la requête.
## ❌ Mauvais
def create
@task = Task.new(task_params)
end
## ✅ Correct
def create
@task = Task.new(task_params)
end
2. ActiveRecord::RecordNotFound
Cause : L'erreur se produit lorsqu'une ressource n'est pas trouvée dans la base de données.
## ❌ Mauvais
@user = User.find(params[:id])
## ✅ Correct
@user = User.find_by(id: params[:id])
3. ActionDispatch::Cookies::CookieOverflowError
Cause : L'erreur se produit lorsqu'un cookie dépasse la taille maximale autorisée.
## ❌ Mauvais
cookies[:big_cookie] = '...' * 1000
## ✅ Correct
session[:big_session] = '...' * 1000
Pour aller plus loin
1. Authentification avec OAuth2
Intégrez l'authentification avec des services tiers comme Google, Facebook ou GitHub pour une expérience utilisateur plus facile et sécurisée.
2. Sécurité de l'API
Protégez votre API contre les attaques courantes en utilisant des mécanismes comme JWT (JSON Web Tokens) et CORS (Cross-Origin Resource Sharing).
3. Sécurité des formulaires
Utilisez les helpers de Rails pour créer des formulaires sécurisés, en utilisant form_with et en vérifiant les paramètres avec strong_parameters.
## app/controllers/users_controller.rb
class UsersController < ApplicationController
def create
@user = User.new(user_params)
if @user.save
log_in @user
flash[:success] = 'Compte créé avec succès'
redirect_to @user
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
end
Défi pratique
Créez une application API RESTful pour gérer des utilisateurs et leurs tâches. Utilisez les gems jwt et cancancan pour la gestion des autorisations.
En suivant ce tutoriel, vous aurez une bonne compréhension de la sécurité en Rails et pourrez mettre en place des mesures efficaces pour protéger vos applications.