Skip to content

Vérification systématique du type de session dans SessionNamespace#5933

Merged
francoisfreitag merged 2 commits into
masterfrom
ff/session-namespace-kind-2
Apr 15, 2025
Merged

Vérification systématique du type de session dans SessionNamespace#5933
francoisfreitag merged 2 commits into
masterfrom
ff/session-namespace-kind-2

Conversation

@francoisfreitag

@francoisfreitag francoisfreitag commented Apr 10, 2025

Copy link
Copy Markdown
Member

🤔 Pourquoi ?

Sécurité : détecter les pollutions de sessions par les utilisateurs et s’en prémunir. La session est un endroit supposé sûr, hors du contrôle des utilisateurs.

@francoisfreitag francoisfreitag added the no-changelog Ne doit pas figurer dans le journal des changements. label Apr 10, 2025
@francoisfreitag francoisfreitag self-assigned this Apr 10, 2025
@francoisfreitag francoisfreitag added tech and removed no-changelog Ne doit pas figurer dans le journal des changements. labels Apr 10, 2025
@francoisfreitag francoisfreitag changed the title Vérifier le type de session dans SessionNamespace Vérification systématique du type de session dans SessionNamespace Apr 10, 2025
@francoisfreitag francoisfreitag force-pushed the ff/session-namespace-kind-2 branch 4 times, most recently from 475a053 to f1de717 Compare April 10, 2025 12:24
@tonial

tonial commented Apr 10, 2025

Copy link
Copy Markdown
Contributor

Je t'ai ajouté à ma PR #5931
Vu que je touche aussi aux sessions, tu as l'air au point sur le sujet :)

@xavfernandez xavfernandez left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Comment thread itou/utils/session.py Outdated
Comment thread tests/utils/test.py
Comment thread itou/utils/session.py Outdated

@EwenKorr EwenKorr left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C'est élégant et plus générique en effet.

@dejafait dejafait self-requested a review April 10, 2025 13:21

@dejafait dejafait left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM et j'apprends plein de trucs sur notre mécanisme de session, merci 😊

