Basic about Verification - php

In the web application, of course in many case we will support CRUD(Create, Retriever, Update, Delete)
Basic programmer will do something like bellow(without Verification ) :
delete?room_id=12
update?room_id=13
The displayed room_id is only for room that belong to the user/client.
first Authentication is only using user and password. well that's a standard.
But i believe we should not trust the user. The bad user may guess the room_id that's not belong him. like delete?room_id=199
I ask my programmer friend, and they even never think about this issue.
So to prevent that, i have a basic solution that to always pass the user_id for any related object. such querying before any action is the room_id belong to the user.
If this the only solution, so i must to modify all of the query i already write.
The question is, is there any good or better solution for this basic problem ?
Thanks

Your approach is a good one. And it really doesn't surprise me that your programmer friends haven't thought about it; unfortunately security seems to be the last thing on most programmers minds.
In a good system, you will perform an authorization check on nearly every action performed to see if this particular user is authorized to perform that action. Its generally good practice to build this check in throughout your app, even for things that you don't normally care if they are authorized for or not: someday you might be.
In your scenario, that action might be to retrieve the room, update the room or even delete the room.
To help things along I have a few recommendations:
Make the room_id non guessable if possible. The easy way, presuming you are already using an int as your primary key, is to encrypt / decrypt it when passing between the client browser and your application.
Make sure that on the browser side you aren't passing in the users id but rather pulling that from session or through some other mechanism. The point is you don't want to trust the user to pass the id to you.
Any action that is not a GET, use an HTTP POST to perform. In other words you shouldn't be putting the ids in the query string at all but rather as post data.

assuming you have registered userid in a session when he logs in using: session_register("userid");
then you can do this to check if logged user owns the room (as you have told you have a database which contains roomid and userid at the same time)
$connect = mysql_connect("$server", "$dbuser", "$dbpassword")
OR die(mysql_error());
$room = intval($_GET['room_id']);
$user = mysql_real_escape_string($_SESSION['userid']);
mysql_select_db("$databasename", $connect);
$select = mysql_query("SELECT userid AS uid FROM table WHERE userid='$user' AND room='$room'");
$fetch = mysql_fetch_assoc($select);
$found = $fetch['uid'];
if ($found == $_SESSION['userid']){
// User owns this room let him delete
} else {
// FAIL, This user does not own this room
}
change the 'table' (which table in database contains both of this info) , 'userid' (user id column name in that table) and 'room' (room id column name in that table)
EDIT:
also if your room_ids may have any characters, remove the intval(); from $room and do a real_escaping for it, if room_ids are only numbers don't change it

Don't ever trust anything your client passes to you. Every request has to be validated on server side and checked whether the logged user is allowed to do that action.
Every text input has to be sanitized either on inserting or on viewing. The latter has bigger chance of forgetting and thus providing a field for XSS. I recommend using implicit sanitisation for templates.
Also try to avoid the use of GET method for critic actions. Attacker can always force user to visit the URL (iframe, sending him shortened link). You should also add special generated token to the deletion form to prevent CSRF attacks.

Related

Including obscured IDs in the URL

