I have an html form, and I would like to insure that all submissions come from my website. I think I have seen people using a key for this (I believe this happens in Django?), and might have some ideas on how to go with that. Is there any standard way to do this in Flask?
Edit:
Now I know I'm talking about CSRF token middleware. Again, is there any standard way of doing this in Flask? How can I store the key on the server side?
In flask you can do CSRF protection using Flask-SeaSurf.There are other methods also but it is straight forward.
To start Just do pip install flask-seasurf and you are ready
import Flask
from flask_seasurf import SeaSurf
app = Flask(__name__)
csrf = SeaSurf(app)
<form method="POST">
...
<input type="hidden" name="_csrf_token" value="{{ csrf_token() }}">
</form>
#csrf.exempt
#app.route('/exempt_view', methods=['POST'])
def exempt_view():
'''This view is exempted from CSRF validation.'''
return 'foobar'
For more information you can visit official website
Please mark this as answer if this solves you problem.
Related
I'm making backend for my website and it requires flask setting cookies. When I set the cookies, it works fine, but when I try to get them with request.cookies.get('name') it returns None. I tried just returning request.cookies and all that was there was my GA cookies, not the one that I set. Am I doing something wrong? Here's my code:
#app.route("/setcookie", methods=["GET", "POST"])
def setcookie():
resp = make_response(render_template("index.html"))
resp.set_cookie("authToken", "testestestestestestes", max_age=1)
return resp
#app.route("/getcookie", methods=["GET" ,"POST"])
def getcookie():
return request.cookies
index.html form:
<form action="/setcookie" method="POST">
<button type="submit">Set</button>
</form>
<form action="/getcookie" method="POST">
<button type="submit">Get</button>
</form>
I compared the GA cookies to the cookies that I set and the only difference was the name and value so that confuses me even more. I also don't need to do anything with them on the frontend, they only need to be read by flask. Can someone help? Thanks
You set max_age to 1 second, your cookie just gets expired, try increasing max_age value
For my login page, I have enable a captcha where user has to enter a 4 digits as displayed in the image. I'm using flask-session-captcha module for this. I followed exactly the same steps as in the instruction.
In the same login page, I also have a hidden CSRF token.
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
It's working fine when I developed and tested it in my local environment (my laptop) but it doesn't work when I tested it in the test server. It will give errors such as "The CSRF tokens do not match." or "Invalid captcha" (even though I answered correctly) or sometimes "Missing CSRF token".
I have tried so many things like using decorator #csrf_exempt for that particular login page. I also added this:
#app.after_request
def apply_caching(response):
response.headers["X-Frame-Options"] = "SAMEORIGIN"
response.headers["Cache-Control"] = "public, max-age=0, no-cache, no-store, must-revalidate"
response.headers["Pragma"] = "no-cache"
response.headers["Expires"] = "0"
return response
But nothing seems to work. It really puzzles me why it works on local but not on test server. I tried not to use csrf_token() in the login page but it gave me error of missing csrf token. Using Google ReCaptcha is not an option because the user doesn't want to use that.
I wonder if it's because the captcha token is conflicted with the csrf token?
Can you try flask_recaptcha?
Below are minimized example.
#app/__init__.py
from flask_recaptcha import ReCaptcha
recaptcha = ReCaptcha(app=app)
#app/views/your_view.py
#app.route('/a_view_for_demo/', methods=['GET', 'POST'])
def a_view_for_demo():
a_form = AForm()
if a_form.validate_on_submit() and recaptcha.verify():
# do your thing after validation.
return render_template('a_template.html', a_form=a_form)
#app_config
RECAPTCHA_ENABLED=True
RECAPTCHA_SITE_KEY="get this key from Google"
RECAPTCHA_SECRET_KEY="get this key from Google"
# a_template.html
<form .....>
{{ a_form.csrf_token }}
{{ recaptcha }}
</form>
I'm currently writing a simple blog application using Flask-Admin for administrative tasks. I'd like to enable CSRF protection and have followed the instructions on the Advanced Functionality page in the docs.
However, this doesn't seem to prevent my dummy CSRF attacks from succeeding and it is unclear how Flask-Admin follows the CSRF protection implementation outlined in the WTForms documentation.
Regarding my dummy CSRF attacks, my method follows the example for POST requests suggested in the OWASP CSRF article:
<body onload="document.forms[0].submit()">
<form action="http://localhost:5000/admin/blogpost/new?url=%2Fadmin%2Fblogpost%2F" method="POST">
<input type="hidden" name="title" value="Evil title"/>
<input type="hidden" name="content" value="Evil content"/>
<input type="submit" value="Save"/>
</form>
where the action address is the new post creation page that draws from the create.html template of Flask-Admin.
When I load the malicious form from a separate origin (localhost:3000) and submit it on document load, I find that the request goes through despite the form being configured with the Flask-Admin SecureForm setup linked above.
I've tried consulting the Flask-Admin source code, but couldn't find the WTForms csrf_token in the relevant templates, though the SecureForm includes the CSRF settings as expected.
Does Flask-Admin diverge from the documented WTForms implementation of CSRF protection? If so, how?
More practically speaking, is there any additional configuration beyond the use of Flask-Admin's SecureForm in my ModelView-based classes necessary to enable CSRF protection?
Note also that the technique described in this answer also worked for me in my attempts to use exposed admin URLs cross-site (again from localhost:3000) to perform actions requiring authentication.
This leads me to ask the follow-up: is it possible to implement CSRF on non-form Flask-Admin pages, i.e. for GET requests, to protect exposed admin URLs used for operations such as logout or account deletion operations?
I have a question regarding Django Forms and GET
I have a form to download student scores in CSV format. The fields are name and year so I have a forms.py
StudentDownloadForm(forms.Form):
name=forms.CharField()
year = forms.CharField()
And I want to use this form in the template.html with
context={'student_form' : StudentDownloadForm(),}
<form action ="" method="GET">
{% csrf_token %}{{ student_form|crispy }}
<input type="submit" value="Query"/>
</form>
So my questions are as follows:
If I use the method="GET" then the csrf token is visible in the URL, which is a security issue
Can I then use the method="POST" instead?
Alternatively, can I remove the csrf token in the form?
According to Django documentation (Cross Site Request Forgery protection):
For all incoming requests that are not using HTTP GET, HEAD, OPTIONS
or TRACE, a CSRF cookie must be present, and the ‘csrfmiddlewaretoken’
field must be present and correct. If it isn’t, the user will get a
403 error.
And:
It deliberately ignores GET requests (and other requests that are
defined as ‘safe’ by RFC 2616). These requests ought never to have any
potentially dangerous side effects , and so a CSRF attack with a GET
request ought to be harmless. RFC 2616 defines POST, PUT and DELETE as
‘unsafe’, and all other methods are assumed to be unsafe, for maximum
protection.
So, you can omit CSRF token for GET requiests
So I'm trying to send data from an html form to my python flask framework.
Here's the example of the html code I'm using
<form method=post action=/test>
<input name=Name value=Austin type=hidden><input type=submit value="Add Notification">
and here's the python flask I'm working with
#app.route('/test', methods=('GET', 'POST')
def test_page():
v = request.values.get('Name')
return v
I've tried many different request methods and can't seem to get it to work and I get a 405 error. I'm not very familiar with the flask web development or using post requests. If anyone could point me in the correct direction then that'd be great!
You're POSTing to your endpoint, but app.route by default only enables GET. Change app.route('/test') to app.route('/test', methods=('GET', 'POST')), and you'll be able to access your endpoint.
That 405 response you're getting is Method Not Allowed.
(Unrelated issue, request.values.get['Name'] should be request.values.get('Name').)