Prevent form resubmission with user refresh and need to submit data to webpage using Django - django

I've seen this question a few times and can't find an option that works in my situation.
I have a webpage that you can get to via a POST. It requires an 'example_id' be sent to the server.
The webpage has a form for the user to fill out. When they submit the form, I need the user to return to same page.
I need to prevent user 'refresh' from resubmitting the form. Most common solution I have found is:
return HttpResponseRedirect('/<web_page/')
I have tried this and adding kargs to the function parameters, but it doesn't seem to work.
Update:
I got my scenario to work by using the csrf token ({% csrf_token %}) . If the user refreshes the page, then the csrf token will be the same. So I check for this in my view and handle this scenario differently.

The solution I found.
I got my scenario to work by using the csrf token: {% csrf_token %}
If the user refreshes the page, then the csrf token will be the same. So I check for this in my view and handle this scenario differently than I would normally.

Related

CRSF cookie not set in iframed Django View within another site

I have a Django app with about a dozen views that I am currently hosting on Heroku. I can do POST requests just fine to the app when directly going to the app url, and I have the 'django.middleware.csrf.CsrfViewMiddleware' enabled. I am running Django 2.1
I am currently having an issue where I am trying to embed this Django app within an iframe, on another site that I host on Weebly. I always get a 403 error when trying to do a post on any of the Django forms. The reason is "CSRF cookie not set."
I am doing this through Chrome on Ubuntu. I checked the Applications tab in the Developer console, and do see the csrftoken key-value pair set in the cookie for the Heroku domain. The Weebly domain does not contain the csrftoken key-value pair. I figured it would just use the cookie from the Heroku app domain and use the csrftoken, but that doesn't appear to be the case.
In Django, here are my settings regarding CSRF:
CSRF_COOKIE_SECURE = False
CSRF_TRUSTED_ORIGINS = ['example123.herokuapp.com',
'app123.weebly.com']
I REALLY don't want to disable security or use the csrf_exempt decorator, as that feels like a hack. I am pulling my hair out on this one!
EDIT:
{% csrf_token %} is in the form, and I can see the hidden field "csrfmiddlewaretoken":
<input type="hidden" name="csrfmiddlewaretoken" value="XXXXXXXXXXXXXXXXXXXXXXywkFTfTC9ttYiOTD0O8uF49SvRjaUWgWeLU0h2PjP2">
There are two different things with csrf in django
1. Csrfmiddlewaretoken : {% csrf_token %}
example of set-token header
2. CSRFcookie : I don't think that you did this one.
example of same request giving different csrf-token
here the images shown are both the examples of one of my app for a specific request
We do often confuse second with the first one. In the second case, the server sets a cookie in the first get request with a csrf token (this is a cookie and not the csrfmiddlewaretoken ), it needs to be sent every-time for csrf cookie verification. This is done by the browser itself and we mostly don't notice it. However the problem arises with using CORS (different origins of request like android/angular app etc).

Form action and its usage in Django

First Quesiton:
This form submits to demo_form?name=ABC
<form action="demo_form" method="get">
name: <input type="text" name="name"><br>
<input type="submit" value="Submit">
</form>
Is there a way to make it submit to demo_form/ABC/?
Second Question:
Even if users don't use my form, if they use a web crawler to simply visit demo_form?name=ABC or demo_form/ABC/, it would yield the same result. I want to prevent that. What's the best way of making those two URLs only valid if the user submit the name via my form? I am learning django so hopefully the solution would work with django framework.
Thanks in advance!
Is there a way to make it submit to demo_form/ABC/?
You could intercept the submission in JavaScript, construct the URL manually, then set location. That would break if JS wasn't available.
More sanely, you could send an HTTP 301 redirect response when you get the request for demo_form?name=ABC
What's the best way of making those two URLs only valid if the user submit the name via my form?
Generally speaking, visiting a form should not be a pre-requisite for anything involving a GET request. A large portion of the point of GET is that the results are bookmarkable, linkable, etc.
It would be more understandable if it was a POST request, as those are intended to change data on the server and you will want to protect against CSFR. The standard protection against CSRF is a token stored in the form and in a cookie

CSRF verification failed when input value changed by javascript

