Implement CSRF protection & error page

This commit is contained in:
Xevion
2022-03-29 16:25:30 -05:00
parent f41b83a15f
commit 311f061b10
3 changed files with 35 additions and 7 deletions

8
app.py
View File

@@ -6,11 +6,14 @@ import click
import pytz import pytz
from faker import Faker from faker import Faker
from flask import Flask, render_template, request from flask import Flask, render_template, request
from flask_wtf.csrf import CSRFProtect, CSRFError
from flask_login import LoginManager, current_user from flask_login import LoginManager, current_user
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash from werkzeug.security import generate_password_hash
from database import db from database import db
csrf = CSRFProtect()
def create_app(): def create_app():
app = Flask(__name__) app = Flask(__name__)
@@ -27,6 +30,7 @@ def create_app():
app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATABASE_URL', '').replace('postgres://', 'postgresql://', 1) app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATABASE_URL', '').replace('postgres://', 'postgresql://', 1)
db.init_app(app) db.init_app(app)
csrf.init_app(app)
login_manager = LoginManager() login_manager = LoginManager()
login_manager.login_view = 'auth.login' login_manager.login_view = 'auth.login'
@@ -52,6 +56,10 @@ def create_app():
# note that we set the 404 status explicitly # note that we set the 404 status explicitly
return render_template('errors/404.html'), 404 return render_template('errors/404.html'), 404
@app.errorhandler(CSRFError)
def handle_csrf_error(e):
return render_template('errprs/csrf.html', reason=e.description), 400
@app.before_request @app.before_request
def update_last_seen(): def update_last_seen():
if current_user.is_authenticated: if current_user.is_authenticated:

View File

@@ -1,9 +1,10 @@
from wtforms import Form, BooleanField, StringField, PasswordField, TextAreaField, validators from flask_wtf import FlaskForm
from wtforms import BooleanField, StringField, PasswordField, TextAreaField, validators
from validators import NoProfanity from validators import NoProfanity
class RegistrationForm(Form): class RegistrationForm(FlaskForm):
username = StringField('Username', [validators.Length(min=4, max=25), NoProfanity()]) username = StringField('Username', [validators.Length(min=4, max=25), NoProfanity()])
name = StringField('Name', [validators.Length(min=2, max=35), NoProfanity()]) name = StringField('Name', [validators.Length(min=2, max=35), NoProfanity()])
password = PasswordField('New Password', [ password = PasswordField('New Password', [
@@ -14,20 +15,20 @@ class RegistrationForm(Form):
accept_tos = BooleanField('I accept the TOS', [validators.DataRequired()]) accept_tos = BooleanField('I accept the TOS', [validators.DataRequired()])
class LoginForm(Form): class LoginForm(FlaskForm):
username = StringField('Username', [validators.DataRequired()]) username = StringField('Username', [validators.DataRequired()])
password = StringField('Password', [validators.DataRequired()]) password = StringField('Password', [validators.DataRequired()])
remember_me = BooleanField('Remember Me', [validators.Optional()]) remember_me = BooleanField('Remember Me', [validators.Optional()])
class EditProfileForm(Form): class EditProfileForm(FlaskForm):
name = RegistrationForm.name name = RegistrationForm.name
about_me = StringField('About Me', [validators.Optional(), NoProfanity()], description='Tell us about yourself',) about_me = TextAreaField('About Me', [validators.Optional(), NoProfanity()], description='Tell us about yourself',)
class NewPostForm(Form): class NewPostForm(FlaskForm):
text = TextAreaField('Text', [validators.Length(min=15, max=1000), NoProfanity()], description='Express yourself.') text = TextAreaField('Text', [validators.Length(min=15, max=1000), NoProfanity()], description='Express yourself.')
class NewCommentForm(Form): class NewCommentForm(FlaskForm):
text = StringField('Text', [validators.Length(min=5, max=50), NoProfanity()]) text = StringField('Text', [validators.Length(min=5, max=50), NoProfanity()])

View File

@@ -0,0 +1,19 @@
{% extends 'layouts/index.html' %}
{% block content %}
<div class="content-inner" style="display: flex">
<div style="margin: 0 auto;">
<h2>400 - Bad CSRF Token</h2>
<p>
{% if current_user.is_authenticated %}
Sorry <strong>{{ current_user.username }}</strong>, the
{% else %}
The
{% endif %} form you submitted requires a CSRF token to be valid.
<br>
This may happen if the form was submitted long after the token was generated, and it has thus expired.
<span style="text-align: center">Go <a href="{{ url_for('main.index') }}">home?</a></span>
</p>
</div>
</div>
{% endblock %}