I need help with some concepts.
In my Django web app, users write content and other users upvote/downvote the said content. Standard stuff.
The voting used to happen via POST. E.g. something akin to this:
<form method="POST" action="{% url 'vote' %}" class="vote_form">
{% csrf_token %}
<input type="hidden" id="id_link" name="link" class="hidden_id" value="{{ link.pk }}">
<input type="hidden" id="id_voter" name="voter" class="hidden_id" value="{{ user.pk }}">
<input type="hidden" id="id_page" name="section_number" value="{{ forloop.counter }}">
<input class="voting" type="submit" name="val" value="upvote"><br>
<input class="voting" type="submit" name="val" value="downvote">
</form>
The voting now happens via simply the following:
upvote<br>
downvote
My two questions are:
1) All else equal (ceteris paribus), is there any difference in these two methods in terms of security? I ran Wapiti (a security scanner) on my website; the latter method popped several security risks (SQL injection, Blind SQL injection, etc) whereas the former method comes out completely clean (but yes, I did change some underlying code as well).
2) The former method left a POST log entry in nginx logs. How would the latter method show up in nginx logs? GET?
There's nothing insecure in your code, but that still doesn't make it a good idea.
Generally you should avoid doing actions that affect the database on a GET. One possible consequence is that if a search engine crawled your site, it would follow the voting links and cause votes to actually be registered; this wouldn't happen with your original code, because search engines don't submit forms.
Related
How to disable the intermediate signout page from django allauth. When the user clicks on the signout link on my site I want him to logout right away, I want to remove this intermediate page
Set ACCOUNT_LOGOUT_ON_GET to True in your settings.
Also see the documentation
Using a GET request is probably a bad idea due to browsers prefetching urls from the URL bar. Chrome (as of right now) is pretty bad for this; it'll send a GET request to pages it think you'll hit enter on when typing in your URL bar.
Plus, people can add a link such as <img src="https://example.com/account/logout/"> and you'll be logged out. That's not a security risk since it's logging you out, but it is certainly annoying for your users.
Instead, you should consider using a POST request using a form with CSRF. Django Allauth already comes with this. Here's the <form> from the intermediate signout page:
<form method="post" action="{% url 'account_logout' %}">
{% csrf_token %}
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}"/>
{% endif %}
<button class="STYLE_ME" type="submit">Logout</button>
</form>
In my case, I just added this to the site header and made the submit <button> look like every other link using CSS so it feels the same to them, but the form will use a POST request.
But if that's not a solution you can implement for any reason, open your settings.py file (or your main settings file) and set:
ACCOUNT_LOGOUT_ON_GET = True
^ The above setting will do what you need. For further Django Allauth settings, check out their configuration page.
Here's another shortcut for preserving the POST request, if you don't want to mess with styling the form button with something like this:
Hide the form:
<form style='display: none;' method="post" action="{% url 'account_logout' %}">
{% csrf_token %}
<input type="hidden" name="next" value="/redirect_target/"/>
<button id="signOutBtn" type="submit">Logout</button>
</form>
Submit with a click event attached to whatever element you've already styled:
$(document).on('click', '#signOutLink', function() {
$('#signOutBtn').click()
});
I have this recurring problem with form submission in Django, and the frustrating part is that I'm not sure how to interpret what's happening. Essentially I have different pages with form submissions on them. Some of them work as following
localhost/page/formpage--> localhost/page/receivingpage
which is what I expect. Othertimes, it goes to a page like this
localhost/page/formpage--> localhost/page/formpage/recevingpage
and the screen shows a blank form page, which is not what I expect. I'm not sure how to interpret this, and I'm not sure where to look for errors in my code. I think I don't fully understand what's going on when I submit a form, how does it generate a URL after I press 'submit'?
Edit: here is my html form:
<!DOCTYPE HTML>
<html>
<div>
<p>Entry Form</p>
<form action= "user" method="post" >
{% csrf_token %}
<p><label for="id_username">Username:</label>
<input id="id_username" type="text" name="username"" /></p>
<p><label for="id_password">Password</label>
<input type="password" name="password" id="id_password" /></p>
<input type="submit" value="Submit" />
</form>
</div>
</html>
I suspect it isn't the form, I have it on another application and it works... the trouble is I don't know if it's the view, the template, or w/e, so I'll update the post with info as people request it.
I'd recommend putting in an action using the url template tag. With that, you will know for certain where the form is going to end up:
<form action="{% url 'user-url-name' %}" method="post">
The url tag will be an absolute url. Without this, you're going to end up at a relative url depending on where in your application the user submits the form, which can be quite confusing during development and not entirely correct.
Using {% url %} tag is the proper way to do. Your problem can also be solved by adding a forward slash / to the action attribute like this:
<form action="/user" method="post" >
Hope this helps!
I'm just getting started with Django, and I'm trying to use built-in features as much as possible. As such, for user login, I'm using the built-in login view, and assigning it to the base url of my site:
urlpatterns=patterns('django.contrib.auth.views',
url(r'^/$','login',{'template':'mytemplate.html'}),
mytemplate.html looks something like this:
<!DOCTYPE html>
<html>
<body>
{%if form.errors %}
<p> Invalid username/password combination, please try again </p>
{% endif %}
<h1>Welcome to My Site!</h1>
<form action="{% url django.contrib.auth.views.login %}" method="post">
{% csrf_token %}
{{form.username.label_tag}}{{form.username}}
{{form.password.label_tag}}{{form.password}}
<input type="submit" id="submit" name="submit" value="Sign in" />
<input type="hidden" name="next" value="{{ next }}" />
</form>
forgot username/password<br />
new user
</body>
</html>
my problem is, the template doesn't appear to be getting passed any of the context it's supposed to. In the rendered HTML, all of my variable tags simply disappear (i.e. rather than being replaced by the appropriate values, thay are replaced with nothing).
I imagine I'm skipping some critical step, but I can't figure out what it is. Any ideas?
You need to change from 'template' to 'template_name'
urlpatterns=patterns('django.contrib.auth.views',
url(r'^/$','login',{'template_name':'mytemplate.html'}),
https://docs.djangoproject.com/en/1.4/topics/auth/#django.contrib.auth.views.login
Try removing the template name from your url configuration. Django will then fall back to a standard template, that way you can see if you screwed up the template somehow or if something else is wrong.
My next guess would be to check your settings for the TEMPLATE_CONTEXT_PROCESSORS. If you have defined any of them, be sure to include
"django.contrib.auth.context_processors.auth",
If you haven't defined any, django will use a standard tuple, which allready includes the auth processor.
I know this is going to sound silly but I can't find what's wrong.
I am using the built in views for user auth and logging in and loggin out respectively switches the language to the non default language for the current session.
I have two languages, setup according to documentation on Djangoproject site i.e. in locale folder and there are .mo files and everything. Fine.
I have a form based language switch that enables language switch for any user that posts to /i18n/setlang
So, my question is, how come it seems to "POST" to switch language when I do a logout or a login (which I guess are both POST's as well).
Thanks for shedding any light possible on this.
EDIT: I should add that it never switches back. It only switches languages in one direction i.e. to the language that is not default.
EDIT2: Not that I think it will attract any more answers but here's the code for my language switcher (it switches on the fly via jQuery. The problems is STILL that it goes to Deutch language and stays there whenever I logout (logout is handled by the logout view in Django).
<ul>
<li>
<form name="setLangen" action="/i18n/setlang/" method="POST"><div style='display:none'><input type='hidden' name='csrfmiddlewaretoken' value='871Y71JyfG9WcieiKr8jjwe4j37IkIfq' /></div>
<input name="next" type="hidden" value="/" />
<input type="hidden" name="language" value="en" />
English
</form>
</li>
<li>
<form name="setLangde" action="/i18n/setlang/" method="POST"><div style='display:none'><input type='hidden' name='csrfmiddlewaretoken' value='871Y71JyfG9WcieiKr8jjwe4j37IkIfq' /></div>
<input name="next" type="hidden" value="/" />
<input type="hidden" name="language" value="de" />
Deutch
</form>
</li>
</ul>
I would guess that you keep language setting in the session, and when user logs out, session is gone and you're back to default lang.
OK. So here's the answer. I thought I'd write it down since someone else CAN end up in this situation.
The problem was that I had switched the order between django locale middleware and the middleware own my own that takes away the brwoser selected language. Need to keep your own interception before Django takes it over and sets the language to whatever the browser tells it to (which is a really weird default behavior in any case).
Hope it helps someone.
'myapp.middleware.ForceDefaultLanguageMiddleware', # <-- BEFORE django locale!!
'django.middleware.locale.LocaleMiddleware',
I'm trying to do some pretty basic form posts with Django, but whenever I try to click on the button to submit the information nothing happens. No errors or messages of any kind show up in terminal or in developer in Chrome. There is no JS on this page just straight html:
<form method="post" action="/">
{% csrf_token %}
<input type="text" id="name" name="name"/>
<input type="text" id="password" name="password"/>
<input type="button" value="Sign Up!"/>
</form>
My view for this page is pretty straightforward as well:
def sign_up(request):
return render_to_response('portal/signup.html', context_instance=RequestContext(request))
I'm really baffled as to what is going on, I've been following this to learn authentication. Everything works but I thought adding a "create user" would be a next step. I can't seem to get any form of any kind to work on other pages as well.
Any help would be great, I'm going crazy!
I think that your problem is that you're using
<input type="button" value="Sign Up!"/>
instead of
<input type="submit" value="Sign Up!"/>
the input submit will send all the form data to the server, the input button won't.
You can learn a little bit more about forms here : http://www.w3schools.com/html/html_forms.asp