I need to include the user ID in the URL like this:
http://www.example.com/user.php?id=123456
However, there is a problem. If a user manually changes the ID in the URL to 123455 for example, that could potentially lead to an erroneous update of the database.
For this reason, I need to somehow make the ID in the URL unreadable to the user so they can't just subtract 1 from the ID and be able to alter another user's data.
Another requirement is that the ID in the URL must be usable, meaning that whatever we do to it, PHP must have a way of figuring out the database row corresponding to that particular ID.
There are 2 possible solutions I can think of. I would be happy to hear your opinion on which one is better. If there's an even better solution that I haven't thought of, please let me know.
Including an encrypted version of the ID in the URL - that should make it extremely difficult for a user to just change the ID in the URL and guess another user's encrypted ID. It's also easy for PHP to decrypt the ID when needed and use it to request the user's data from the database.
Adding a new column called "hash" in the "users" table in the database. As you may have guessed, every user will have a unique random hash or UUID stored in the database which will be included in the URL. That makes guessing another user's hash very unlikely. PHP can easily retrieve the user's data by using the hash in the database query.
If a user manually changes the ID in the URL to 123455 for example, that could potentially lead to an erroneous update of the database.
The way to solve this problem is to have sanity checks on the server so the user is not allowed to erroneously update the database. You either want some sort of permission checking ("this user is not allowed to update this record"), or other consistency checks that ensure no updates can be made erroneously ("the user is generally allowed to update this record, but right now it would cause a conflict with something else, so we won't").
You will have to include some id in the URL, and a user will always be able to change that id. At best you can make valid ids harder to guess by using something other than consecutive numbering, but that doesn't solve the underlying problem that your server has no sanity checks. Don't fault the user for generating errors, it's your code that's allowing it.
You should use sessions for this, not GET[] parameters, sessions are the tool for this Job. You can try the solutions you think of but from my point of view using sessions will be a lot better and simpler to use and implement.
But if you need to do something like the classic "recover my acount" so you don't have a way to log in you user, them you may use a hash in an URL and send it by email to "ensure" your user is the one who get's the URL.

Reveal the User ID over the url? E.g.: www.domain.com/user/1

What is the best practice?
I have a website, that has a user profile page and you can get to it with domain.com/user/1. Every number reveals the User_ID from my database. I'm curious is this a bad idea? I'm not into SQL injecting, but maybe one can use the information against me. I'm using Laravel and it has some basic protecting against injecting.
What do you think? Should I use random numbers for the user profile or it doesn't matter at all?
Note : Writing in context to laravel
Yea, it depend entirely on the purpose you want to use it for.
Lets say, for example in simple product listing an url that looks like
http://www.demosite.com/seller/1234/products/1234
would disclose vendor id and product id associated. so, even if someone try to do something like
http://www.demosite.com/seller/1235/products/1232 would fail if the vendor or product does not exits which is totally fine.
Also, as you are using laravel likely the selected routes will be only visible to user authenticated so, first level of security is achieved and you only have worry about internal users for which if you are still worried
use Hashing or encryption (again it depends entirely on the sensitivity of data.)
You can look here.. for Laravel Hashing or Encryption
if you have any queries comment back..
If depends!
If there is anything at all sensitive that can be accessed with just the id then it is a problem.
However if there is nothing sensitive – not even when preempting the id of an account before it is created1 – then there is no issue.
Consider for example https://stackoverflow.com/users/7009480/philipp-mochine which contains your user id here on Stackoverflow.
1 A multi-stage registration would be a problem with this: attacker jumps ahead to the last page and sets authentication details while the real person is still filling in their profile (fix: create the account and password then the user can fill out everything later).

Random ID Number when user created

