I am running Flask on the Google App Engine using the Flask GAE Template .
I implemented the CSRF protection described in Flask-WTF Docs and I tested it.
I had an interesting problem when the session variable csrf_tokengets reset by my iPhone browser (Safari). I will describe what led me to this conclusion, but firstly, here is my code:
Relevant code in views.py:
def test_page(code):
form = forms.TestCSRFForm()
return render_template('csrf_test.html', form=form)
def test_ajax():
form = forms.TestCSRFForm()
return "{}".format(form.validate_on_submit())
Relevant code in urls.py:
app.add_url_rule('/csrftest/<code>', 'test_page', view_func=views.test_page, methods=['GET'])
app.add_url_rule('/csrftest/', 'test_ajax', view_func=views.test_ajax, methods=['POST'])
My template (csrf_test.html):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<title>Test</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script type="text/javascript">
function go() {
var csrftoken = $('{{ form.csrf_token }}').attr('value');
alert(csrftoken);
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type)) {
xhr.setRequestHeader("X-CSRFToken", csrftoken)
}
}
});
$.ajax({
type: "POST",
url: "/csrftest/",
data: { csrf_token: csrftoken }
}).done(function( msg ) {
alert(msg);
});
}
</script>
</head>
<body>
<button onclick="go();">go</button>
</body>
</html>
Some entries I made in Flask-WTF csrf.py:
def generate_csrf(secret_key=None, time_limit=None):
"""Generate csrf token code.
:param secret_key: A secret key for mixing in the token,
default is Flask.secret_key.
:param time_limit: Token valid in the time limit,
default is 3600s.
"""
if not secret_key:
secret_key = current_app.config.get(
'WTF_CSRF_SECRET_KEY', current_app.secret_key
)
if not secret_key:
raise Exception('Must provide secret_key to use csrf.')
if time_limit is None:
time_limit = current_app.config.get('WTF_CSRF_TIME_LIMIT', 3600)
if 'csrf_token' not in session:
session['csrf_token'] = hashlib.sha1(os.urandom(64)).hexdigest()
if time_limit:
expires = time.time() + time_limit
csrf_build = '%s%s' % (session['csrf_token'], expires)
else:
expires = ''
csrf_build = session['csrf_token']
hmac_csrf = hmac.new(
to_bytes(secret_key),
to_bytes(csrf_build),
digestmod=hashlib.sha1
).hexdigest()
logging.info("session['csrf_token'] = %s" % session['csrf_token'])
return '%s##%s' % (expires, hmac_csrf)
def validate_csrf(data, secret_key=None, time_limit=None):
"""Check if the given data is a valid csrf token.
:param data: The csrf token value to be checked.
:param secret_key: A secret key for mixing in the token,
default is Flask.secret_key.
:param time_limit: Check if the csrf token is expired.
default is True.
"""
if not data or '##' not in data:
return False
expires, hmac_csrf = data.split('##', 1)
if time_limit is None:
time_limit = current_app.config.get('WTF_CSRF_TIME_LIMIT', 3600)
if time_limit:
try:
expires = float(expires)
except:
return False
now = time.time()
if now > expires:
return False
if not secret_key:
secret_key = current_app.config.get(
'WTF_CSRF_SECRET_KEY', current_app.secret_key
)
if 'csrf_token' not in session:
return False
logging.info("session['csrf_token'] = %s" % session['csrf_token'])
csrf_build = '%s%s' % (session['csrf_token'], expires)
hmac_compare = hmac.new(
to_bytes(secret_key),
to_bytes(csrf_build),
digestmod=hashlib.sha1
).hexdigest()
logging.info("comparing hmacs: {0} {1}".format(hmac_compare, hmac_csrf))
return safe_str_cmp(hmac_compare, hmac_csrf)
Let's say I save the following links in the Notes application on my phone:
http:
http:
If I am in the first link from my phone and press "Go", everything works fine:

csrf_token , , , hmacs , .
, "", Safari ( ) , (csrftest/456), Safari ; /csrftest/ 456, ( , , ), /csrftest/ 123
:



, , , Safari (/csrftest/123), csrf_token - hmac /csrftest/ 456 csrf_token, hmac csrf_token , hmacs .
Safari, , ?
. , , Happy Thanksgiving:).