Bonjour Ă tous,
J'espĂšre que vous avez passĂ© de belles fĂȘtes de fin d'annĂ©e et que vous ĂȘtes dâattaque pour 2023 !
Je suis ravie de vous prĂ©senter notre premiĂšre newsletter de l'annĂ©e đ
Aujourd'hui, je vais vous parler dâun sujet qui fait dĂ©bat chez nous : Comment renforcer vos sessions Devise contre les attaques par rejeu de session (session replay attack) ?
Bref, on parle cookie dans la newsletter biscuit đ đȘ
Lors d'un audit de sécurité récent, nous avons découvert que lorsqu'un utilisateur se déconnectait, son cookie de session restait actif, ce qui lui permettait de se reconnecter via son inspecteur.
Nous nous sommes donc penchĂ©s sur le sujet pour remĂ©dier Ă ce problĂšme sur lâensemble de nos plateformes.
IsmaĂ«l vous explique, Ă©tape par Ă©tape, le fonctionnement des sessions de Rails et comment Devise lâutilise. Il nous montre comment vĂ©rifier manuellement puis avec des tests unitaires si cette faille est prĂ©sente sur votre application avant dâexplorer deux solutions diffĂ©rentes pour y remĂ©dier.
Spoiler : le choix entre les deux solutions ne sera pas simple, chez nous, elles font encore dĂ©bat. đ
Je donne la parole à Ismaël :
Chez Capsens, nous sommes une agence spécialisée dans la Fintech et le Ruby on Rails. Nos clients sont principalement des plateformes d'investissement, des banques ou des startups qui manipulent des flux financiers ou des données sensibles.
Naturellement, la sécurité est donc une priorité pour nous. Nous sommes réguliÚrement audités par des experts de la cybersécurité.
Lors d'un de ces audits, un Ă©lĂ©ment intĂ©ressant nous a Ă©tĂ© remontĂ© : si un utilisateur se dĂ©connecte, son cookie de session est toujours actif, c'est Ă dire qu'on peut le rĂ©utiliser pour ĂȘtre connectĂ© en tant que cet utilisateur. Cela rendrait la plateforme vulnĂ©rable aux vols de sessions dans le cas oĂč l'utilisateur se connecterait via un ordinateur infectĂ© par un logiciel qui enregistrerait ses actions.
Nous utilisons systématiquement la gem Devise pour gérer l'authentification sur nos plateformes Ruby on Rails. Cette librairie existe depuis plus de 10 ans, a été installée presque 150 millions de fois sur sa derniÚre version et est utilisée par plus de 480 000 utilisateurs Github. C'est l'une des gems phare de la communauté Rails & Ruby avec ses 484 contributeurs.
L'idée de cette article est de s'intéresser aux raisons qui font que cette faille existe et de proposer une solution pour la combler.
Dans cet article, nous nous intéresserons à ce point précis du fonctionnement des sessions de Rails et comment Devise l'utilise pour gérer l'authentification. Comment reproduire cette faille via des tests unitaires avec Rspec, la comprendre et enfin comment la corriger avec Active Record Session Store.
Comprendre les sessions de Rails & Devise
Avant de s'y atteler, il est important de comprendre comment les sessions de Devise fonctionnent. Pour rappel, le but d'une session est de permettre d'identifier un client dans ses interactions avec le serveur.
Le fonctionnement classique de Rails, et du web en gĂ©nĂ©ral, est d'utiliser pour cela un cookie. Il s'agit d'un petit fichier texte stockĂ© sur le navigateur de l'utilisateur qui contient plusieurs couples clĂ©-valeur (xxxx=yyyy). Ce fichier est dĂ©posĂ© par le serveur et va ĂȘtre transmis avec chaque requĂȘte HTTP.
Exemple de cookie de session Rails :
session_id="23929"
expire_at="2023-01-01 20h30"
domain="localhost"
HttpOnly=true
Devise utilise ce systĂšme pour l'authentification. Lorsque l'utilisateur se connecte, il ajoute au cookie de session une clĂ© avec en valeur l'identifiant de l'utilisateur en base de donnĂ©es. Ainsi Ă chaque requĂȘte, il sait comment identifier l'utilisateur. Le systĂšme est sĂ©curisĂ© puisque la valeur du cookie de session est chiffrĂ©e et dĂ©chiffrĂ©e avec la SECRET_KEY_BASE
de votre application pour Ă©viter que quelqu'un ne puisse modifier son identifiant et ainsi s'authentifier en tant que quelqu'un d'autre.
Pour rĂ©sumer, lorsque l'utilisateur se connecte, Devise ajoute dans la session de l'utilisateur son identifiant en base de donnĂ©es. Ensuite Ă chaque requĂȘte, le serveur dĂ©chiffre le cookie de session et assigne donc current_user
à l'utilisateur en base de données qui correspond à cet identifiant.
Ce systÚme provient de Warden, un middleware Rack et qui va ajouter à la session un mécanisme d'authentification en injectant un objet dans l'environnement Rack à request.env['warden']
. Plus d'informations sur Warden disponibles Ă ce lien.
Afin de mieux comprendre, prenons un exemple concret. Je suis donc allĂ© mettre un breakpoint dans mon code grĂące Ă pry de maniĂšre Ă intercepter une requĂȘte authentifiĂ©e.
Je déchiffre alors le contenu de la session, plus particuliÚrement de la partie qui nous concerne :
$ pry(<AccountController>)> session
# =>
{
"warden.user.user.key" => [
[1],
"35VBDJgZO7F1sPfhvPJ57u"
],
# [...d'autres attributs (session_id, flashes, request...)],
}
On obtient une clé warden.user.user.key
qui contient une liste de deux valeurs :
Le
1
correspond à l'identifiant de mon utilisateur en base de données$2a$12$35VBDJgZO7F1sPfhvPJ57us
correspond aux 30 premiers caractĂšres duencrypted_password
de l'utilisateur.
Le deuxiÚme paramÚtre permet d'avoir un mécanisme pour invalider une session en cas de modification du mot de passe. Il est défini par la méthode authenticatable_salt
de Devise:
# devise/models/database_authenticatable.rb
# A reliable way to expose the salt regardless of the implementation.
def authenticatable_salt
encrypted_password[0,29] if encrypted_password
end
En cas de déconnexion, le serveur supprime simplement ce paramÚtre warden.user.user.key
du cookie de session du navigateur l'utilisateur.
Comprendre le problĂšme
Le problĂšme se situe au niveau de la dĂ©connexion. En effet, comme Ă©voquĂ©, la dĂ©connexion native proposĂ©e par Devise se rĂ©sume Ă rĂ©initialiser le cookie de session de l'utilisateur. Ainsi, si on suit la logique du fonctionnement, il suffit de rĂ©utiliser n'importe quel cookie de l'utilisateur, et celui-ci serait encore valide mĂȘme aprĂšs dĂ©connexion tant qu'il n'aura pas changĂ© de mot de passe. Essayons !
Je me connecte sur une application Rails avec une configuration Devise classique.
J'inspecte la valeur de mon cookie de session et je la copie
Le cookie de session s'appelle ici _doclift_session
et sa valeur est UgGIeMB2jbpOrtHOQsGq[...]2FmoSlrg1YBQ%2Bg%3D%3D
(mise de cÎté pour notre test).
Je me déconnecte
Je modifie la valeur de mon nouveau cookie de session pour remettre l'ancien
Via l'inspecteur, dans l'onglet Application â Cookie, je remplace la valeur de _doclift_session
par l'ancienne que j'avais mise de cÎté.
Je rafraichis la page, je suis connectĂ© đŁ
La session de l'utilisateur n'Ă©tant gĂ©rĂ© que via le cookie de session de Rails qui contient uniquement l'ID de l'utilisateur, aucun autre mĂ©canisme que le changement de mot de passe ne permet d'invalider dĂ©finitivement un cookie de session. MĂȘme si l'utilisateur s'est dĂ©connectĂ©, si le cookie a Ă©tĂ© interceptĂ©, alors il pourra ĂȘtre rĂ©utilisĂ©.
Tests unitaires
Avant de corriger le problĂšme, nous allons Ă©crire un test unitaire simple qui le reproduit afin de nous assurer facilement que notre solution le corrige bien.
Pour cela nous utiliserons des request_specs
de rspec :
rails g rspec:request users/sessions/delete
# => create spec/requests/users/sessions/delete_spec.rb
Nous souhaitons que notre test fasse ce que nous avons fait manuellement, c'est-Ă -dire rĂ©cupĂ©rer un cookie de session d'un utilisateur authentifiĂ©, puis se dĂ©connecter et remplacer son nouveau cookie de session par l'ancien : le rĂ©sultat attendu est de ne pas ĂȘtre connectĂ©.
# spec/requests/users/sessions/delete_spec.rb
require "rails_helper"
RSpec.describe "POST Users::Sessions#delete", type: :request do
let(:user) { create(:user) } # FactoryBot
subject(:perform_log_out_request) { delete(destroy_user_session_path) }
before do
sign_in(user)
# la requĂȘte est necessaire pour que la session
# soit créée et son cookie déposé
get(root_path)
end
context "when user signs out" do
it "deletes user_session" do
expect {
perform_log_out_request
}.to change {
session["warden.user.user.key"]&.dig(0, 0)
}.from(user.id).to(nil)
end
it "has invalidated previous session" do
previous_cookie = cookies[:_doclift_session]
perform_log_out_request
cookies[:_doclift_session] = previous_cookie
get(root_path)
expect(response).to redirect_to(
new_user_session_path
)
end
end
end
Lorsque l'on exĂ©cute les tests, on constate bien que le dernier Ă©choue, le cookie de l'utilisateur est toujours valide mĂȘme aprĂšs sa dĂ©connexion :
$ rspec spec/requests/users/sessions/delete_spec.rb
.F
Failures:
1) POST Users::Sessions#delete when user signs out has invalidated previous session
Failure/Error: expect(response).to redirect_to(new_user_session_path)
Expected response to be a <3XX: redirect>, but was a <200: OK>
# ./spec/requests/users/sessions/delete_spec.rb:21:in `block (3 levels) in <top (required)>'
Stocker la session cÎté serveur : Active Record Session Store
Active Record Session Store est une gem qui a était d'abord incluse directement dans Rails puis proposée sous la forme d'une gem externe. Il permet de stocker la session non plus cÎté client mais directement en base de données, donc cÎté serveur.
Les avantages d'utiliser une telle solution sont multiples :
Réduit fortement le risque de cookie overflow, c'est-à -dire de dépasser la taille maximum (4 Ko) autorisée par les navigateur lorsque l'on tente de stocker une trop grande quantité d'informations dans la DB.
Permet de garder un contrÎle total des sessions : les sessions étant en base de données, on peut facilement imaginer un systÚme qui permet de révoquer une session lorsque le besoin se présente.
Permet d'Ă©viter de stocker cĂŽtĂ© client des informations potentiellement sensibles (mĂȘme s'il est fortement recommandĂ© d'Ă©viter de stocker des informations sensibles dans la session).
RĂ©duit la taille rĂ©seau de chaque requĂȘte puisqu'on n'a plus besoin de transfĂ©rer toutes les informations de la session Ă chaque requĂȘte, elles peuvent rester cĂŽtĂ© serveur.
Cette solution présente également des inconvénients :
Cela implique d'ajouter une nouvelle dépendance (lié à une fonctionnalité coeur) à son application et son lot de problÚme que cela engendre.
Lorsque une application cherche Ă scaler, elle tend Ă rĂ©duire le nombre de requĂȘtes Ă la base de donnĂ©es dĂ©s que c'est possible. La session cĂŽtĂ© client est une bonne solution pour Ă©conomiser de nombreuses requĂȘtes en lecture et Ă©criture.
Depuis Rails 6, il est plus facilement possible de connecter plusieurs bases de donnĂ©es Ă son application notamment pour sĂ©parer les requĂȘtes de lecture des requĂȘtes en Ă©critures (plus lentes). Active Record Session Store complique ce genre de pratiques puisqu'il serait plus complexe de faire la sĂ©paration entre les requĂȘtes qui impliquent de l'Ă©criture des autres en se basant sur les verbes HTTP (GET, POST, PUT ...)
Ceci Ă©tant dit, la gem est trĂšs simple Ă mettre en place, il suffit de :
Ajouter la gem gem 'activerecord-session_store'
Ă son Gemfile & bundle exec install
puis lancer la commande rails generate active_record:session_migration
qui crée la migration suivante :
# db/migrate/20230116171912_add_sessions_table.rb
class AddSessionsTable < ActiveRecord::Migration[7.0]
def change
create_table :sessions do |t|
t.string :session_id, null: false
t.text :data
t.timestamps
end
add_index :sessions, :session_id, :unique => true
add_index :sessions, :updated_at
end
end
La migration va donc créer une table sessions
composée de 4 champs :
un champ string unique
session_id
avec un index qui va servir Ă stocker l'identifiant de la sessionun champ text
data
qui contiendra le contenu de la session utilisateurles 2 timestamps
created_at
&updated_at
Lançons cette migration avec rake db:migrate
.
Il nous reste plus qu'Ă indiquer Ă Rails que l'on souhaite utiliser active_record_store
plutĂŽt que cookie_store
en modifiant ou créant le fichier config/initializers/session_store.rb
:
# config/initializers/session_store.rb
Rails.application.config.session_store(
:active_record_store,
key: "_doclift_session",
)
Lançons les tests pour vérifier que l'on corrige bien notre faille de sécurité :
rspec spec/requests/users/sessions/delete_spec.rb
..
Finished in 2.11 seconds (files took 1.11 seconds to load)
2 examples, 0 failures
Le correctif corrige bien le problĂšme ... mais comment ?
Intéressons-nous un peu plus en détail à ce qu'il se passe.
Active Record Session Store utilise sans surprise également un cookie mais il y a deux différences majeures :
Sa taille est significativement réduite : 48 bytes contre 488 bytes avec le cookie_store
Sa valeur est beaucoup plus courte, en effet, ici l'ID mesure seulement 32 caractĂšres
Ces deux différences s'expliquent par le fait que ce cookie ne sert qu'à lier le client à une session qui est cette fois stockée en base de données.
# console Rails
SESSION_CLASS = ActionDispatch::Session::ActiveRecordStore.session_class.freeze
$ SESSION_CLASS.last
=>
#<ActiveRecord::SessionStore::Session:0x000000010f145db0
id: 26,
session_id: "2::d92dd021553fb0826be17dbc6bf1e17f77b34bf5384f45b4517f6f8e187060ff",
data: "BAh7BkkiEF9jc3JmX3Rva2VuBjoGRUZJIjBoREZseTB3dGt4QXpHVWFodEd6\nRzE2Q2xGODhaamdIMzlIaXJGUE5YdXc4BjsARg==\n",
created_at: Mon, 16 Jan 2023 22:05:42.567198000 CET +01:00,
updated_at: Mon, 16 Jan 2023 22:05:42.579124000 CET +01:00
>
Ici le session_id
est différent de celui visible dans le cookie de l'utilisateur pour mitiger le risque d'attaque temporelle mais on peut relativement facilement le retrouver :
# console Rails
session_public_id = "7b0ef645ef6d6bbe468b01664bd11c44"
sid = Rack::Session::SessionId.new(session_public_id)
sid.private_id
# => "2::d92dd021553fb0826be17dbc6bf1e17f77b34bf5384f45b4517f6f8e187060ff"
Le champ data
est encodé avec Marshall en base64
mais la gem implémente des méthodes #load
& #dump
afin de pouvoir les lire et modifier facilement  :
# console Rails
SESSION_CLASS = ActionDispatch::Session::ActiveRecordStore.session_class.freeze
SESSION_CLASS.last.data
=> ActiveRecord::SessionStore::Session Load (0.7ms) SELECT "sessions".* FROM "sessions" ORDER BY "sessions"."id" DESC LIMIT $1 [["LIMIT", 1]]
{
"_csrf_token" => "hDFly0wtkxAzGUahtGzG16ClF88ZjgH39HirFPNXuw8",
"user_return_to" => "/"
}
Tant que l'utilisateur n'est pas connecté, il n'a pas de clé warden.user.user.key
en revanche on peut retrouver les éléments classiques que contiennent une session tel que l'url de redirection aprÚs connexion.
Il est pertinent de faire remarquer qu'Ă chaque fois qu'un client effectue une requĂȘte Ă l'application, une session en base de donnĂ©es est crĂ©e pour lui si il n'en a pas dĂ©jĂ une. Cela signifie qu'un utilisateur malintentionnĂ© peut facilement crĂ©er des millions de lignes dans votre base de donnĂ©es avec un simple script qui fait une requĂȘte et supprime le cookie de session en boucle. Il est donc important de se protĂ©ger contre ce genre d'attaques avec un systĂšme de bannissement d'IP ou autre systĂšme de protection contre les bots (Cloudflare avec challenge avant d'accĂ©der au site par exemple).
Une fois l'utilisateur connectĂ©, sa session est augmentĂ©e avec les mĂȘmes informations que dans le cas d'une session cĂŽtĂ© client :
# console Rails
SESSION_CLASS = ActionDispatch::Session::ActiveRecordStore.session_class.freeze
def find_session_with_public_id(public_id)
rack_sid = Rack::Session::SessionId.new(public_id)
private_id = rack_sid.private_id
SESSION_CLASS.find_by_session_id(private_id)
end
$ session = find_session_with_public_id("eb7a620b9f947590bcd917e3a985f018")
$ session.data
# ActiveRecord::SessionStore::Session Load (0.5ms) SELECT "sessions".* FROM "sessions" ORDER BY "sessions"."id" DESC LIMIT $1 [["LIMIT", 1]]
# =>
{
"warden.user.user.key"=>[
[1],
"$2a$12$35VBDJgZO7F1sPfhvPJ57u"
],
"flash" => { ... }
}
En revanche, une fois que l'on se déconnecte, la session est supprimée de la base de données :
# console Rails
$ find_session_with_public_id("eb7a620b9f947590bcd917e3a985f018")
# ActiveRecord::SessionStore::Session Load (0.3ms) SELECT "sessions".* FROM "sessions" WHERE "sessions"."session_id" = $1 ORDER BY "sessions"."id" ASC LIMIT $2 [["session_id", "2::eb635a939ad94353db96019c812621cefd16d723b90794634411de35961d1b5b"], ["LIMIT", 1]]
=> nil
De maniĂšre gĂ©nĂ©rale, Ă chaque fois que la session a besoin d'ĂȘtre modifiĂ©e, elle est supprimĂ©e puis recrĂ©Ă©e :
# console Rails
$ SESSION_CLASS.ids
=> [32]
# On se connecte
$ SESSION_CLASS.ids
=> [33]
# On se déconnecte
$ SESSION_CLASS.ids
=> [34]
Pour conclure, Active Record Session Store nous apporte un moyen simple de se prémunir contre les attaques par rejeu de session aprÚs que l'utilisateur se soit déconnecté.
Ce systĂšme ne permet d'invalider facilement une session dans le cas oĂč le client (de cette session) ne se dĂ©connecterait pas. S'il a oubliĂ© de se dĂ©connecter de cet ordinateur, sa seule possibilitĂ© pour invalider immĂ©diatement toutes ses sessions est de changer son mot de passe, ce qui invaliderait son salt comme Ă©voquĂ© prĂ©cĂ©demment grĂące Ă la mĂ©thode authenticatable_salt
.
De plus, cette solution prĂ©sente tout de mĂȘme des dĂ©fauts non nĂ©gligeables :
elle implique d'avoir un systÚme pour purger périodiquement les sessions obsolÚtes sinon vous vous retrouvez avec des millions de sessions inutiles en bases de données
elle complexifie Ă©normĂ©ment le scaling de votre application en rendant trĂšs fastidieuse la sĂ©paration des requĂȘtes en lecture et en Ă©criture
elle sollicite la base de donnĂ©es Ă chaque requĂȘte avec une grande partie de requĂȘte en Ă©criture
elle rend (plus) vulnérable aux attaques DDOS
Pour ces raisons, le choix de Rails de déprécier et d'externaliser cette solution est compréhensible. Il serait donc intéressant d'explorer une autre solution.
Corriger le problĂšme avec authenticatable_salt
# devise/models/database_authenticatable.rb
# A reliable way to expose the salt regardless of the implementation.
def authenticatable_salt
encrypted_password[0,29] if encrypted_password
end
Comme évoqué précédemment, cette méthode permet d'invalider une session lorsque l'utilisateur change de mot de passe. Nous pourrions donc augmenter sa logique pour ajouter un second paramÚtre qui permettrait de faire changer ce salt en cas de déconnexion.
Nous allons donc ajouter un token stocké sur la table de l'utilisateur qui sera regeneré à chaque fois que l'utilisateur se déconnecte et ajouter ce token à la méthode authenticatable_salt
.
Créons donc une migration pour ajouter session_token
Ă la table users :
class AddSessionTokenToUsers < ActiveRecord::Migration[7.0]
def change
add_column(
:users,
:session_token,
:text,
default: -> { "md5((random())::text)" },
null: false,
)
add_index :users, :session_token
end
end
La migration ci-dessus ajoute un champ texte session_token
sur la table utilisateur et lui assigne une valeur par défaut aléatoire de type md5 (exemple : 314809aaf64aa80d35e117ae1111ee82
) différente (sans garantie d'unicité) pour chaque ligne en base de données.
Pour que la solution soit fonctionnelle, il reste encore à modifier ce token à chaque fois que l'utilisateur se déconnecte. Pour cela il suffit de modifier la méthode de déconnexion de Devise et donc overrider le controller de sessions :
# On génére le controller SessionsController
# dans le scope "users"
$ rails g devise:controllers users -c sessions
# => create app/controllers/users/sessions_controller.rb
Puis ensuite on spĂ©cifie Ă Rails oĂč chercher le controller pour les routes de sessions :
# config/routes.rb
Rails.application.routes.draw do
devise_for :users,
controllers: {
sessions: "users/sessions",
}
# [...]
end
On modifie alors le SessionsController
que l'on vient de créer pour overrider la méthode de déconnexion afin qu'elle regenÚre le token stocké dans session_token
# app/controllers/users/sessions_controller.rb
class Users::SessionsController < Devise::SessionsController
# [...]
# DELETE /resource/sign_out
def destroy
current_user.invalidate_all_sessions
super
end
end
Enfin on crée la méthode invalidate_all_sessions
et on override la méthode authenticatable_salt
sur le modĂšle utilisateur :
# app/models/user.rb
class User < ApplicationRecord
# [...]
def authenticatable_salt
"#{super}#{session_token}"
end
def invalidate_all_sessions
self.update_column :session_token, SecureRandom.hex(8)
end
end
Désormais à chaque déconnexion, le salt sera mis à jour ce qui implique d'invalider tous les anciens cookies de session.
Vous n'avez pas besoin de définir une valeur trop élevée pour ce session_token
, en effet, il sert ici uniquement de salt, c'est Ă dire que mĂȘme si par hasard deux utilisateurs venaient Ă avoir le mĂȘme token, cela ne serait pas gĂȘnant puisqu'ils n'auront pas pour autant le mĂȘme ID en base de donnĂ©es.
Vérifions que notre correctif permet bien d'invalider le cookie de session de l'utilisateur en cas de déconnexion :
$ rspec spec/requests/users/sessions/delete_spec.rb
..
Finished in 2.11 seconds (files took 1.12 seconds to load)
2 examples, 0 failures
Si votre application contient un dispositif permettant à vos administrateurs de se connecter en tant qu'un utilisateur, il conviendrait alors de ne pas réinitialiser le token de l'user en cas de déconnexion de l'administrateur sinon celui-ci se retrouverait déconnecté alors qu'il est potentiellement en train de naviguer sur le site.
Cette solution a été proposée initialement par Natalie Zeumann dans son article Devise: Invalidating all sessions for a user.
De là , on peut donc trÚs facilement utiliser notre méthode user.invalidate_all_sessions
pour permettre à un administrateur d'invalider immédiatement les sessions pour un utilisateur donné sans avoir besoin de lui demander de changer de mot de passe. Notez que cette solution est également compatible avec Active Record Session Store afin de permettre de s'assurer que toutes les sessions sont bien purgées lorsque l'utilisateur se déconnecte.
MĂȘme si elle est simple Ă mettre en place, cette solution prĂ©sente un dĂ©faut non nĂ©gligeable, elle repose sur une mĂ©thode qui n'est pas exposĂ©e dans l'API publique de Devise. En d'autres termes, celle-ci peut ĂȘtre dĂ©prĂ©ciĂ©e Ă n'importe quel moment dans une future version de Devise.
D'autres solutions existent, nous explorerons notamment dans une prochaine lettre le stockage des sessions dans Redis.
Alors Ă vous de jouer maintenant, plus d'excuses pour laisser cette faille risquer de mettre en pĂ©ril les sessions de vos utilisateurs, vous avez toutes les clĂ©s en main. Dâailleurs, je serais curieuse de savoir laquelle vous avez choisie et pour quelles raisons, peut-ĂȘtre arriveriez vous Ă mettre tout le monde dâaccord !
En attendant, nous nous penchons sur une troisiĂšme solution, jâespĂšre pouvoir vous en parler bientĂŽt ! đ
Toujours dans le thĂšme de la sĂ©curitĂ©, je souhaitais Ă©galement vous partager cet article qui liste les principales en-tĂȘtes de sĂ©curitĂ© que vous pouvez utiliser pour protĂ©ger vos sites Web.
Cet article nous a récemment été partagé par Robert sur notre canal #technique_links
. Câest un canal Slack que nous utilisons au quotidien pour se partager des articles intĂ©ressants et pour dĂ©battre de sujets techniques (notre passe-temps prĂ©fĂ©rĂ©).
Bonne fin de semaine Ă tous et Ă la semaine prochaine !
MĂ©lanie
Merci pour cet article qui rentre dans le détail des sessions, super intéressant, ça me fait reréfléchir au sujet et comparer avec ma base de code !
Stocker les sessions en dehors d'un cookie comme c'est fait là ça permets Ă©galement en tant qu'admin d'avoir un moyen de forcer la dĂ©connexion de quelqu'un, ce qui peut ĂȘtre parfois utile.
Quelques autres pistes et questions qui me passent en tĂȘte :
- est-ce quâActiveRecord Session Store permets de supprimer les sessions de quelqu'un dans la base au moment d'une dĂ©connexion, directement ?
- utiliser une date comme salt (par exemple `disconnected_at`), ça pourrait donner une information potentiellement plus « intéressante » qu'un md5, j'ai l'impression ?
- on peut Ă©galement utiliser Redis pour stocker les sessions et ainsi palier aux dĂ©fauts de sĂ©paration des requĂȘtes, augmentation des requĂȘtes, et simplifie la purge pĂ©riodique