SECURITY: Secure id in a url - php

I use the following url when I edit a post from the user :
../post/edit/3 //If the id of the post is 3 for example
To avoid that the user modifies the url intentionally, for example /post/edit/5, I use the following logic to make sure the user doesn't edit the post when he doesn't have permission:
if (//user is allowed to edit post){
//edit post
}
else {
throw new AccessDeniedException('You do not have the permission to edit this post');
}
Is this the general approach that you use when editing a post? Is there a way to do something cleaner so that the user cannot play with the id of the post in the url?
EDIT
The more I think about it, the more I realize that I have never seen an id in a url like this in a website that is concerned with security. So, I agree we can still use the id and check if the user can show/see this id, but still the user can already do too much.
Wouldn't it be better to hash the id, allowing us to generate a new encrypted ID using any available algorithm:
<?php
echo hash('md5', 'id_to_edit');
?>
What is the standard approach to secure an id in a url? In general, is it a good idea to display info like the id in a url?

Special situations may call for special measures, but in a typical situation, all that is necessary is:
Use SSL so that sessions can't be hijacked by eavesdroppers
Check the user's permissions before doing anything.
Plenty of sites do it similar to the way you described initially. For example, WordPress has URLs like https://example.com/wp-admin/post.php?post=112&action=edit. Clearly, a curious user could choose to edit the post=112 part.
So, one standard you might consider is: "Do I need to be more concerned about security and privacy than WordPress?"
If, for example, you don't want people looking at log files to know what IP addresses are editing what posts, you have a few options. Each approach has trade-offs so what the best one is will depend on what your biggest concerns are.
For example:
You might use a hash to conceal the post id number, like you suggest in your update to your question.
Or you might just send that info via a POST method (instead of GET) over SSL and not include it in your URL at all.
One advantage of the first approach is that people can use bookmarks to get back to the page. You might not want that. Or you might. Depends on your app.
One advantage of the second approach is that (for example) Google Analytics won't reveal if one post id is being accessed/edited over and over again or if many post ids are being accessed/edited. This may matter to you depending on whether such information might tell someone something and who has access to your Google Analytics stuff. Or it might not matter at all.
There are a lot of other possible considerations too, such as performance.
By the way, if you do use MD5, be sure to include something in the input that an attacker will not know. Otherwise, it will be trivial for an attacker to reverse a discovered hash via a lookup table and generate further legitimate hashes for sequential post ids. In PHP, you'd want to do something like:
hash('md5', $some_hard_to_guess_secret_string . $data_you_wish_to_hash);
There is no single best practice that applies to every situation. But in a typical situation, it is not necessary to hash the post id value or even send it through POST. In a typical situation, be sure to use SSL (so that sessions can't be hijacked) and check user permissions before doing anything and you are likely good to go.

You must treat all data coming from the client as suspect. This includes the URL. You should check that this client is indeed authenticated and that he is authorized to perform whatever action is indicated (by the URL, post data, etc). This is true even if you are only displaying data, not changing it.
It is not important if the record id is easily seen or modifiable in the URL. What matters is what can be done with it. Unless the id itself imparts some information (which would be surprising), there is no need hide it or obfuscate it. Just make sure you only respond to authenticated and authorized requests.

check permissions
don't use GET values for validation, authentication, authorization. session, post variables are ok.
to make things interesting... $x =md5(random number + post_id + userid) send all the values seperately like /edit/3?id=$x&y=rand_number when you get back to the edit page you check everything. else throw them an exception.
few more ideas involve db but if you are interested.

That's standard approach. You should alwasy check permissions on both: showing form and on action after submiting the form.

Regardless if you hash the ID or not, you must check permissions when editing a post, or someone could potentially stumble upon a page they are not supposed to be able to edit and they could cause serious damage. This could either be through randomly guessing, or through browsing through the history of another user that used your app.
Check permission before allowing someone to edit something.
That isn't to say you can't hash your IDs so they aren't quite as linear, but take a look at popular applications such as Wordpress, or even Stack Overflow. They are all based on incrementing numbers because regardless of knowing the ID or not, if you don't have permission, you can't edit it.

Obfuscating IDs will not increase security. As previously mentioned - you should always check permissions.
The reason why you might have an impression that you haven't seen url like this in a website that is concerned with security is because some of those websites are usually running on something like Java or .Net, and are using GUIDs ( http://en.wikipedia.org/wiki/Globally_unique_identifier ). Some of them however are using sequential IDs (e.g. gmail is using sequential IDs for emails).
MD5'ing is not a good idea. Cracking it is really easy, especially if it's something like md5(5684). I've looked up couple of hashes of numbers <100.000 here http://md5.noisette.ch/index.php and it found every single of them.

It can be better to use ACL for that. You can configure your application to deny everything and use ACL to give an access to the specific object.
It's a common practice not to use any hashes instead of ids in URL. Clean id allows you to grep apache logs, application logs with simple command. All logic must be in the code to give or deny access to the specific domain entity.

How much more secure do you need to be than checking if the user that's already confirmed who they are (logged in) has permission to edit the post in question? If you simply had a hashed value displayed in the address bar it would still be relatively easy to find the hashing algorithm and then they could still have control over what post they're trying to edit. Security through obscurity will always be a false sense of security.

Related

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).

