Skip to content

Fork of Flask-RESTPlus 0.12.1 that adds CSRF support. Flask-RESTPlus is a fully featured framework for fast, easy and documented API development with Flask

License

Notifications You must be signed in to change notification settings

OpenTechStrategies/flask-restplus-csrf

 
 

Repository files navigation

Flask RestPlus CSRF

Flask-RESTPlus-CSRF is a fork of Flask-RESTPlus that adds support for CSRF tokens.

Because Flask-RESTPlus-CSRF is just a small set of changes on top of the original Flask-RESTPlus, and is intended to be a drop-in replacement, we have left the original package's name unchanged in the Python namespace. That is, this CSRF-enabled version is also installed as Flask-RESTPlus, and therefore cannot coexist with the original Flask-RESTPlus within the same project.

In this document, we will usually refer to this overall package as "Flask-RESTPlus-CSRF" (except when we're talking about the original package). However, the actual installation commands will still use just "flask-restplus".

About the original Flask RESTPlus

Flask-RESTPlus is an extension for Flask that adds support for quickly building REST APIs. Flask-RESTPlus encourages best practices with minimal setup. If you are familiar with Flask, Flask-RESTPlus should be easy to pick up. It provides a coherent collection of decorators and tools to describe your API and expose its documentation properly using Swagger.

CSRF Workflow

Browsers "do" things by making web requests. Users declare their intentions quite broadly: "fetch me the New York Times homepage" or "do an image search for 'cute cats'". The browser then issues dozens of web requests to fetch text, formatting, and instructions. Those requests happen without user interaction or specific authorization.

A users's browser authenticates to a website, say FederalBank.com. That browser now has permission to act with the user's permission. From FederalBank.com's perspective, anything the browser does is done by the user, including the automated requests needed to fulfill broadly-expressed user needs.

This is all well and good. It's how the web is meant to work, and it mostly works pretty well. Users, though, visit many different sites, and in the absence of security measures (like CORS and CSRF), any of them might ask your browser to issue a request to any site. The site might treat those requests as being intentionally issued by a user, even though that user did not authorize them or even know about them.

The security goal of this project is to prevent such unauthorized requests from one site to another. We do not want to allow forged requests that borrow a browser's authentication cookies for unauthorized purposes.

There are two main approaches to addressing this problem. The first is CORS, which is beyond the scope of this exercise. The second is via issuance of CSRF tokens to visitors.

The workflow for CSRF tokens is that, upon login, a site generates a random token. On the server, it remembers this token along with the user's session information. It inserts this token into the javascript of the webpage it serves to its user. It does not set the CSRF token in cookies. In this manner, the user has a copy of the CSRF token in the site's webpage, but that token is not available from anyplace else. The server can treat requests submitted without the token as unauthenticated.

For third parties that might want to issue requests while disguised as this user, they would first have to obtain the token. Even if CORS policy allowed it, they could not simply use another site to cause the browser to make the request. The other site wouldn't have the needed token.

This brings us to the CSRF workflow:

  1. On login, choose a CSRF token. Store it with the session data. It is good for a set amount of time or until logout. On every request, generate a new token with a similar duration of validity.

  2. Insert the token into the javascript of pages generated by the site. This makes the token available to scripts on the page.

  3. Design the webpage's scripts to include the token in authenticated requests.

  4. On the server side, reject API requests that require authentication but do not provide one of the valid tokens.

  5. On logout, invalidate all the tokens, typically by destroying the server's copy of them.

Compatibility

Flask-RESTPlus-CSRF requires Python 3.6.3. Yes, that's a pretty specific version of python. We're open to other versions, but that's the one we need right now, so we're focused on it.

Installation

You can install Flask-RESTPlus-CSRF with pipenv:

  $ pipenv install -e git+https://github.com/OpenTechStrategies/flask-restplus-csrf@master#egg=flask-restplus-csrf

Quick start

With Flask-RESTPlus-CSRF, you only import the api instance to route and document your endpoints.

    from flask import Flask
    from flask_restplus import Api, Resource, fields

    app = Flask(__name__)
    api = Api(app, version='1.0', title='TodoMVC API',
        description='A simple TodoMVC API',
    )

    ns = api.namespace('todos', description='TODO operations')

    todo = api.model('Todo', {
        'id': fields.Integer(readOnly=True, description='The task unique identifier'),
        'task': fields.String(required=True, description='The task details')
    })


    class TodoDAO(object):
        def __init__(self):
            self.counter = 0
            self.todos = []

        def get(self, id):
            for todo in self.todos:
                if todo['id'] == id:
                    return todo
            api.abort(404, "Todo {} doesn't exist".format(id))

        def create(self, data):
            todo = data
            todo['id'] = self.counter = self.counter + 1
            self.todos.append(todo)
            return todo

        def update(self, id, data):
            todo = self.get(id)
            todo.update(data)
            return todo

        def delete(self, id):
            todo = self.get(id)
            self.todos.remove(todo)


    DAO = TodoDAO()
    DAO.create({'task': 'Build an API'})
    DAO.create({'task': '?????'})
    DAO.create({'task': 'profit!'})


    @ns.route('/')
    class TodoList(Resource):
        '''Shows a list of all todos, and lets you POST to add new tasks'''
        @ns.doc('list_todos')
        @ns.marshal_list_with(todo)
        def get(self):
            '''List all tasks'''
            return DAO.todos

        @ns.doc('create_todo')
        @ns.expect(todo)
        @ns.marshal_with(todo, code=201)
        def post(self):
            '''Create a new task'''
            return DAO.create(api.payload), 201


    @ns.route('/<int:id>')
    @ns.response(404, 'Todo not found')
    @ns.param('id', 'The task identifier')
    class Todo(Resource):
        '''Show a single todo item and lets you delete them'''
        @ns.doc('get_todo')
        @ns.marshal_with(todo)
        def get(self, id):
            '''Fetch a given resource'''
            return DAO.get(id)

        @ns.doc('delete_todo')
        @ns.response(204, 'Todo deleted')
        def delete(self, id):
            '''Delete a task given its identifier'''
            DAO.delete(id)
            return '', 204

        @ns.expect(todo)
        @ns.marshal_with(todo)
        def put(self, id):
            '''Update a task given its identifier'''
            return DAO.update(id, api.payload)


    if __name__ == '__main__':
        app.run(debug=True)

Dev Notes

See https://github.com/OpenTechStrategies/flask-restplus-csrf-demo/ for an example usage.

Install Source and Setup Dev Environment

When doing development, you can link your webserver to this cloned version:

  $ pipenv install -e $PATH/TO/THIS/LIBRARY

Documentation

Documentation for the original Flask-RESTPlus is hosted on Read the Docs.

About

Fork of Flask-RESTPlus 0.12.1 that adds CSRF support. Flask-RESTPlus is a fully featured framework for fast, easy and documented API development with Flask

Resources

License

Contributing

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Python 98.7%
  • Other 1.3%