Pithos
Simple, secure web session handling for Python applications.
WARNING: This project is currently under active development and should not be used in production environments. API's may change without support for previous versions.
Goals:
Straightforward to understand and implement.
Web framework/library independent;
Support for different storage back-ends;
Secure by default;
Why Pithos?
Pithos is ancient Greek for a large terracotta storage jar. While no terracotta has been used in this project, we do provide you with a large jar for cookie related storage ;-)
Overview
Pithos provides three concepts to handle sessions:
A session instance which acts like a Python dictionary and handles session state handling, serialization and encryption;
A storage back-end which knows how to store, retrieve and cleanup sessions;
A handler class which ties session instances and storage together and integrates this with the request and response handling of your web-application.
In addition helper functions are provided to handle login and logout of authenticated users.
Pithos is Python 2.7 and Python >= 3.4 compatible.
Initial setup
Install like this:
pip install pithos
Optionally install storage specific requirements:
pip install pithos[redis]
Usage of a web framework is not required. Pithos can be used in any Python code which provides generic web concepts such as HTTP requests and reponses with cookies.
Pithos provides ready to use integration with Flask. The Flask implementation can be used as a reference implementation for your own setup.
Flask
For Flask one can configure the Flask app like this:
from flask import Flask
from pithos.flask import setup_pithos
from pithos.filesystem import FilesystemStore
app = Flask()
pithos_store = FilesystemStore(root='/my/path/to/sessions')
setup_pithos(app, pithos_store)
Pithos leverages the Flask session
interface, and can thus be used as a
regular Flask session:
from flask import session
@app.route('/foo')
def foo():
session['remember'] = 'me'
return 'bar'
Django
TODO: Implement and document Django integration
Tornado
TODO: Implement and document Tornado integration. Probably needs a async storage backend.
WSGI
TODO: Show plain WSGI integration
Session instances
A session instance works similar to a regular Python dictionary, in fact it
inherits from collections.MutableMapping
.
Public attributes of sessions:
is_modified
which indicates that the session has been modified. This is
automatically set to True when manipulating keys on the session directly but
should be manually set when modifying mutable data structures stored in the
session (such as dictionaries and lists).
The following public methods can be called on a session instance:
set_duration(ttl=<int>)
: all sessions expire after a default period set in
the handler
. Specific sessions may have a specific duration which can be set
using this method. This can be used to give privileged sessions a shorter
duration.
reset()
: clear anything stored in the session and forget its ID and
encryption key. Most of the time you're better of using the delete_session
method of the session handler
because that also tries to resets the session
cookie in an HTTP response.
Storage
Pithos sessions must be persisted somewhere, because it does not support storage of session content in cookies. Pithos currently provides plain file-system storage, and Redis backed storage. File-system storage is easy on memory usage while the Redis storage has the advantage of automatically removing expired sessions and using a central storage usable by multiple hosts.
Pithos uses JSON to serialize sessions, and in addition to natively supported
data types also serializes UUID
and datetime
instances to strings
(deserialization is not implemented).
Authenticated sessions
The pithos.authsession
module contains a few helper functions to implement
authenticated sessions related functions, such as login and logout.
These function work with the concept of a user checkvalue
. This should be a
JSON serializable value which changes when sensitive aspects of a user are
changed, for example when its password or username changes. Whenever this
checkvalue changes, all sessions of that user will become invalid. A sensible
checkvalue could be constructed by calculating a digest over the users protected
password and username as stored in the user database, or it could be random
value stored with the user and which is updated every time the user updates its
password.
The following functions are available:
get_user_id(session)
Retrieve the user ID from the session, return None when no user is set. Do not
forget to run check_session
immediately after retrieving the user instance.
get_user_extra(session)
Return a dictonary with extra user details stored with the user ID in the current session. This could be used to store which authentication method has been used to login.
login(session, user_id, checkvalue, **kwargs)
Login a user identified with user_id
onto the session. Also stores the user
checkvalue
and optionally additional user related data using keyword
arguments. The extra keyword arguments can later be retrieved using the
get_user_extra
function.
logout(session, response=None)
Destroys the current session and (optionally) sets an empty session cookie on the provided response.
keep_login(session, user_id, checkvalue)
Call this function when the users checkvalue deliberately changes, for example directly after the user successfully changes its password. This prevents the user from being logged out while all other sessions for this user become invalid.
check_session(session, checkvalue, response=None)
Checks if the users checkvalue matches. When the check fails, the session is reset and the function returns False.
Security
Pithos uses the excellent Python PyNaCl library which is a Python binding for NaCl.
Random 128 bits session ID's;
Sessions are stored encrypted and can only be read when in possession of the clients session cookie. Pithos uses authenticated encryption using NaCl Secret-key authenticated encryption (crypto_secretbox) (Salsa20 stream cipher + Poly1305 MAC for authentication);
Guaranteed session (server side) expiry in addition to session cookie expiry;
Optionally fix session to initial client IP address;
Only stores (JSON) data in sessions (not code, such as possible with Pickle);
Pithos provides helper functions to bind an authenticated user to a session. These helper functions prevent session fixation, needless session creation and invalidating authenticated sessions for a specific user.
Ideas / plans
Extend documentation and test suite
Optionally run session engine as daemon to use it from non-Python environments, use ZeroMQ and provide a Python client?;
Implement SQLAlchemy, Django ORM, and memcached backends;
Django, Tornado, bottle, webpy integration;
Provide example for plain WSGI usage.