In this blog post I will describe how to secure your Flask application.
Cross Site Scripting or XSS is an attack that tries to have your website or application load a malicious script in the browser. This script can try access user’s credentials data, get cookie information, modify settings, download bits, etc.. One way to avoid this attack is to escape text and to validate user input.
By default Flask configures Jinja2 to auto escape all values loaded in the page.
jinja_options = ImmutableDict(
where the jinja2.ext.autoescape extension depends on
app.jinja_env.autoescape = True | False
This could lead to some performance overhead. You still have to consider several scenarios where you should be careful:
– avoid generating html without Jinja2;
– avoid sending out data from uploaded files;
– avoid using the Markup class on not verified data sent by a user;
Additional information about the XSS attacks can be found here.
Cross-Site Request Forgery or CSRF is an attack that uses the user’s authentication credentials to execute unwanted actions.
In order to secure your application against CSRF is to use a random string and to verify it against a hidden field. The complete code snippet can be found here.
Additional information about CSRF attacks can be found here.
SQL Injection is an attack where users can inject SQL commands via user input form and have them executed on the server. This SQL commands could do everything: read sensitive data, modify the database data, perform administrative tasks against the database server. Your application can be exposed to this attack when you dynamically create SQL statements (concatenating data based on user’s input), etc. By default SQL Alchemy quotes special characters – semicolons or apostrophes.
Authentication and Authorization
Authentication is a process that verifies the user’s identity, by validating his / her credential (username / email, password) against a given authority. Authorization process verifies whether the authenticated user has access to a given resource.
Flask-Security is a very helpful extensions that integrates several other Flask extensions and Python libraries:
and provides out-of-the-box support for Flask-SQLAlchemy.
Note: I am using an older version of Flask-Login – 0.2.11, in order to workaround a breaking change in the extension’s API, that breaks the integration with the other security related Flask extensions.
Flask-Security uses internally a User and Role data model, that could be defined via the SQL Alchemy API.
roles_users = db.Table('roles_users', \
db.Column('user_id', db.Integer(), db.ForeignKey('user.id')), \
db.Column('role_id', db.Integer(), db.ForeignKey('role.id')))
class Role(db.Model, RoleMixin):
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(80), unique=True)
description = db.Column(db.String(255))
def __init__(self, name):
self.name = name
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(255), unique=True)
password = db.Column(db.String(255))
active = db.Column(db.Boolean())
roles = db.relationship('Role', secondary=roles_users,
def __init__(self, email, password, active, roles):
self.email = email
self.password = password
self.active = active
self.roles = roles
The User class derives from the UserMixin Flask-Login default user implementation and same goes for the Role class – RoleMixin. You could add any aditional information to both User and Role classes if you need to.
Note: I have modified the seed.py module to seed the database with test users and roles data.
I am using SQL Alchemy for managing both User and Role objects. I have added the following configuration related to using Flask-Login with SQL Alchemy:
# Configure Security
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
app.security = Security(app, user_datastore)
The complete Flask-Security configurations with their explanations can be found here.
To be compliant with the layout, I have implemented custom login and registration forms:
It is common to be able to access the current user in your Flask application within the Jinja templates and introduce some logic based on that data. In order to achieve that goal you could use context processors:
and you could access the user in your templates: bookshelf/templates/layout.htm
As I mentioned earlier: authorization is a process verifies whether the authenticated user has access to a given resource. Flask-Security allows developers to restrict access to a given page by specifying that a user should be either logged in or have given role(s) assigned, by decorating the view function with @login_required, @roles_required:
from flask_security.decorators import roles_required
@admin.route('/author/create', methods=['GET', 'POST'])
The complete demo application, described in this blog post, can be found here.
In the next blog post I will describe how to optimize your Flask application.