Question

The Django documenation seems to be very explicit that a POST must be redirected. I'm new to all of this, and when I deploy I'm not eager to be hacked. My question is: is the following view exploitable? I redirect when the post.cleaned_data is valid. Do I also need to redirect when it is not valid? Additionally, does a "recursive" view like this contain any security weaknesses?

def detail(request, blog_id):
    b = get_object_or_404(Blog, pk=blog_id)
    if request.method == 'POST':
        form = CommentForm(request.POST)
        if form.is_valid():
            poster = form.cleaned_data['poster']
            comment = form.cleaned_data['comment']
            comment_date = timezone.now()
            b.comment_set.create(poster=poster, comment_date=comment_date, comment=comment)
            return HttpResponseRedirect(reverse('blog:detail', args=(b.id,)))
        else:
            return render(request, 'blog/detail.html', {
                'blog': b,
                'form': form,
                })
    form = CommentForm()
    return render(request, 'blog/detail.html', {
            'blog': b,
            'form': form,
        })

Additionally, for those with experience with testing, would you mind describing what steps I should take to fully test this view? I know how to test status codes. I have also tested the post method, and would like to know how to view the whole chain of redirects (e.g. The post gets called, and returns an HttpResponseRedirect but self.client.post stops there, and I want to continue through the next call where it recursively returns the get request at the end of the view. Thanks for your input in advance.

Was it helpful?

Solution 2

When the form is invalid, you need to render the view again, when you pass the same form object, it will display errors automatically, so no redirection in this case, this is how you make your view more clean:

def detail(request, blog_id):
    b = get_object_or_404(Blog, pk=blog_id)

    if request.method == 'POST':
        form = CommentForm(request.POST)
        if form.is_valid():
            poster = form.cleaned_data['poster']
            comment = form.cleaned_data['comment']
            comment_date = timezone.now()
            b.comment_set.create(poster=poster, comment_date=comment_date, comment=comment)
            return HttpResponseRedirect(reverse('blog:detail', args=(b.id,)))
    else:
        form = CommentForm()

    return render(request, 'blog/detail.html', {
            'blog': b,
            'form': form,
        })

Regarding tests, to go through the redirect, you need to add follow argument in the post method (it's set to False by default):

c.post('/login/', {'name': 'fred', 'passwd': 'secret'}, follow=True)

OTHER TIPS

Redirecting after a successful post is nothing Django-specific - it's just GoodPractice for any web application whatever the language / techno. And there's not much of a "security" issue here, you just want to avoid the user posting the same thing again and again if he refreshes the page.

As is, your view is almost the canonical edit_or_create view - cf mariodev's answer for an improved code layout, but from a purely functional POV that's the very same thing.

How to test redirects etc is fully documented.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top