Skip to content

feat(security): store S3 keys as encrypted session cookie#12860

Draft
mekarpeles wants to merge 2 commits into
masterfrom
12856/s3-encrypted-session-cookie
Draft

feat(security): store S3 keys as encrypted session cookie#12860
mekarpeles wants to merge 2 commits into
masterfrom
12856/s3-encrypted-session-cookie

Conversation

@mekarpeles
Copy link
Copy Markdown
Member

Summary

Moves patron S3 (archive.org) key storage from the account store (plaintext at rest) to an encrypted, HttpOnly session cookie set at login time.

Closes #12856
Lead: @jimchamp

What changed

Login flow (accounts/model.py, plugins/upstream/account.py)

audit_accounts() now returns s3_keys in the audit dict instead of persisting them via save_s3_keys(). _set_login_cookies() encrypts the keys with Fernet (AES-128-CBC + HMAC-SHA256; key derived from the app secret via SHA-256) and sets a Secure, HttpOnly, SameSite=Lax cookie named s3 with the same TTL as the session cookie.

Key retrieval (borrow.py, account.py)

Both retrieval call sites now use get_s3_keys(account), which reads from the s3 cookie first and falls back to the store. This handles sessions predating this change without forcing re-login.

Migration script (scripts/purge_s3_keys.py)

Iterates all account store objects and removes the s3_keys field. Do not run until the cookie path has been live long enough that no active sessions rely on the store fallback.

Testing checklist

  • encrypt_s3_keys / decrypt_s3_keys round-trip in Docker
  • Login sets s3 cookie with correct attributes (Secure, HttpOnly, SameSite=Lax)
  • Borrow action succeeds using cookie path
  • Borrow action succeeds using store fallback path (session without cookie)
  • Tampered s3 cookie is rejected gracefully, falls back to store
  • scripts/purge_s3_keys.py --dry-run lists accounts with s3_keys without writing
  • make test passes in Docker

Notes

  • cryptography==44.0.2 added to requirements.txt (may already be a transitive dep via internetarchive; pin version as needed)
  • save_s3_keys() remains on OpenLibraryAccount for now; will be removed in a follow-up once the purge script has been run

mekarpeles and others added 2 commits June 4, 2026 23:49
On login, audit_accounts() now returns s3_keys in the audit dict
instead of persisting them to the account store. _set_login_cookies()
encrypts the keys with Fernet (AES-128-CBC + HMAC-SHA256, key derived
from the app secret) and sets them as a Secure, HttpOnly, SameSite=Lax
session cookie named "s3".

Key retrieval in borrow.py and account.py is updated to read from the
cookie first, falling back to the store for sessions predating this
change (soft migration).

Also adds scripts/purge_s3_keys.py for a future pass to remove
plaintext s3_keys from all account store objects. Do not run yet.

Closes #12856
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: store S3 keys as encrypted session cookie instead of in account store

1 participant