All new Registrations are manually reviewed and approved, so a short delay after registration may occur before your account becomes active.
php security experts...submitting forms safely
Let's say I have a form that looks like this:
<form action="/script.php" method="post"> <input name="my_input" length="80" /> <input type="submit" value="submit" /> </form>
Now I also want to include a numeric identifier - call it a ticket id. "Here's the ticket history, do you want to add something?" The user can't modify that.
My question is...what is the safest way to get that ticket id in the form submission?
No problem accomplishing it, but my question is around security. So here are the ways to get a variable back that I can think of:
<form action="/script.php" method="post"> <input name="my_input" length="80" /> <input type="hidden" name="ticket_id" value="12345" /> <input type="submit" value="submit" /> </form>
or
<form action="/script.php?ticket_id=12345" method="post"> <input name="my_input" length="80" /> <input type="submit" value="submit" /> </form>
I'm concerned that someone could craft a malicious POST and submit it and append their comments to a different ticket. i.e., compose a POST from their own server/browser/tool. If I was doing this with GET then they certainly could do that just by changing the url vars - it's possible to do that also with POST too, right?
I can check that the user owns that ticket of course and do some other validation, but fundamentally, how do you present data to a user and safely get it back again in an HTML form?
Is there something other than creating a unique serial number ("FORM 12345 should present ticket id 6789") record on the server side and then checking it back?
I'm using PHP & MySQL on the backend though I'm not sure my question is specific to those technologies.
Comments
@joepie91
cPHP actually has a framework built in which generates random hashes for variable names and decodes them on the other side. It's quite good +
Anyway on the PHP side simply check that the currently logged in user owns the ticket being replied to before processing it any further. If the ticket id and the user id don't match die();
Yeah, I get the ticket # back and if the ticket isn't owned by the user, bail. And if the user does own the ticket, make sure he's not trying to force a reply to a closed ticket, etc.
But I was wondering about this in general...how do you safely present data to a user and get it back? I'm thinking I have to do some kind of form-id-stamp and keep track of it on the server side.
This. Just include the ticket ID in the form data or the URL, and check whether the user can actually post to that ticket, server-side. Anything client-side can be modified, so you shouldn't trust it.
And you should indeed look into CSRF protection (which was what @BlueVM was refering to with regards to CPHP). This is a probably a good resource to read about this, or you could use a framework that provides CSRF protection by itself.
You don't. At best you can store stuff in the session superglobal, but there's limited use for that.
EDIT: And I should mention that it's a very bad idea to store anything related to a 'state' of a certain request, in the session superglobal. If you do something like saving the currently viewed ticket into a session variable, and the user loads two different tickets, then all replies on both pages will go to the ticket that was opened last. Don't do it.
@raindog308: You are describing a CSRF attack. So yes, one of the methods is to create a unique serial number/token that is sent in every form request and must match what you have on your end on post before processing.
My other recommendation is to use a web framework stack. Really. Trust me, it saves you a lot of headache. The established ones usually will handle session/cookies, CSRF token generated, post validation and properly escapes the form data, that all you really need is to check that your user has access/is owner to the ticket, and voila, save the new data.
If it was me, I will always validate if user owns it. I want to treat server code as a separate entity, validate all things that were already validated in client side, and trust nobody.
for your concern, how about a symmetrical encode/decode thing?
My suggestion, keep your original logic the same, to keep things simple. And attack this using filters or interceptors, something like that. so that its a separate code that handles this, and not your business logic code.
Let me share my experience here. This is what I have done.
At the backend, I verify if the ticket is correct by these lines:
That does not protect against CSRF attacks.
what about checking session?
As @joepie91 & @jcaleb mentioned. That does not work @seikan. You have to use
sessions
. Plus, thetoken
can be random. It is only to validate that your app produced the submitted form.Use a database and check everything server side? :P (And spit it all out from the db?)
intval is what you might be interested in for integer casting. (make sure you check for negatives or whatnot before insertion/etc)
Hope this helps
Yeah, I hear you. This is actually something that hooks into MyBB for user authentication/management, but not a forum interaction, so their post_key system isn't available.
I can store a unique form token (unique to each form presentation) in the DB along with what variables are supposed to be present and their values, then check the id and the vars when I get it back. Is that sufficient to protect against CSRF?
I'd like to use CodeIgniter, CakePHP, etc. but it's nice to have people login once without having to have a separate system, hence the custom code.
If you are going to store the values in the database anyway, then why are you taking input from the form data?
Oh. Yeah. :-)
I guess all the form needs is a token.
..randomly generated new ticket ID? Erm..ok. In a system that was coded by a fourth grader and doesn't work off a logged in..eRM, WELL, alright because it sounded like a fun question?
Yes. Tokens are good. Validation is good. Sanitization is good. Frameworks are good, libraries for form handlers et all usually take care of all of this..
Old. And too hypothetical. I'd rather worry about whether or not the Earth's core will stop spinning.
You're saying don't use sessions because they could be poorly managed.
Good session management is the key here. Thousands of scripts on every major site on the Internet rely on solid session and cookie management to solve all of these problems. I don't even think this was a real question.
What were you guys really trying to test or inquire about by asking this...Comon now you can tell me..
Only well reasoned thought here. Howabout, wait for it...proper table relationships! You guys ever hear of a pumpkin table? This is programming 101. Yeah Yeah CSRF, Session stealing, LDAP injection, Path traversal and Buffer overflow Oh My!
Is this what some one called my signature charm. /Sigh..Makes me want to jump out a f***in window.
I am logged into Google @natestamm and only getting "Goatse Tool" results.
Could you elaborate on this, if possible, please ?
...with cherries on top.
@natestamm What's a pumpkin table when it's at home?
Use mt-rand instead: http://jp1.php.net/manual/en/function.mt-rand.php
Thanks @Wintereise.
Just add server side check - is currently logged client related to specific ticket number. We are trying to avoid client side check when possible, all validation stuff is done on server side.
What were you guys really trying to test or inquire about by asking this...Comon now you can tell me..
The fuck are you going on about?
Here's a very simple CSRF prevention script that doesn't require any changes to your code, just include the file and it should work: https://www.owasp.org/index.php/PHP_CSRF_Guard
It does so by caching the output from the script, and then when PHP exits it changes any forms using POST to add a CSRF token which is stored in the session.