Monday, July 6, 2015

Re: Django formset hidden id field

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQIcBAEBCAAGBQJVmsyMAAoJEC0ft5FqUuEhbdkP/jJXIMWgllrYUpyiREhYsk91
Hpc9St1YAxb92RYtKW1HK9iYoaFSWgTlOh+bkWpxlhfaDrlR8+bOj5E+l9tf2Yu7
O+m5pOG2eBPQUlhIxoG1VDAgESnoX52n03RgxeTQtTybqxzlnUqpnh4xbxf6OLiN
FCPMZPUfTbqL8mvCxoGuS+ivzpzdCojdxOiMAovQCEnGrGBWVyVLPU96J+TIk4Ax
k9019gjkOikyLsha9oxI4aRiuPcNx/6URwY40zaC/N+j9ddFz+7m6j5AY92Ghjyv
IlPO6oTh49bTX898sC80dzebP+wSDrYUTpRNvHnLfKZDl09FuggqcAKpMW7nM+8G
hzBLsxEv6WdfgYK8viE55we3Zd/5falotOgGWS9q27Na+ZgR0NrYj3yiFW+jORnM
cwq0bWOhoFhTI+mf9jZiwx6Ta9G0WC+GgxKQw/5ioFrb0dbgH3ldhtuSQltggABj
8//IOho211K1uY2Bp1RsyPmA/LSslA7czy5HaQORbT4HK9YtxsPw2dhdsL4mHZB5
Ael1S/8qpWzJdpEwSEDck8wPXR4KgSHIHkteWagn9nFyzCVWASNWSQXXcT7KKrt8
QpBMbZaIuceDWcJAb8+IDwV+RMM7egNalfv9p6/b8PtvmTdoD7rvqoUVMBjjIisP
e+7+jqsFgKwvRvPh3YPh
=fZcD
-----END PGP SIGNATURE-----
Hi Peter,

On 07/04/2015 12:42 AM, Peter of the Norse wrote:
>> On Jul 2, 2015, at 7:46 PM, Carl Meyer <carl@oddbird.net> wrote:
>>
>>> So what? It's quite likely that whoever is editing this row of
>>> the database, also has permissions to edit the other rows as
>>> well. There's no reason for them to go through the hassle of
>>> manually editing a hidden field when they can go to a different
>>> page and edit it there.
>>
>> That's a bad answer. It's common in many systems for a user to
>> have access to edit some records in a table but not others (this is
>> often known as "object-level permissions"). If it was really
>> possible to edit any row in the table by just manually editing the
>> PK hidden field, that would be a serious security flaw in
>> formsets.
>>
>> But it's not. Whatever queryset you pass to the model formset
>> limits the available rows for editing. The end user can edit the PK
>> to refer to any item in that queryset, but not any item in the
>> table.
>>
>>> In general, primary keys are not security flaws. While it's a
>>> good idea to hide them from front-end pages, that's mostly
>>> because they make URLs hard to read. I have heard that you don't
>>> want to use them publicly, because your competitors can use them
>>> to gauge your success, but that's the kind of "Nice Problem to
>>> Have" that can wait until you're bigger.
>>
>> Exposing primary keys themselves (e.g. in URLs) is not necessarily
>> a security flaw. Exposing a primary key in a hidden field that can
>> be edited to change a form to edit any row in a table often would
>> be a serious security flaw.
>
> You can't have it both ways. Either exposing the PK is a security
> flaw or it isn't. It's just as easy for nefarious n'er-do-wells to
> edit the form's URL as a hidden field. In either case, if you are
> using object-level permissions, more checks (not made automatic in
> Django) are necessary. Having the ID passed as a parameter doesn't
> necessitate, hinder, or alleviate running these checks.

Yes, this is a good clarification, thanks. What I meant to say is that
simply exposing the ID information to the user isn't necessarily a
security issue. But any server-side use of a client-provided ID (whether
provided in the URL or in a form field) needs to be properly validated
on the server side (just like any other data received from the client).
Formsets do this validation; if they didn't, they would be insecure.

My main point is that it's not at all adequate to say that "if a user
has access to edit one object, they probably have access to edit all the
others anyway." They may or they may not; that's application-specific.
Formsets allow the developer to specify exactly what queryset of objects
the user should be allowed to edit via the formset, and they validate
that the user can only edit those objects, and no others (even if the
hidden ID field is manually modified.)

> If you can come up with a method that associates form data with a
> database row that doesn't involve the PK, I would love to know. Keep
> in mind that most tables only have the one unique identifier.

I'm not saying that you shouldn't use unique IDs to associate form data
with rows in the database (though there are some valid reasons to prefer
e.g. a UUID or a unique slug to an auto-incrementing ID in some cases).
I'm just saying that you should never trust an ID value (or any data)
coming from the client; you should ensure on the server side that the
user actually should have access to the object they are trying to access.

Javier showed a good method for doing this in typical cases, by passing
a limited queryset rather than a model class to get_object_or_404.

Carl

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at http://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/559ACC8C.8000104%40oddbird.net.
For more options, visit https://groups.google.com/d/optout.

No comments:

Post a Comment