How to generate secure private urls in CakePHP?

I like to create a secure URL for a user for his entries (delete and edit links).
for ex, this is my actual URL
http://localhost/project/blogs/delete/1/test-title
what i want to do is,
http://localhost/project/blogs/delete/4324143563443/test-title (some hash made of salt+user auth id)
My main purpose is to create a secure hash along with the URL for delete and edit method.
Is there any custom method's available?
I searched in CakePHP Security functions http://book.cakephp.org/2.0/en/core-utility-libraries/security.html and not sure whether its the right way to do it or not sure which algorith to use)
Firstly, although I am not quite clear on how/why you want to do this, it sounds like you want to "protect" these links through obscuring their URL's. This is known as "Security through Obscurity" and is generally frowned upon.
In Cake (and most apps), the usual way to achieve this is to allow users to login (see: Auth Component) and then, for example, in your delete action (i.e. for the URL /delete/1) requests would be checked for a valid user session, and that the user has sufficient permissions to delete.
Although I would strongly reccommend otherwise, if you did wish to create these obscure URLs then you should probably use Security::hash();. The problem with this is that you wouldn't be able to just hash the id and then determine the id from the hash directly (thats the whole point!). Instead you would need to store the hashes in the database and then query for the hash (each post could have a unique hash generated either from the id or just random data, either would do).
As already mentioned "Security by obscurity" isn't very smart. Nevertheless easiest way to achieve what you want is use UUID's for your table's primary key instead of numeric auto increment.

Is placing data in an href safe?