I want to use a users unique id to save a cookie - so that I know which user is logged in, and then I can change their content to suit.
I am currently just using the usual auto id when a new record is created, but I have heard that for creating user accounts (specifically when you're going to use that ID to change content) that you shouldn't have them 1 after another; e.g. not 378, 379,380 and so on but more like this 138462193, 109346286, 982638192 so it's kind of like a random unique identifier.
How would i achieve this?
Is this a best practice?
You protect your data against attacks by using ACL, to limit which user has access to to what (and with what data). Foreign key relations to establish ownership between user and data, session ID regeneration at login, CRSF tokens to prevent attacks via other sites, and so forth.
Not to mention logging, to be able to find out what went wrong when things do go wrong.
Only in very special cases do you ever need to worry about the ID of users being sequential. Most of the time this ID will be available to other users, via the web site itself, anyway. As a part of normal operations.
Thus adding a random element to the user ID won't bring anything but a false sense of security. Even if you keep the internal ID different from the "external" user-facing ID, as long as you're using the external ID to identify and change content it's basically the same as the internal ID. Only valid reason for using a dual ID system, in most cases, is for human readability. If you're uncertain about whether your use case is one of the exceptions, it's not.
PS: I see in your comment that you say that the passwords are encrypted. Hopefully you mean "salted and hashed", more specifically by using password_hash () and it's associated functions.

How to validate if it's an authorised user sending a request?

I'm stuck in this situation where I need to validate if it's the right user sending the request/information to the server. For example, a user submits a delete friend request, in the URL as parameters I include the friend's id (another member id); should I also include the member asking for the friend delete request's id?
I'm just trying to validate or make sure it's the right user sending the request. What's the best way to go about this in general? If the user is logged in can we just validate by logged in member's id? Or is there a better way?
Without knowing how your authentication works, it's a little difficult to say.
When I've had to do this in the past, I've used a combination of server-side authentication to identify the user sending the request, and URL parameters to specify what they want to delete. A user needs to be logged in to send a Delete request, and I'm tracking their userID with a $_SESSION variable. So when I get a Delete request, the SQL looks vaguely like:
DELETE FROM
friends
WHERE
userID=$_SESSION["id"] AND friendID=$_POST["friend"]
As halfer explains in the comments, this is a generally bad way of doing things, as it opens an SQL injection vulnerability in the code. You can consider a couple of ways of avoiding that.
Firstly, you can sanitize the data - if you know that your friendID is always going to be an integer, you can check for that. A regular expression to check for non-numeric characters will work - if there's anything dodgy in there, you can deal with it appropriately and not pass it to the database.
The second approach is the one I prefer - when you make your query, you can use a prepared statement, and bind the parameters to it. Using PDO, you'll end up with something that looks like:
$sth = $dbh->prepare('DELETE FROM friends WHERE userID=? AND friendID=?');
$sth->bindParam(1, $_SESSION["id"]);
$sth->bindParam(2, $_POST["friend"]);
$sth->execute();
Try to require more secure UUID identifiers (generated and stored by you) for such requests, they are still not completely secure but considerably better than simple ids
Use a session variable to store the logged in user id. Once the session is established and your authentication scheme inserts the logged in flag you are all set. Just check the logged in flag when you need to perform any user requests.

Strategy for unique user-voting such as Stackoverflow's?

I noticed that for voting SO implements an XHR method which POSTs to a posts controller and sends the post ID and vote type through the URL, in addition a fkey parameter is sent, eg:
http://stackoverflow.com/posts/1/vote/2
I'm going to be implementing a similar technique, I'm wondering what logic I could use to prevent duplicate voting by the same user and prevent spamming, in addition to overall logic when implementing this.
The schema for the table I'll be storing them:
thread_id user_id vote_type
2334 1 2
So far I came up with these bullet points:
ensure the user is logged in
ensure that a valid post ID and valid vote type is sent
ensure that after POSTing, the user has not previously voted
the code that creates the hash can't contain dynamic information such as user agent, since a user could be on a different browser, different OS, right?
Update:
"SO is probably using the login cookie to identify the user." - Andrew
Could someone demonstrate how this would be done, or in other words more specifically provide an example of how the fkey, which is an alphanumeric 32-bit string, is generated?
Question:
since I'm not sending the actual user id anywhere with my XHR code, does this mean I have to update my table schema so that I can store the fkey instead of say, the user_id? The fkey will probably have to be unique to each user, and so I can probably query whether there is a row in the voting table that has an fkey of whatever.
Would appreciate any tips or insight on anyone who's implemented a similar technique.
create UNIQUE index on fields (thread_id, user_id) and DBengine will protect you from multy comments on one thread :)
You can just sign the URIs somehow in order to prevent users from manipulating valuse. For instance, you could hash parts of the URI with a secret and append the hash to the URI. When users copy the URI and change values, the URI and the signed part become invalid.
This is often done in RESTful APIs, and your current approach is similar to.
I think it depends on how badly you want to keep people from re-submitting or fiddling with your data. Nothing will be 100% (unless your budget is through the roof), but you can do a good job of keeping most people from resubmitting by:
check their UID - or generated ID from the UID (I will explain)
record their IP address, and check against the DB for the IP and the submission ID (along with the generated UID)
Using the IP solution alone, can be defeated by using a proxy of course, or a connection that changes IP's often such as the DSL carrier in my city (but even then, its every couple of days). I personally generate a unique key based on that persons UID, and pass that back and fourth if necessary. A salted MD5 hash usually works fine, or even an AES implementation if MD5 is viewed as too weak. Combined together, you should have a good starting place.

Categories