Best URL ID implementation - php

I'm trying to come up with a good way to avoid directly using ID's in URL's to look up table entries. The main reason is that for privacy reasons, I don't want my users to be able to simply change, say, /?unique_id=10 to /?unique_id=11 and see someone else's information.
I've noticed many sites use randomly generated strings, but what's the best structural implementation of something like this?
Thanks!
Oh, and I doubt it matters, but I'm using PHP.
EDIT:
The information contained on the pages is public information. That is, anyone with the link should be able to access the page without trouble. What I want to prevent is people simply iterating through IDs and seeing everything in the database. I prefer that only people that have been given a link access the page. That said, it's not a huge problem if a random person stumbles across it.
Also, I don't want people looking at the ID to figure out how many total entries there are.

You probably need some kind of user check to make sure people arent seeing other peoples records anyway, but using a GUID for this is a good start.
You could use a hash of something like record1, record2 etc, but a determinted hacker could easily do this.
Another option is to use record aliases so each record has a string that represents it which you then use as the key. You often see this in wordpress or other CMS systems.
So if your id refers to a post maybe take the title and replace spaces with -
eg. www.example.com/article.php?id=Summer-is-the-best-time-of-year

You shouldn't had to deal with that at url level. You just take care of that at the session so if user 123 tries to access yoursite.com/unique_id=456 the session checking will prevent him from doing it. I mean you're talking about private pages isn't it ?
Even if you encode it (the user id) it will be accessible as a hash or something which would be nothing more than obfuscation which is not as good as preventing access on your own (with a session)

I have used MySQL's UUID() function for this, but you should definitely use permission checking to ensure that users aren't able to view data for other users.
This answer shows simply how to create a unique identifer.

you can encrypt them use md5(id) and search for the record the has the same md5(id)
ie
select * from table where md5(id) = '$encrypted'

Why not use AJAX calls for any queries to the DB rather than including them in the URL $_GET.

Related

How to prevent a user from manipulating query string in URL?

