I have blog comment forms in Django and I would like to know the following:
Should I add CSRF to the forms?
If I want to use the simple "render_comment_form" method, how do I add it?
If I can't add it like that, what is the best practice for doing it?
Each tutorial or discussion on the subject seems to have a different approach, and I am not certain I understand how it all works.
My answer assumes that you are using Django 1.2:
Yes! You should protect all your data that is sent by POST requests to the server against CSRF attacks.
You don't need to add the token yourself. This is already done by django. Have a look at the default template that is used by the render_comment_form tag and you will see, that the csrf_token is already included. You can overwrite this template in your project and including the CSRF token into it is as easy as writing {% csrf_token %} into the form.
There is a way to protect your forms even if you don't set the tokens in the templates. Have a look at django's documentation about that topic. But this method is marked as a legacy method so it's not recommended to use that - it's only provided for backwards compatibility with versions of Django earlier than 1.2.
Related
Lets say, in a view, I use input data to create an instance of a Model in my Django project.
def create_post(request, message):
post = Post.objects.create(message=message)
post.save()
Now, the problem is, the 'message' is coming from sources which may be unsavory, that is, a plugin that makes AJAX requests to my API. If it was a django form, I could have just used {% csrf_token %} and cleared the issue, but, I want to do this in my view. How do I do this?
Note, please don't suggest adding csrf protection in my Javscript code, because that will not work for my case.
Thanks!
Are there any real reason to use builtin forms in django?
One of them as I understand is validation. Ok. And maybe some convinience (but not for me).
Anything else?
Is there any acceleration in site work with forms?
From Django documentation -
While it is possible to process form submissions just using Django’s
HttpRequest class, using the form library takes care of a number of
common form-related tasks. Using it, you can:
Display an HTML form with automatically generated form widgets.
Check submitted data against a set of validation rules.
Redisplay a form in the case of validation errors.
Convert submitted form data to the relevant Python data types.
Also django forms provide some level of security by enforcing CSRF.
Some of the cool things you can do with django forms
I agree that in some circumstances, the temptation to avoid the use of Django form is very strong.
If I need just one field with no validation nor style, why should I define a django-form?
HTML:
<form method='POST' action='url_to_my_view'>
Type something: <input type='text' name='any_value'/>
</form>
Django:
<form method='POST' action='url_to_my_view'>
{{ form }}
</form>
with the overhead of defining the form and including it in the view.
But I still use Django-forms: experience tells me that software shortcuts always lead to problems...
The more built-in forms, the less work for developers. You are free to implement them from 0 but it is always faster to use something that is already done and tested.
Anyway, you have something in the middle: inherit from built-in forms and customize them.
Does django have a user editable templating language that is secure like rails has liquid?
i.e. a end user can't hack template code to somehow output dangerous objects and hack the website.
If you're using the template language the right way: yes.
See Django template tags and filters:
http://docs.djangoproject.com/en/1.2/ref/templates/builtins/#escape
http://docs.djangoproject.com/en/1.2/ref/templates/builtins/#autoescape
http://docs.djangoproject.com/en/1.2/ref/templates/builtins/#escapejs
An example:
{{ evil_userinput }}
This will print out the users input directly.
{{ evil_userinput|escape }}
This will escape all HTML entities an so it isn't possible to include dangerous code in your HTML page.
Liquid has originated from Django templating language, so the answer is yes. You can render user submitted templates and process them the way you want. Security however is something that developers should concern. Templating tools won't protect you if you want to let your users shoot you in the foot unless you sanitize and validate their input.
Here are a few good reads:
http://www.djangobook.com/en/2.0/chapter04/
http://www.djangobook.com/en/2.0/chapter09/
http://loopj.com/2009/05/23/a-django-developers-views-on-rails/
I just started to use django. I came across forms and I need to know which one is the better way to validate a forms. Would it be using django forms or should we use javascript or some client side scripting language to do it?
You should ALWAYS validate your form on the server side, client side validation is but a convenience for the user only.
That being said, Django forms has a variable form.errors which shows if certain form fields were incorrect.
{{ form.name_of_field.errors }} can give you each individual error of each field that's incorrectly filled out. See more here:
http://docs.djangoproject.com/en/dev/topics/forms/
There's a pluggable Django app (django-ajax-forms) that helps validate forms on the client side through JavaScript. But as AlbertoPL says, use client side validation only as a usability measure (e.g. telling a user that his desired username is already taken without reloading the registration page). There are all kind of ways to sidestep client side validation, in most cases as simple as deactivating JavaScript.
Generally speaking: presume all data coming from the outside as faulty until validated.
Just came accross django-floppyforms, which seems to do clientside validation by default. They use HTML5 which supports clientside validation by default. Not sure if they also use javascript though if the browser doesn't support HTML5. Haven't tried it myself yet.
Link to django-floppyforms: Documentation and Github
If you are using bootstrap then you can simply add required attribute in forms field. For example if there is programe field then you can validate it like:
In forms.py:
programme = forms.ChoiceField(course_choices,required=True, widget=forms.Select(attrs={'required':'required'}))
Note: It requires to link to bootstrap files in your .html page of that form.
You will need to do this is JS. This app integrates forms with parsley.js to tag the forms with correct data-* attributes automatically.
I would like to give users access to delete a model instance that they added to the db. In the django docs it says allowing someone to delete from the template is not a good practice. Is there a secure way to let a user click a "delete this" link from the template and remove that model instance? How should I go about doing that?
Check out this question for discussion related to what you are asking about.
Essentially, when you normally click on a link on the page the browser makes a GET request to the server to get the next page's contents. Just like there is a lot of pushing towards semantically relevant CSS layouts, it is also important that your page requests are semantically relevant. The problem with using links to remove items is that it is making a GET request to DELETE something in the database. From this comes the problem that some search engines might index your links and accidentally erase content. There also comes the problem of cross-site request forgeries which can make an unsuspecting user make a command to a website without being aware. So the proper way to handle this is by following the rule that any request that modifies state in the server should be processed via POST. As such, instead of doing this:
Delete Item
It is better to do this:
<form action='{% url remove_item %}' method='POST' id='form'>
<input type='hidden' name='action' value='delete'>
<input type='hidden' name='id' value='{{ item.id }}'>
<input type="submit" value="Delete Item">
</form>
If you would like to keep your links while maintaining the POST, you'd have to resort to Javascript:
Delete Item
Unsightly, yes, but it's for the best. Your Django view would then do something like this:
def remove_item(request):
if request.method == 'POST':
## remove item
Furthermore, as Scott mentions, Django has some built in stuff to help you avoid the cross-site request forgeries I mentioned above, since it is still possible to do it even if you are doing a POST (just slightly harder). The way to avoid this is to have some kind of token tied to the form that needs to be validated server side before allowing the action to be taken. Check out the CsrfMiddleware class for more details on that. It will essentially automate some of that work out of it for you.
Additional Reading
URIs, Addressability, and the use of HTTP GET and POST
9.1.1 Safe Methods, HTTP 1.1, RFC 2616
Architecture of the World Wide Web, Volume One
Using POST with a regular link
Cross-Site Request Forgeries and You
Have the user submit a POST request to delete that model instance. These kinds of changes should never be possible via GET requests, so that people can't link each other to unwittingly performing changes on the site.
In your view, check that request.user is the same as the author of that particular model instance. You could also check that the HTTP_REFERRER is not set to another site if you were really worried.
Your security issue here is Cross Site Request Forgery. Django provides CsrfMiddleware which will actually add security to your forms to prevent this kind of attack. But it only works as long as you're not allowing permanent changes to take place via GET requests.