Comment thread itou/utils/session.py Outdated
view.
"""
try:
session_kind = self._session[self.session_kind_key]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Un peu naïvement j'aurais plutôt mis ça en dessous de self._session[self.name] afin que tout soit contenu au même endroit mais ça veux dire devoir ajouter un niveau entre self._session[self.name] et data si on ne veux pas polluer 🤔.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

La transition m’a fait un peu peur, parce qu’il faudrait réécrire les sessions en cours. Et l’accès direct via request.session["name"] serait cassé (bien qu’il ne soit pas encouragé). J’ai trouvé que stocker les données à côté permettait de répondre au problème de manière moins invasive.

Comment thread itou/utils/session.py Outdated
Comment thread itou/utils/session.py
Comment thread itou/utils/session.py Outdated
session_kind = None
if session_kind is not None and session_kind != self.expected_session_kind:
logger.warning(f"Loading a {session_kind} while expecting a {self.expected_session_kind}.")
raise Http404

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pas sûr que Http404 soit la bonne exception, le type ne devrais pas être différent donc si on est dans ce cas alors c'est qu'il y a un loup et donc on veux un truc qui casse bien fort et pas être silencieux.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Http404 ne devrait se produire que si la session est corrompue (elle a un session_kind qui n’est pas l’attendu).
On peut mettre un erreur plus costaud pour Sentry.

Http404 n’est pas une super exception, mais permet de mutualiser le comportement actuel plutôt que de demander à chaque utilisateur de SessionNamespace de garder chaque lecture avec try: ... except SessionCorrupted: raise Http404.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pour moi on ne veux pas spécialement attraper l'erreur mais la laisser passer, pour moi on est dans la même logique que le token CSRF ou autre joyeuseté de ce type donc retourner une 404 me semble bizarre pour ce genre de truc.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dans un monde parfait, oui. C’est aux vues de décider quoi faire en cas d’erreur, et pas à un utilitaire de gestion de session.

Le problème est que l’erreur peut sortir à n’importe quel appel, parce que le SessionNamespace est initialisé paresseusement. Si SessionNamespace accédait immédiatement à la session, on pourrait ne garder que dans __init__() et demander aux appelant de gérer ce cas. Vu la multitude de méthode de l’API de SessionNamespace, une demander à l’appelant de garder chaque appel me semble se faire des nœuds au cerveau.

J’ai déjà pensé plein de fois à passer SessionNamespace en accès immédiat, mais c’est long et pénible, et les gains me semblent minimes.

Si on veut, on peut aussi définir une:

class SessionNamespaceCorrupted(Http404):
    pass

Ça permet aux vues « bonnes élèves » de gérer proprement le cas, et d’éviter la 500 sur les autres.

Comment thread itou/utils/session.py
Comment thread tests/utils/test.py
@francoisfreitag francoisfreitag force-pushed the ff/session-namespace-kind-2 branch 2 times, most recently from 8ed8f7b to da2657c Compare April 10, 2025 15:41
Comment thread itou/utils/session.py Outdated
Comment thread itou/utils/session.py
if session_kind is not None and session_kind != self.expected_session_kind:
logger.warning(f"Loading a {session_kind} while expecting a {self.expected_session_kind}.")
raise Http404
self.kind_verified = True

@francoisfreitag francoisfreitag Apr 14, 2025

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On marquera les sessions actives qui ne vérifiaient pas session_kind comme verified. C’est juste pour une semaine et pas bien pire que le comportement actuel.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On est d'accord que cela ne concerne que la session de candidature ?

@francoisfreitag

Copy link
Copy Markdown
Member Author

J’ai poussé un fixup pour les deux commentaires résolus :

  • Écrire kind_verified dans verify_kind().
  • Bouger le check if kind_verified: dans verify_kind.

@francoisfreitag

francoisfreitag commented Apr 14, 2025

Copy link
Copy Markdown
Member Author

Sans autre retour, je pense merger cette PR en l’état (après squash) demain. J’accorde très facilement des délais supplémentaires sur simple MP.

Comment thread itou/utils/session.py
if session_kind is not None and session_kind != self.expected_session_kind:
logger.warning(f"Loading a {session_kind} while expecting a {self.expected_session_kind}.")
raise Http404
self.kind_verified = True

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On est d'accord que cela ne concerne que la session de candidature ?

@rsebille rsebille left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Toujours circonspect d'utiliser http404 mais c'est ce que font les wizard actuellement donc soit 🤷.

Comment thread itou/utils/session.py Outdated
Will help land future changes, where more keys should be ignored
according with `.endswith()`.
Multiple forms on the site are quite long, and were split over multiple
pages, storing the intermediary data in the session. Data is only
written to the database at the end of the editing process.

In order to work well with tabs, the sessions are namespaced (usually
stored under a UUID at the root of the session), and the user passes the
namespace through the URL. Which means the user can read the UUID from
the URL, and try reusing a session from an editing process in other
views, allowing users to somewhat manipulate their session.

Although most processes are expected to fail when given data from
another editing process, it remains a security risk as developers cannot
reasonably keep track of the intersection of session data for all
editing processes on the site.

To protect against such issues, some views (subclasses of WizardView)
store a session_kind, and verify it when they load the user session.

Generalize the verification to all `SessionNamespace`, to force all
users of `SessionNamespace` to follow that pattern.
@francoisfreitag francoisfreitag force-pushed the ff/session-namespace-kind-2 branch from 294afce to 3d0e0f8 Compare April 14, 2025 15:21
@francoisfreitag francoisfreitag added this pull request to the merge queue Apr 15, 2025
Merged via the queue into master with commit 0a5b541 Apr 15, 2025
@francoisfreitag francoisfreitag deleted the ff/session-namespace-kind-2 branch April 15, 2025 07:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants