How to secure this PHP form - php

I have a form for editing users. The user ID is passed to the client (in a hidden field) so that I know which user to update when the form is posted back to the server. My question is, how can I guard against users changing the ID in the DOM, thereby updating a record to which they should not have access?
The only ways I can think of are:
Save the user ID in the session. (Painful).
Run a salted hash on the user ID (and perhaps other form elements) and include it also as a hidden form element. (Not particularly secure?)
Are there other approaches?
Thanks!
EDIT: Hey, some great responses coming in. Note that the logged in user and the user being edited may be two different users, e.g. a Manager is editing a Staff record.

The best way to do this is to just check after submission if the user has the right to edit that user.
Don't pollute the session with this data, because it can get messy, for example when a user opens the same page multiple times.

It depends somewhat on the conditions under which the user is allowed to edit it.
At the heart of it, it comes down to:
Authenticate the user
Check if the user is authorized to make that change
Authenticating the user is usually a case of "Do the username and password match?" or "Is there an active session with a logged in user associated with it?"
Authorization depends on your business logic. It might be "Is the logged in user the same as the user being edited?" or "Does the user being edited have a manger field containing the id of the logged in user?" and so on.
In the first case, storing the user id in the session shouldn't be painful. In the second case, you just do a database lookup as one of the first things you do in the script.

Why are you relying on a hidden field for knowing which record to update? If the user is logged in you should already have the user_id of him with you on the session.
So you can just find which record to update by finding which user is logged in.

As mentioned, the fastest and painless way to sort this would be to stick the USER_ID in the session, period.
Comments saying that you "pollute" session with that information are plainly uneducated, ignore them.
The other thing I noticed in comments is the "check if the user has the rights to edit the entry" which implies there's some sort of hierarchical system in place, which seems not to be true.
Alternative to session storage would be, as you assumed already, obfuscating the USER_ID value in the hidden field somehow. You could either encrypt it, or instead of integer ID - you could use GUIDs but that has implications of its own, tho it makes it incredibly hard for someone to "guess" the correct GUID to mess around with the records.

Related

Profile data using $_GET[]

I currently have a file using $_GET['id'] = $userProfileNumber, to uniquely produce appropriate user data.
My question is: In order to make sure I redirect the user to their OWN profile should I be referencing "profile.php?=".$ownID in all profile links? Or is there an easier way? Thank you.
$ownID= id from email column upon login, used to represent logged in user.
You could store their ID in a session upon login and have profile.php get the ID from the session rather than the URL parameter using $_GET.
I would divide the answer into two major scenarios.
First scenario: The profile page is public. You are interested that each user would see the profile of his mate. In this case, I would totally agree with your way, as there are lots of users. Even here, on Stackoverflow, you can click on my profile below and witness the user id in the URL (with additional user name which is not required, just for prettiness' sake).
Second scenario: The profile page is private. It is merely intended for the use of the current logged in user. Here, I would go with the idea of Ben Fried - caching the repeated user data as a cookie or in local / session storage and pass it as a HTTP header / payload.
Security issues in this approach: you should consider an authentication mechanism. I.e generating an authenticated token on log in to be stored for a later use. In each request, validate this token and only then retrieve the desired and protected data.

Is it safe to check user login Session with GET variable?

lets say i have a session called $_SESSION['id_user']
and it stores session of the user id. Lets say that the user profile is www.example.com/profile.php?id=123
if I want to check if that profile is the user and if i do something like
if(isset($_SESSION['id_user']))
{
if($_SESSION['id_user']==$_GET['id']){print something since this is the users own profile}else{print nothing}
}
Is the above code good enought? or is their any security problem? or is it wise to compare GET variable with SESSION variable? its not printing anything that will give user identity away or anything I just want to show a (edit profile button) for the user that is visiting his own profile.
Yes, it is safe - the session is stored on the server and a user cannot change the session data manually. Unless their session is hijacked, then only they will be able to see their own profile.
For piece of mind (and to prevent possible SQL injections I'd just cast the two variables as (int)s before using them (also cuts down on having to write $_SESSION['id_user'] multiple times. I would also use === which checks the variables without any type conversions.
As mentioned in the comments by Thomas, if you've got the users ID in the session already, then unless you need to (differentiate between profiles), just use that and don't send the user ID over GET.

"Favorites" feature using cookies and sessions (PHP & CodeIgniter)

I'm trying to implement a "favorites" feature to my site and I was wondering on how to go about storing this data. What I'd like to do if possible is have the user favorite things and store it in the DB - that way I could use the data to personalize search results.
I'm also trying to have it so there is a smooth transition between favorites in a non logged in state to a logged in one (allow the user to save favorites anonymously but if logs in transfer/ask to transfer those to his account)
How would I be able to store this data for long periods of time? I'm currently using DB encrypted sessions and I was thinking of extending the session time or setting it to not expire. That would probably lead me to some security issues no?
I'd appreciate the help,
Cheers.
Well, if i understand, what you want is that a registered user can set "something" as a favorite, since this is a M:N relationship (strictly from a database point of view), i would recommend a table storing these relationships, i.e. Supposing you have a user and a topic table, the SQL would like similar to this:
create table favorite(user_id integer not null references user, topic_id integer not null references topic);
At least this is what most DB books will tell you to do. If you don't have a user table (i suppose you have one for that "something" you want to mark as favorite), you could just store the id you assign to the user whenever s/he logs into the system. Hope to have been of help.
Create actual users out of your anonymous sessions. Persist them in the database without login credentials and associate favorites or whatever else you store with their user ID. If they sign up before they clear their cookies, you just add their login/profile into to the existing user ID and all the favorites they've created are already in the right spot. One system for both logged in and logged out users, not two.

Check permissions?

How do people usually verify that the information being fetched from a database is indeed related to the active user?
For example: let's say we list a group of PMs inside user x's inbox - how do I make sure that only user x can fetch something from the inbox, and not someone else (this would be done by "hacking" the address ofcourse).
Obviously I could just compare the active username with what is in the database table, but is there no easy way I can control this globally somehow, without having to compare the active username with hundreds of different tables for different actions?
Supposedly you're fetching the messages of the logged in user to begin with, no? Something like:
"SELECT * FROM `messages` WHERE `recipient` = '$loggedInUserId'"
If so, I don't understand the question. If that's not what you're doing, you're doing something wrong.
Well your application tracks users sessions, and ensures security. I.e. when user logins server sets cookie with session id, and by session variable your server upon request of page will know what user is really requesting something(or maybe no logged in user at all if there is no cookie), thus your application may use user id from session and request url to figure out if it should show what is requested, or show error message or redirect because user is trying to access what is not his. Of course this is a bit more involving but thats a start. I suggest reading on php sessions and cookies.
That is what database query conditionals are for... only selecting the relative data.
Generally once the person is logged in you would get their username and password from $_SESSION variables, query the database to make sure they are a valid user, then grab whatever you need using a WHERE username = '$username'

Users database structure that allows multiple simultaneous logins to same account

A feature that is currently missing from one of my web apps is that a single user can only be logged in on one machine at a time. That is, if the users logs in elsewhere, his previous session will be logged off.
This is due to my current users table having the columns:
user: id, username, hash, salt... cursession
When each user logs in, the session ID is put into the "cursession" field and on each page-load, is checked against the database. As a result, only one "session" can be active at a time.
Is the current table structure and method secure and standard? This system was pretty much improvised, and I have no professional experience.
What would be a way to allow multiple simultaneous logins? I'm simply thinking of adding a "sessions" table with more userid-cursession relations, but what's the standard method for doing this?
I propose that you put the current logged in userid in the user's session (as a session variable), and drop the cursession field from the table altogether. You don't need to reinvent session handling since PHP already has it built-in.
That way the user can be logged in at multiple computers at once. Session variables are safe too, since they're not manipulated by the browser. The only thing kept in the browser is a session id which identifies the current session, all other data is stored on the server-side. The only thing that will happen if the user changes his browser cookies is that he will be logged out (start an empty session), so he can't force himself to log in as someone else.

Categories