Say I have a website like foo.com and have the user be able to enter the username, and gives you back your view count. So if the username is bar, the url would look something like foo.com/index.php?username="bar".
Now if I had another user john, what could prevent bar from entering foo.com/index.php?username="bar" and getting their view count?
what could prevent bar from entering foo.com/index.php?username="bar" and getting their view count?
The short answer is nothing. Cause there are no safe (and consistent along different browsers and systems) ways to prevent user from editing the url. But...
You can check if the current logged in user has the permissions to view that data.
If you're using a framework, probably there's already an implementation for RBAC (Role Based Access Control).
So you should check the documentation for that.
If you're not and you're on a project with plain PHP, you have to implement that. And it can get quite complicated.
This is one of the downsides of PHP, user can always alter the request (and the forms contents) and you should always check that the data is correct. (that's one of the reasons most PHP programmers use frameworks).

Share login between PHP and ASP Classic (VBScript)

I'm trying to update/maintain an older web site that was initially written in Classic ASP/VBScript, and later had PHP pages added. I'd like to set it up so that PHP handles the login, but then that logged in state can be shared between PHP and ASP/VBScript. Note that the pages and languages are fairly intermingled -- somebody spending time on the site might come across several different pages in each language, in no particular order.
(Eventually I expect it to be completely rewritten in PHP, but I have to eat this elephant one bite at a time; and for now I'm simple trying to improve security.)
Let's assume I've successfully logged in and validated the user in PHP using something like phpPass. How do I tell the ASP/VBScript page they just pulled up that they're logged in? How can I best do this securely?
(And thank you for any help!)
You cannot share sessions across Classic ASP/VBScript and PHP as they create/use them differently. My solution isn't that secure but would work:
Log the user in via 1 of the languages (say PHP)
Pass the initial session variable to a URL and get ASP to look at the querystring and then create another session for ASP there.
That would deal with it...although not that secure!
The best answer I've been able to find for this issue was the following. Specific to sharing a login between Classic ASP and ASP.net, but the methodology is exactly the same:
As you probably already know, classic asp and asp.net cannot share the
same session state, so you do need to have a mechanism to log from one
into the other.
What I would do is: when someone logs in, create a unique GUID that
you save in the database for that user. When you jump from one site to
the other, pass that GUID into the query string. When you try to
auto-log them into the other site, look up that GUID and see if it's
attached to anyone. If it is, log them in.
This way you aren't passing anything that a user could guess or
decrypt.
Additionally, it's smart to add a timestamp to the database as well; and the GUID should only be valid for a second or two. Log in on the PHP end, then flip over to ASP and check the GUID.
Not totally secure, but appears to be about as secure as I'm going to find.
source: https://stackoverflow.com/a/921575/339440
Edit to add: per comments, also record the user's IP address to the database and compare it on the ASP side. No teleporting allowed!
CORRECTION: In this case "GUID" is a misnomer. What you need here is a random string of characters, not a GUID. A GUID is a semi-random construct with one of a handful of specific formats, and is not applicable here.

How to reject direct query?

I am using a URL to query some posts by their ID.
http://domain.com/page-name/?id=123
Visitors click the URL and will open the page and get the right post.
However, if anybody want, he can input this URL in browser and get the post, he can even get a lot of different posts if he knows other IDs. How can I reject this kind of query?
By the way, my site provide embed code for post. So, I need to enable access from other website.
The easiest way probably would be to check the HTTP Referer via $_SERVER['HTTP_REFERER'] and make sure the visitor clicked the link on one of your pages. This will, however, prevent any kind of bookmarking as well.
Another solution would be to use something else than IDs as URL parameter. Those would be hard to guess. You could use an MD5-Hash of the id + date or something instead of just the ID. (Of course you would have to store the hash in the database!)
On some pages you can see another approach. It is mainly used for search engine optimization, but can work for you as well. Generate a string from the title of the post (something like "news_new_blog_software") and store that in the database. Then use mod_rewrite to redirect all calls of http://domain.tld/post/* to a PHP file and over there check if the string after /post/ is in your database. This might look a little nicer than MD5 hashes, but you would have to ensure URL strings are not used several times.
If you want to make it really secure there is basically no other way than using some kind of login to check the access privileges.
However, if anybody want, he can input this URL in browser and get the post, he can even get a lot of different posts if he knows other IDs.
Exactly. That is the purpose of the World Wide Web.
And there is absolutely no reason in rejecting direct queries.
In fact, from the technological point of view, every request to you site is a "direct" one.
You are probably trying to solve some other problem (most likely imaginary one). If you care to tell it to us, you will get the right solution.
You can generate some kind of secret key and append it to the link URL, something like
http://domain.com/page-name/?id=123&key=1234567890
Some specific data required to generate this key is stored in cookie.
You can use md5 hash of random value + timestamp + page id, saving that random value to cookie. Every time you get a request, you check if key is present in request parameters, if user has cookie, then calculate hash and compare it with the one in the request.
you can pass id in hidden field and use post form method.
You need authorisation, not this. This would stop people clicking through to your site from search engines or other websites.
If you don't want to implement authorisation/login, then why not try implementing the First Click Free: http://support.google.com/webmasters/bin/answer.py?hl=en&answer=74536

Ways other than an iframe to pass parameter from php to asp.net

I have an PHP Application. If I have logged in that application I am trying to pass the parameter as querystring through an iframe to the asp.net page.
Is there any other way to implement other than using an iframe?
Instead of having the PHP application submit data to your ASP application, it would be better if they could natively and securely share some of the data.
How?
Well, your goal is having one script tell the other that the user has been logged in, right? In PHP, this is usually done by putting something in the $_SESSION. Your ASP application can't read $_SESSION, though. You'll need to use something else.
When the user logs in, create a unique value. Maybe the result of hash_hmac over some interesting data? Whatever it is, it should be unique every time it's created and unguessable. Don't throw in things like the user's IP address or the current time.
Save the unique value to a database table that both applications can read. Also store other information that will help identify the user, such as her identifier (user_id or whatever you have on hand).
So, the PHP code that logs the user in has created this unique value and stuck it in a shared database table. Now, the PHP application should forward the user to your ASP application. Include the unique value in the request.
When the ASP application receives the request, it will look for the unique value. If it's found, it can look in the shared table. If the value is found in the table, it can then take whatever measures it needs to in order to mark the user as logged in.
Once the ASP application has logged the user in, then it should delete the unique value from the shared table. The user can be forwarded to wherever she was going in the first place.
By making the key usable only one time, and only after a successful login in the PHP application, you'll reduce the possibilities of abuse by malicious or curious users. All of the important information will be hidden in the shared database table.
Be warned that this is an overly simplistic implementation of "single sign on" and is full of caveats and edge cases. While it might work for you, it might not be the best solution. Given your question history, it looks like you've been struggling with similar issues for quite some time. You might want to give some thought into using a slightly more "industry standard" SSO mechanism. SAML is the 800 pound gorilla of SSO standards. I normally wouldn't wish it on my worst enemy, but maybe it's the thing you're really looking for here.
Also, don't use iframes, they're cookie eating disasters in some browsers.

How to use A HREF with $_POST?

I have an HTML menu with links like <a href="input&db=<some database>" There are multiple menu items and multiple databases, so I am using GET as my form method and using it in my menu item links.
However, that shows up in the browser's address bar (as /inout&db=mydatabase) & might lead the user to start guessing as to database names.
How can I have a list of links to the same page, in which only the database varies, using $_POST ?
EDIT: oops, my bad Shoulda said server-side only, so no JS
POST values will be just as obvious to anyone who would be savvy enough to do anything with this information. Unless you're building something like phpMyAdmin, you should never pass such internal information to the client side to begin with. And if you are, where's the harm? You do have proper authentication in place, don't you?
I think the only way to send request via post using links is to use JavaScript. But sending it via post is not secure at all; anyone can install FireBug to see the request.
Instead, I'll suggest a change to your design. Databases are usually at the bottom tier in an application hierarchy, and coupling page details with database sounds unnecessary. Maybe you should try to encapsulate pages so that they don't need to know which database they are reading from?
Granted, I have no idea of the scope of your application (you may be doing something like phpmyadmin). Then it may be unavoidable, and I will just suggest the usual combination of verification and sanctification all users' input and their rights.
Or you can just encrypt your database names. Still I would prefer a change to design.
Use the onclick event of the anchors to submit a hidden POST form, or to perform AJAX POST actions.
No. There are a few narrow and dangerous solutions you can apply:
Use an iframe : everything will work as before, but the actual address will not appear in the browser address bar.
Use AJAX to fetch data.
Replace the link with a form-submitting button or javascript: link.
These all solve the "database name appears in address bar" issue, however:
Anyone with even basic technical skills and appropriate tools (chrome, firebug) can determine the database name anyway by looking at the requests being sent out.
Not using GET can mess up the browser's back and refresh buttons, and prevent deep linking.
My suggestion would be to keep using GET as you currently are, but add a secret token to the URL (such as HMAC(db_name,secret_key)) that cannot be guessed by the user but can be easily checked for validity by the server. This way, unless you give the user a link to the database (with both database name and secret token), all the guessing in the world will not let them access it.
Neither GET or POST will hide your database name.
Even you using POST, view source will reveal the HTML.
In the first place, you should not expose your database name.
Or replace it with some fuzzy mapping
such as
input&db=A
input&db=B
Internally, do string matching and convertA to actual database name

Categories