Skip to content

Latest commit

 

History

History
343 lines (211 loc) · 10.9 KB

README.md

File metadata and controls

343 lines (211 loc) · 10.9 KB

flask-xsrf

flask extension for defending against cross-site request forgery attacks (xsrf/csrf), by protecting flask request endpoints with uniquely generated tokens for each request.



FLASK PYTHON XSRF
flask python csrf





BUILD STATUS

branch service status service title status
master ci-build travis-ci-build-status-master github tags github-tags
develop ci-build travis-ci-build-status-develop github releases-all github-releases-all
master coveralls.io coveralls-coverage-status-master github releases-latest github-releases-latest
develop coveralls.io coveralls-coverage-status-develop pypi releases-latest pypi-releases-latest
master landscape.io landscape-code-health-master pypi downloads pypi-downloads
develop landscape.io landscape-code-health-develop pypi dl-month pypi



REFERENCE / LINKS



HOW IT WORKS

  • flask route handlers are decorated to generate, send a uniquely hashed token
    • the hashed values are stored on the server, using flask sessions
    • the token is sent in the response header X-XSRF-Token
  • on subsequent client requests..
    • the client will be expected to send the token back to the server
      • either through form data, or through the header X-XSRF-Token
    • to the server receive, validate uniquely hashed tokens

diagram of an xsrf attack

FEATURES

  • flexible - decide which style of implementation suits you best.
    • capture, validate XSRF-Tokens through headers, cookies, form-fields; the style is an easily configurable choice.
  • timeout - optionally, you can specify a default time window for valid tokens
  • tested - used internally @ google.


USAGE

REQUIREMENTS

python flask
2.7.6+ 0.11.0+


INSTALLATION

install with pip (more often it is recommended to lock / specify a specific version):

pip install --disable-pip-version-check flask-xsrf
pip install --disable-pip-version-check flask-xsrf==1.0.3

IMPLEMENTATION

implementation of the library with your flask app breaks down into four steps.

1: add a secret_key to your flask app config object:

from flask import Flask

flask_app = Flask(__name__)
flask_app.secret_key = '<:session_secret_key>'
flask_app.config['session_cookie_secure'] = True
flask_app.config['remember_cookie_name'] = 'testdomain.com'
flask_app.config['remember_cookie_duration_in_days'] = 1

2: create an instance of an XSRFTokenHandler object, and specify a method/callable which will be used as a getter by the token handler to get a user_id. optionally, you can assign auto-generated id's for anonymous requests. lastly, you may specify a default timeout, in number of seconds, to expire tokens after a specific the amount of time:

from flask import Response
from flask import session
import flask_xsrf as xsrf

@flask_app.before_request
def before_request():
  if 'user_id' not in session:
    session['user_id'] = 'random_generated_anonymous_id'

def get_user_id():
  return session.get('user_id')

xsrf_handler = xsrf.XSRFTokenHandler(
  user_fn=get_user_id, secret='xsrf_secret', timeout=3600)

NOTE: currently, usage of the session is required (see TODO notes below).

3: decorate GET request-handlers to send a generated token:

@flask_app.route('/test', methods=['GET'])
@xsrf_handler.send_token()
def test_get():
  return Response('success')

4: decorate POST request-handlers to receive, validate sent tokens:

@flask_app.route('/test', methods=['POST'])
@xsrf_handler.handle_token()
def test_post():
  return Response('success')

TO SUMMARIZE

that's all there is to it. please feel free to contact me [email protected] or to submit an issue on github for any questions or help. however, creating a fork and submitting pull-requests are much preferred. contributions will be very much appreciated.



CONTRIBUTING

STAR, FORK THIS PROJECT

forks stars
github forks github stars

LOCAL ENVIRONMENT SETUP (OSX)

here's a list summary of the python environment setup:

  • setup pyenv, pyenv-python-2.7.11
  • setup virtualenv, virtualenvwrapper
    • create project virtualenv
    • with a command such as $ mkvirtualenv flask-xsrf-dev
  • install pip dependencies
  • install local development build
    • $ python setup.py --verbose develop

INSTALL PYENV

pyenv (aka NVM or RVM for python) allows installing python at specific versions, and helps to manage multiple versions on osx. install is easy, and can be tricky to work with, unless you remember to set the proper environment shell variables:

init-pyenv(){
  export PYENV_ROOT="$HOME/.pyenv"
  export PYENV_PY_VERSION="2.7.11"
  export PYENV_VERSION_BIN_DIR="$PYENV_ROOT/versions/$PYENV_PY_VERSION/bin"
  export PYENV_BUILD_ROOT="$PYENV_ROOT/sources"
  export PYENV_SHIMS_DIR="$PYENV_ROOT/shims"
  export PYENV_SHELL="bash"
  export PYENV_DEBUG=0
  export PATH="$PYENV_ROOT/bin:$PYENV_VERSION_BIN_DIR:$PATH"
}

init-virtualenv(){
  export VIRTUALENVWRAPPER_SCRIPT="$PYENV_VERSION_BIN_DIR/virtualenvwrapper.sh"
  export WORKON_HOME="$HOME/.virtualenvs"
  export PIP_VIRTUALENV_BASE=$
  . "$VIRTUALENVWRAPPER_SCRIPT"
}

now we're ready to install pyenv/python:

init-pyenv
git clone https://github.com/yyuu/pyenv.git "$PYENV_ROOT"
eval "$(pyenv init -)"
pyenv install 2.7.11 && say "pyenv install of python 2.7.11 complete"
pyenv rehash
pyenv global 2.7.11

next, configure virtualenv:

init-virtualenv
pyenv exec pip install --disable-pip-version-check --upgrade pip
pyenv exec pip install --disable-pip-version-check virtualenv && pyenv rehash
pyenv exec pip install --disable-pip-version-check virtualenvwrapper && pyenv rehash

next, create the project virtualenv, install dependencies:

mkvirtualenv flask-xsrf-dev && pyenv rehash
workon flask-xsrf-dev && pyenv rehash
pyenv exec pip install --disable-pip-version-check -r .serpent/runtime-config/pip/requirements.txt && pyenv rehash

DEVELOPMENT FLOW

  • TODO: generate asciicinema movie clip of setup steps..?
  • activate the environment
    • $ init-pyenv
    • $ init-virtualenv
    • $ eval "$(pyenv init -)"
    • $ workon flask-xsrf-dev
  • run tests
    • $ python setup.py nosetests
  • view coverage report
    • $ coverage report --show-missing

viola. that's pretty much all there is to the flow (for now..).




TODOs

  • add feature: enable checking of referer headers / client ip-address
  • remove hard-coded dependency / usage of session.
  • add feature: enable storage of tokens in cookie.
    • this might help ease implementation, as the client would not have to manually manage passing of tokens to server.


COPYRIGHT, LICENSE

the derived work is distributed under the Apache License Version 2.0.