Is there another way of passing a record-id to a method
a) without it appearing in the URL?
b) without the user being able to fathom-out how to attach which id to
which URL?
As each link contains row-id, I guess there is nothing to stop someone
from getting the id from the page source-code. Is it safe to use the
above href method if I test for authorised credentials (user/password
stored as session variables, perhaps?) before performing the edit/delete
action?
I am currently using CherryPy 3.2, but I guess the theory could apply to
any HTTP framework or web app..
Any help would be appreciated.
Alan Harris-Reid
> I have a web-page where each row in a grid has edit/delete buttons to
> enable the user to maintain a selected record on another page. The
> buttons are in the form of a link with href='/item_edit?id=123', but
> this string appears in the URL and gives clues as to how to bypass the
> correct sequence of events, and could be risky if they entered the URL
> directly (especially when it comes to deleting records).
You should *never* use a GET request to do actions like deleting
records. You already are aware of it being risky, so don't do this. You
should use GET for getting information, and POST for modifying information.
> Is there another way of passing a record-id to a method
> a) without it appearing in the URL?
Use a POST request. Note that the user still has to select something,
and that this information is send by the browser, and hence the user can
see this information (and maybe others), and repeat the action with, for
example, a Python program.
> b) without the user being able to fathom-out how to attach which id to
> which URL?
I am not sure what you want to prevent here. If you're afraid that user
A can delete things that belong user B, than "hiding" things or making
them "hard to guess" are not going to help much. If you have several
users, you must use some login procedure (and sessions).
> As each link contains row-id, I guess there is nothing to stop someone
> from getting the id from the page source-code. Is it safe to use the
> above href method if I test for authorised credentials (user/password
> stored as session variables, perhaps?) before performing the
> edit/delete action?
Yes. But still make sure that session ids are not easy to guess, and
expire. And make very sure that session ids can't leak to others.
Moreover, each time you modify a database use POST. One could argue to
also use POST for logging out, otherwise another site might be able to
log your users out if they visit that site.
--
John Bokma j3b
Hacking & Hiking in Mexico - http://johnbokma.com/
http://castleamber.com/ - Perl & Python Development
Well, if it's really ok for them to delete records programmatically even
if it's ok for them to delete through the web site. I'd probably
encrypt the post parameters if this was a concern.
You should *never* say never, because there might be situations where
exceptions from rules are valid. This is one such cases. Making this a
post means that you need to resort to javascript to populate & submit a
hidden HTML-form. Just for the sake of a POST.
And there are people who say "you should *never* write web-apps that
only work with enabled javascript"... catch 22.
Also, your claim of it being more risky is simply nonsense. GET is a
tiny bit more prone to tinkering by the average user. But calling this
less risky is promoting security by obscurity, at most.
Diez
You can populate an invisible HTML-form with the values, and submit that
- of course you need javascript for this.
But this doesn't increase security a bit. Using an extension to FF such
as HTTP live headers, it's easy enough to figure out what parameters are
passed, and simply forge a request.
> b) without the user being able to fathom-out how to attach which id to
> which URL?
Paul already mentioned that - you can create a server-side,
session-stored action-item that is identified by a hash of some sort.
Then use that hash as parameter.
But I'd say you should instead make sure that your serve actions perform
authorization checking before performing any operations. Then you don't
need to worry - even guessing a hash argument won't work then.
>
> As each link contains row-id, I guess there is nothing to stop someone
> from getting the id from the page source-code. Is it safe to use the
> above href method if I test for authorised credentials (user/password
> stored as session variables, perhaps?) before performing the edit/delete
> action?
You should of course always do that. Every http-action except login
should be guarded (unless you allow anonymous access of course).
Diez
GET parameters also tend to get recorded in the http logs of web proxies
and web servers while POST parameters usually aren't. This was an
annoyance in a web chat package I fooled with for a while. Because the
package sent user messages by GET, if I ran the software the way the
developers set it up, the contents of all the user conversations stayed
in my server logs. I was unable to convince the chat package
maintainers that this was a bug. I ended up doing some fairly kludgy
hack to prevent the logging.
If somebody happens to have access to a proxy & it's logs, he can as
well log the request body.
Don't get me wrong, I don't want to propagate the use of GET as one and
only method for parameter passing. But whatever is transmitted clear
text over the wire is subject to inspection of all hops in between. Use
SSL if you bother.
Diez
I'm not talking about a malicious server operator. In this situation, I
was the server operator and I didn't want to be recording the
conversations. I had to go out of my way to stop the recording. SSL
doesn't help and in fact I was using it, but web server logging happens
after the SSL layer. I suppose SSL would help against a malicious
proxy.
Many people back in those days (before AJAX became a buzzword du jour)
wanted to do encryption on the client in java or javascript, but that
was almost unworkably kludgy, and SSL was the only approach that made
any sense. It might be easier now that the javascript API's are richer
and the interpreters are faster.
Well, we actually implemented POST-parameter logging (inside the
WSGI-app), because we *want* all parameters users pass. They end up in
the application anyway, and aid debugging. Of course we blind sensitive
parameters such as passwords & creditcard numbers.
Of course only information not gathered is really safe information. But
every operation that has side-effects is reproducable anyway, and if
e.g. your chat-app has a history, you can as well log the parameters.
Diez
No I can't. The chat-app history would be on the client, not the
server, so I'd have no access to it. Put another way: as server
operator, I'm like the owner of a coffee shop. I can't stop patrons
from recording their own conversations with each other, and it's not
even really my business whether they do that. But it would be
outrageous for the shop owner to record the conversations of patrons.
Which is the exact thing that happens when you use an email-provider
with IMAP. Or google wave. Or groups. Or facebook. Or twitter. Which I
wouldn't call outrageous.
This discussion moves away from the original question: is there anything
inherently less secure when using GET vs. POST. There isn't.
Users can forge both kind of requests easy enough, whoever sits in the
middle can access both, and it's at the discretion of the service
provider to only save what it needs to. If you don't trust it, don't use it.
Diez
Those are not comparable. IMAP is a storage service, and groups,
facebook, and twitter are publishing systems (ok, I've never understood
quite what Google Wave is). Yes, by definition, your voice mail
provider (like IMAP) has to save recordings of messages people leave
you, but that's a heck of a lot different than your phone carrier
recording your real-time conversations. Recording live phone
conversations by a third party is called a "wiretap" and doing it
without suitable authorization can get you in a heck of a lot of
trouble.
> This discussion moves away from the original question: is there
> anything inherently less secure when using GET vs. POST. There isn't.
Well, the extra logging of GET parameters is not inherent to the
protocol, but it's an accidental side effect that server ops may have to
watch out for.
> Users can forge both kind of requests easy enough, whoever sits in the
> middle can access both,
I'm not sure what you mean by that. Obviously if users want to record
their own conversations, then I can't stop them, but that's much
different than a non-participant in the conversation leaving a recorder
running 24/7. Is that so hard to understand?
Interception from the middle is addressed by SSL, though that relies on
the PKI certificate infrastructure, which while somewhat dubious, is
better than nothing.
> and it's at the discretion of the service provider to only save what
> it needs to. If you don't trust it, don't use it.
I certainly didn't feel that saving or not saving client conversations
on the server side was up to my discretion. When I found that the
default server configuration caused conversations to be logged then I
was appalled.
Do you think the phone company has the right to record all your phone
calls if they feel like it (absent something like a law enforcement
investigation)? What about coffee shops that you visit with your
friends? It is not up to their discretion. They have a positive
obligation to not do it. If you think they are doing it on purpose
without your authorization, you should notify the FBI or your
equivalent, not just "don't use it". If they find they are doing it
inadvertently, they have to take measures to make it stop. That is the
situation I found myself in, because of the difference in how servers
treat GET vs. POST.
> Am 03.02.10 19:11, schrieb John Bokma:
>> Alan Harris-Reid<al...@baselinedata.co.uk> writes:
>>
>>> I have a web-page where each row in a grid has edit/delete buttons to
>>> enable the user to maintain a selected record on another page. The
>>> buttons are in the form of a link with href='/item_edit?id=123', but
>>> this string appears in the URL and gives clues as to how to bypass the
>>> correct sequence of events, and could be risky if they entered the URL
>>> directly (especially when it comes to deleting records).
>>
>> You should *never* use a GET request to do actions like deleting
>> records. You already are aware of it being risky, so don't do this. You
>> should use GET for getting information, and POST for modifying information.
>
> You should *never* say never, because there might be situations where
> exceptions from rules are valid. This is one such cases. Making this a
> post means that you need to resort to javascript to populate & submit
> a hidden HTML-form. Just for the sake of a POST.
Make each edit/delete button a submit button and optionally style it.
> Also, your claim of it being more risky is simply nonsense. GET is a
> tiny bit more prone to tinkering by the average user. But calling this
> less risky is promoting security by obscurity, at most.
Maybe you should think about what happens if someone posts:
<img src="http://example.com/item_delete?id=123"> to a popular forum...
>> Also, your claim of it being more risky is simply nonsense. GET is a
>> tiny bit more prone to tinkering by the average user. But calling this
>> less risky is promoting security by obscurity, at most.
>
> GET parameters also tend to get recorded in the http logs of web proxies
> and web servers while POST parameters usually aren't.
More significantly, they'll appear in the Referer: header for any link the
user follows from the page, so they're visible to anyone who can get a
link to their site onto the page (whether <a href=...>, <img src=...> or
whatever).
Even if this isn't possible at the moment, will you remember to fix it the
first time you allow an off-site link?
You should assume that anything which goes into a GET request is visible
to the entire world. Don't put anything even remotely private in there.
Is it so hard to understand that this is not about laws and rights, but
about technical properties of the HTTP-protocol?
Your web-based chat uses HTTP, no P2P-protocol, and thus the service
provider *can* log conversations. I don't say he should, I don't say I
want that, I don't say there are now laws that prevent them from doing
so, all I say is he *can*.
> I certainly didn't feel that saving or not saving client conversations
> on the server side was up to my discretion. When I found that the
> default server configuration caused conversations to be logged then I
> was appalled.
Then stop logging. Or get a hosting-provider that allows you to
configure it to strip QUERY_STRINGS from log-entries. And if they refuse
to, maybe using POST solves the issue.
But wait, there is
http://www.cyberciti.biz/faq/apache-mod_dumpio-log-post-data/
So what if they run that?
So, for the umpteenth time: data sent over the wire can be recorded.
From the user's POV, your nitpicking of who's the actual culprit - the
IT-guys, or the programmers - is fruitless. You have a nice anecdote
where switching from GET to POST allowed you to trick whoever wasn't
acting to your wishes. Good for you. But John B. and your posts indicate
that using POST is inherently more secure. It *isn't*.
> Do you think the phone company has the right to record all your phone
> calls if they feel like it (absent something like a law enforcement
> investigation)? What about coffee shops that you visit with your
> friends? It is not up to their discretion. They have a positive
> obligation to not do it. If you think they are doing it on purpose
> without your authorization, you should notify the FBI or your
> equivalent, not just "don't use it". If they find they are doing it
> inadvertently, they have to take measures to make it stop. That is the
> situation I found myself in, because of the difference in how servers
> treat GET vs. POST.
If they have a positive obligation not to do it, it doesn't matter if
they run their service over GET or POST.
Again, this is not about laws and what service providers should or must
do. It's about POST vs. GET, and if either of them is more secure or
not. It isn't.
Diez
*slap* Yep, you are right, no JS needed. I should have thought about that.
>
>> Also, your claim of it being more risky is simply nonsense. GET is a
>> tiny bit more prone to tinkering by the average user. But calling this
>> less risky is promoting security by obscurity, at most.
>
> Maybe you should think about what happens if someone posts:
> <img src="http://example.com/item_delete?id=123"> to a popular forum...
And the difference to posting
from urrlib2 import open
from urllib import encode
open("http://example.com/item_delete", data=encode([("id", "123")]))
to that same public "hacker" forum is exactly what?
If your webapp happens to allow item_delete to be called without
authentication & authorization, then *that's* your problem.
Diez
You mean like
http://www.google.de/search?q=dirty+buttsex
? Which is the key example for when to use GET - non-modifying queries.
I agree though that you have to be cautious about that, and using POST
makes it easier to do so.
Diez
Basic HTTP stuff - this is definitely not Python-related.
<OT>
Do yourself (and your users / customers / etc) a favor and read the HTTP
rfc. "GET" requests should NOT modify the server state. At least use
"POST" requests for anything that Create/Update/Delete resources.
For the record, someone once had serious problems with GET requests
deleting records - turned out to be a very bad idea when a robot started
following these links...
</OT>
> Is there another way of passing a record-id to a method
href="/item/23/edit"
href="/item/edit/23"
etc
> a) without it appearing in the URL?
> b) without the user being able to fathom-out how to attach which id to
> which URL?
Wrong solution. The correct solution is to
1/ make correct use of the request method (GET and POST at least).
2/ make sure the user performing the action has the permission to do it.
1/ won't protect your data from malicious users, but will at least avoid
accidental mistakes.
2/ by checking the user's perms when handling the POST request of course
- not by hidding "forbidden" urls.
> As each link contains row-id, I guess there is nothing to stop someone
> from getting the id from the page source-code.
Nor even from trying any other id (brute-force attack).
> Is it safe to use the
> above href method if I test for authorised credentials (user/password
> stored as session variables, perhaps?) before performing the edit/delete
> action?
cf above.
> I am currently using CherryPy 3.2, but I guess the theory could apply to
> any HTTP framework or web app..
Indeed.
</OT>
Sure, my complaint is that the default setup caused this to actually
happen so lots of people using that software were recording user
conversations without realizing it and maybe without caring. This
is a bad erosion as I see it.
> Then stop logging. Or get a hosting-provider that allows you to
> configure it to strip QUERY_STRINGS from log-entries. And if they
> refuse to, maybe using POST solves the issue.
I did stop logging. There wasn't an issue with the hosting provider
since I was running the server myself. But I had to resort to some ugly
software kludge to stop logging those particular strings. More
frustratingly, I filed a bug report about the issue against the chat
software but the conversation was sort of like the one you and I are
having now. I just couldn't convince them that there was a problem and
that they should change the default.
> http://www.cyberciti.biz/faq/apache-mod_dumpio-log-post-data/
> So what if they run that?
That sounds like something someone would have to go out of their way to
install and use. It's not the default. Of course if someone is
malicious they can do all sorts of nasty stuff. A coffeeshop that
wanted to mess with me on purpose wouldn't have to do high tech crap
like recording my conversations--they could just poison my coffee. I
have to trust them to not do this on purpose, but then I see a situation
where their coffee sweetener accidentaly has a harmful chemical, so of
course I'd ask them to do something about it.
> So, for the umpteenth time: data sent over the wire can be recorded.
And for the umpteenth time, I'm less concerned about "can be" than "is".
POST isn't logged unless you go to some lengths to have it logged. GET
is logged unless you go to some lengths to prevent it. It's not enough
in a software deployment to only consider what actions are possible.
It's important to make sure that the default actions are the right ones.
> If they have a positive obligation not to do it, it doesn't matter if
> they run their service over GET or POST.
GET makes it harder for them to fulfill their obligations. As a
security nerd, I saw what was happening and took measures against it,
but a more typical operator might never notice or care.
There is also the matter of the referer header which an anon mentioned,
though it didn't apply to this particular situation because of how
the application worked.
There's also the issue that a user can change "123" to "125" and
possibly mess with someone else's resource, unless you use some server
side authentication. Or just seeing how often the numbers change could
reveal patterns about what other users are doing. I always think it's
best to encrypt anything sensitive like that, to avoid leaking any info.
Oh yes ?
> Making this a
> post means that you need to resort to javascript to populate & submit a
> hidden HTML-form.
I beg your pardon ???? This is total nonsense. Hopefully you don't need
any js to emit a post request from a browser ! The only thing you need
to do is to use a form and submit input instead.
What I said IIRC.
> Or just seeing how often the numbers change could
> reveal patterns about what other users are doing. I always think it's
> best to encrypt anything sensitive like that, to avoid leaking any info.
Depends on how "sensitive" it really is.
Sorry, posted too fast, John alredy adressed this.
A lot will depend on the terms of service of the network supply
contract. Most vendors take pains to ensure that such "innocent" logging
(i.e. the maintenance by their servers of logging information, which may
under subpoena or similar legal coercion be given up to law enforcement
authorities as "business records") is permitted. If you have signed the
contract, then they have the right to log that data.
Caveat emptor.
regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
PyCon is coming! Atlanta, Feb 2010 http://us.pycon.org/
Holden Web LLC http://www.holdenweb.com/
UPCOMING EVENTS: http://holdenweb.eventbrite.com/
> Am 04.02.10 01:42, schrieb John Bokma:
[..]
>> Maybe you should think about what happens if someone posts:
>> <img src="http://example.com/item_delete?id=123"> to a popular forum...
>
> And the difference to posting
>
> from urrlib2 import open
> from urllib import encode
>
> open("http://example.com/item_delete", data=encode([("id", "123")]))
>
> to that same public "hacker" forum is exactly what?
Imagine that a user of example.com, logged in at example.com (i.e. with
a valid session ID in a cookie), visits the aforementioned (by me)
forum, and that he has an item 123. It will be deleted.
> If your webapp happens to allow item_delete to be called without
> authentication & authorization, then *that's* your problem.
You now understand that *with* a & a a GET request can be *still* harmful?
The webapp must be actually preventing the processing of GET-requests
for the aciton in question. This isn't the case by default for many of
them, in fact at least e.g. TurboGears, as well as PHP offer you ways to
treat GET and POSTvars the exact same way. So unless the programmer is
aware of this potential problem, it won't help.
And in the same way one can embed a form with a post-action that leads
to the full http://example.com-url into an external page. So it is
equally as dangerous. Yes, links are easier, no doubt about that. But
POST doesn't magically make you safe from those kinds of attacks.
The only way to prevent this are short-lived sessions, or action-tokens
of some kind, as Paul mentioned before.
Diez
Regards,
Alan