I'm wanting to pass data from one php page to another on click, and use that data in populating the linked page. At first I was going to use ajax to do this, but ran into trouble, and then realized it was as easy as placing the data in the href of the link.
My question is, is it safe to place the data directly in the href in this manner? I know that passing the data via the URL (which this ends up doing) is safe, but I heard somewhere (that I can't recall), that placing the data directly in the href of a link can cause problems with web-crawlers and the like.
Is this true? Is there anything else I should worry about in using this method? Or is this the best way for me to send data, unique to each link, to another page on click?
The PHP:
while($row = mysql_fetch_assoc($result_pag_data)) {
echo "<a target='_blank' href='secondary_imgs.php?imgId=".$row['imgId']."'></a>";
}
There should be no problems with web crawlers as they just follow the links.
There is however a potential security problem in that malicious users can address arbitrary rows in your table by altering the URL string. This may or may not be a problems depending on what the links point to.
If you need to restrict your data to particular users then this is not a good idea, otherwise, its simple and straightforward if it works for you then do it.
I think it's safe enough if you want to display some data, but never use get method to insert data, especially careful when it comes to sql. NEVER use get method to modify sql, if had to, validify the arguments first.
Be careful with post method too. In a word, never trust users, you never know.
It looks like it's safe since you're "only" querying an image with a specific id (that's all you're doing, right?). Just ask yourself if
http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
9.1.1 Safe Methods
Implementors should be aware that the software represents the user in their interactions over the Internet, and should be careful to allow the user to be aware of any actions they might take which may have an unexpected significance to themselves or others.In particular, the convention has been established that the GET and HEAD methods SHOULD NOT have the significance of taking an action other than retrieval. These methods ought to be considered "safe".
applies.
Neither passing data through URL, nor embedding it into href is safe.
That data can be seen by user, so you are not protecting your data from user.
That data can be modified by user, so you are not protecting your data from modification and your script from getting evil or misformed parameters.
So, if you are designing the system which is going to be run under strict protection in a friendly environment - it's OK to pass params through the URL (hovewer, note that URL string is limited to 4096 characters). If not - it depends on protection level you want.
The simpliest way is to use POST requests instead of GET. THis way you'll not protect your data from evildoers, but ordinary users will not have the ability neither see nor modify it. Anyway, it's a good idea to validate the input on the server always.
Define "safe".
Without knowing the the threat model is nor how the data is used it's impossible to answer.
Certainly there are very important differences between a GET and POST (but note that a POSTed for can still send GET variables via the action URL).
It's no less dangerous using a POST rather than GET to send data. Nor using a cookie. All can be modified at the client end.
If you're talking about CSRF, then there's lots of methods to prevent this - try Google for starters.

Create unique Poll/vote/survey in php

The unique poll/vote/survey i mean here is, user can only vote once. How do i do that? Track their ip? Login? Beside login, what else? (login is my last option, thus beside login, is there anything else I can do?)
To restrict the number of votes per person, you need to track the person.
Now there can be several ways to do that, and I'll list them with their pros and cons. Its for you to decide which method suits you best.
login: this will offer you ultimate control. But its also a little cumbersome for the user. and its your last preference
IP: how will you handle people behind web proxies? How about people with dialup connections and/or dynamic IPs?
cookies: this is good for short term polls, so you can set the expiration of cookies to a time when the poll has ended. But, a potential drawback is that a user (contrasted with a luser) will know how to delete the cookies!
openId: While this method is not too different from the 'login' method, this saves the user from registration (which really is the part that sux the most about logins).
EDIT: the problem with this situation is that you need to resolve the identity of the user. I think OpenID does this pretty darn well.
Cheers,
jrh.
You could always store a cookie on their computer. Beware, though, that the user can easily disable cookies, or modify the contents of a cookie. There is no 100% reliable method to do what you want to do - the user can always create a new account, or move to another computer, etc.
If you want to go with the cookie approach though, there are three possibilities.
You can store a bit of text saying this person has already voted
You can store a unique id referencing their vote
You can store a session cookie and store the rest of the data on the server (probably more secure, since they can't edit the data, only the session id, and doing so will probably invalidate it).
The most secure way is a login system.
But if you dont want to use one, i used to add a hash containing the users IP and browser witch will help me filter out to a much better degree then just simple IP ( the browser string might be different for different persons using the same browser, because of the version, operating system and extensions installed ), but you still have problems if they switch browsers, the same problem as cookie.
The hash was stored in a database.

URIs vs Hidden Forms

I'm working in CodeIgniter, and I want to send requests to my controller/model that have several parameters involved. Is there a difference between passing those parameters via a hidden form (i.e. using $_POST) as opposed to passing them through URIs (e.g. 'travel/$month/$day/')? Are there any security concerns with this approach?
Example Security Concern:
URIs
http://www.example.com/travel/$month/$day/
Hidden Form:
form_hidden('month',$month);
form_hidden('day',$day);
Rule of thumb — GET requests should never change the state of things. So, if you actually change something or request — use hidden forms with nonce values (to prevent accidental resubmissions and CSRF attacks). Otherwise, there's no difference.
Auth should be decoupled from URIs and POST data — there are cookies, HTTP auth and SSL client certificates. Everyone knows that there is a 11th June in 2009, and a lot of people may know that you use /$year/$month/$day/ scheme in URIs (or "year","month" and "day" POST fields) on your site. But only those who are entitled to access should be able to see what's on this page (or POST data to this URI). And, yes, both GET and POST data can be easily tampered, so you obviously have to check for validity.
If you choose URIs, if the user bookmarks the URLs,
it brings security problem.
and if any user clicks any links ,
then the target web server can now know
HTTP_REFFER, and the server administrator
can know the link.
it means he can see the URI.
so my personal opinion is that
you better choose hidden form.
If you monitor your incoming-data (users are evil goblins, remember), and clean when necessary it's not going to make much of a difference. The difference only comes down to usability: if you want users to be able to access the same results without always having to go through a form, then use the URL method.
In all honesty, your example doesn't given enough data to determine which method (POST/GET) would be appropriate for you.
Suggested Reading: GET versus POST in terms of security?
I ran into this same issue recently. When anything additional is exposed in the URL, you run the risk of exposing website methods/data. After quite a bit of research, I elected to only show variables when absolutely needed or if the page was just a simple view. The more data you expose in your URL, the more checks you'll likely need to put in place (what if the user modifies the URL in x way).
Another consideration is the ability to bookmark or link to URLs (presumably views). One idea is to hide variables in the URL via an encrypted string. You could then store the encrypted string in your database and serialize as needed. I did this for a search engine and it gave me the best of both worlds. This was with CodeIgniter.

Categories