In my Django template I have a POST form. It includes the tag {% csrf_token %}. If I submit this form normally then everything works fine. However, I need to change a form input value via Javascript/Jquery:
$('input').val(id);
If I do this then I get the "CSRF verification failed" error message when I submit the form. I do submit the form via Javascript, but this has not been a problem so long as I don't dynamically change any values.
I have been "solving" this by writing #csrf_exempt above my Python functions. However, this skips the security. Is there another way?
Command $('input').val(id); overwrites all input entries, which can be found, so hidden csrf_token input loses its value. Try to make more specific selector. For example:
$('input[name=change-me]').val(id);

Csrf token verification fails between two Django web applications

I am trying to pass csrf token between two web application to make one POST data to the other.
"client" application (C) asks csrf token to "server" application (S) via a GET operation.
S responds to C with a form:
<form id='csrfRequestForm' name='csrfForm' action='http://{{ context_path }}/ajax/getcsrf' method='post'>
<!-- csrf token -->
{% csrf_token %}
<!-- datas to POST follow -->
...
</form>
C has to submit this form to action (mapped on a url used by S) in order to POST datas to S.
When C tries to do it, csrf verification fails. I've checked GET's result and csrf token is received with the form. I have django.middleware.csrf.CsrfViewMiddleware keyword listed under MIDDLEWARE CLASSES in settings.py and RequestContext is passed when rendering form's view with render_to_response(... RequestContext(request))
What am I doing wrong?
Thanks
Try defining your context and returning it like this...
context = RequestContext(request, {
'request': request
})
return render_to_response(..., context_instance=context)
This is by design, and disallows for cross site POST execution. One option you have is to mark the methods you would like to be able to execute as safe, as per the django docs:
https://docs.djangoproject.com/en/dev/ref/contrib/csrf/
I wasn't able to resolve it in your way, but I managed out how to do it:
C go directly to S via javascript opening a popup with:
window.open("http://<S_address>/<path_to_request_form>");
In this way, user using C that is logged via a third party authentication server (I forgot to mention it earlier, sorry), is still logged in the popup window in S and receives the form in it with a correct csrf token. I don't know if it's correct but it works.
Thanks for your time

Render to response to a redirected url in Django

In a form submission scenario, form is post to "/submit". I want to redirect user to "/sucess" on success and pass render some message to a template at new url. How to do this in Django? render_to_response doesn't do redirect and HttpResponseRedirect doesn't do template rendering.
The response from Daniel Roseman is potentially dangerous, opening your site to XSS vulnerabilities.
Make sure you strip html tags from whatever message is passed if you must do it this way.
A better way would be to redirect to /success/?msg=ok, and have in your view a dictionary:
{ 'ok': 'Your success message' }
If your success page needs a dynamic message, you need to pass it there somehow. You can either do this via GET parameters in the URL you are redirecting to - eg return HttpResponseRedirect('/success/?msg=My+success+message+here') - or by setting some values in the session, which the success view can pick up.
The best way to do what you want is:
In your view set the success message (or error message) as a dict. And use the render_to_response to display any template.
In your template you can verify if there is a message and if the message is an error message or a success message.
Some like this:
In your view:
if anyError:
dict = {"message" : {"error" : "The error message"}}
else:
dict = {"message" : {"success" :"The success message"}}
in your template:
{% if message %}
{% if message.error %}
{{ message.error }}
{% else %}
{{ message.success }}
{% endif %}
{% endif %}
Hope i've helped
There is no good way to do what you want. The browser submits the form, which will take the user to /submit. Once you decide whether it's "successful", it's too late; the browser has already decided on it's destination. All you can do is redirect. But, as you're finding out, it's going to be hard to keep your POST state when you redirect.
I would give up on this. It's not how websites are supposed to work.
I think Django does this already if you extend the generic view. On create there's an optional argument "post_save_redirect". This functionality is used in the automatically generated Django admin system. For example if you want a new resource, say user, you go to the url "/user/add". After you submit it redirects you to "/user/1" with a success message "you just saved user #1". So this is possible, but I'm still researching how to do it without extending the generic view. I'm still very new to Django and python, so looking through Django core to find how they did it is not so easy for me.
I would recommend to use Django message framework which is used for one-time notification messages.
https://docs.djangoproject.com/en/1.8/ref/contrib/messages/