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
Related
I recently created two pages, front-end.php and back-end.php.
front-end.php post some data to back-end.php on mouse click (I am currently using ajax for this).
Now if I use Fiddler, then also I am able to post data to back-end.php. I do not want this to happen. What should I do?
I searched on Internet for answer and came to a word 'Setting User_agent', but solution is not given clearly.
Regarding what I want, Actually I do not want some bot or some other type of automatic program to get some data from some source and post it to my back-end.php. I want to assure that the user comes to my webpage and then post some data.
User Agent is a header that your browser sends to the web server with each request identifying itself. Here you can see what it is like.
Fiddler sends "*" or "Fiddler" as user agent, so you can ignore requests having those values. However, this is far from optimal solution to your problem because one can simply spoof the user-agent header by sending whatever she likes.
An other non-secure condition would be to check the referer. So, you can ignore all requests except those coming from "front-end.php". Keep in mind that this, too, can be spoofed by the user.
You should keep also in mind that since a user can send data to the web-server using her browser, there is nothing that can stop her from sending data or making requests using any other way.
In general, web developers should respect the user's freedom and not force such tactics, so please be more specific and tell us what exactly is the real problem you want to solve and a more elegant/secure solution may exist.
EDIT: If you do not want crawlers to index some/all of your pages you should add them in your robots.txt file.
Regarding all other automations/programs I'm afraid there is no perfect way to be sure if the request was made from a human being or a robot. I would do two things: a) Make sure to add validation rules to my backend and b) as a last resort implement a CAPTCHA test.
I would use CAPTCHA only if absolute necessary because it irritates most users and makes their lives difficult.
You should add a hash of some internal secret and the value you want to send. As you are the only one who knows how to make the hash, a fiddler cannot know how to create the secret.
For instance, you make a hash of "asdflj8######GJlk" concatenated by whatever your value in your form is. Now the hacker cannot change the form. The problem is, you can post the same value (with the same hash) from another place. To stop this from happening you should make sure all hashes can be used only once. The only thing a hacker can do now is to post your request from fiddler instead of from your site, but not at the same time. As a final step you can add something as a time-limitation
So what you need is a hash with:
a secret
a method to make the hash single-use
a methode to make the hash time-limited
add this as a field. Specific implementation is left as an exercise ;)
I would not use user_agent, these can be easily faked.
(these methods are the same that payment-providers use to ensure the data (e.g. the amount to be payed!) is not tampered with)
The shortest answer is that anything your browser can do, Fiddler can do. It can send any header it wants using any value it wants.
If your goal is to be able to pass some values from one page to another, without ANYONE changing them (either the browser or Fiddler) you use a Message Authentication Code (a signed hash of the data).
ASP.NET builds this feature in for their "ViewState" data; see http://msdn.microsoft.com/en-us/library/system.web.configuration.pagessection.enableviewstatemac(v=vs.110).aspx
However, that precludes the client (e.g. your JavaScript) from changing the values at all; if JavaScript can change the values, it means that it has the key, and if it has the key, so does Fiddler.
A number of my pages are produced from results pulled from MySQL using $_Get. It means the urls end like this /park.php?park_id=1. Is this a security issue and would it be better to hide the query string from the URL? If so how do I go about doing it?
Also I have read somewhere that Google doesn't index URLs with a ?, this would be a problem as these are the main pages of my site. Any truth in this?
Thanks
It's only a security concern if this is sensitive information. For example, you send a user to this URL:
/park.php?park_id=1
Now the user knows that the park currently being viewed has a system identifier of "1" in the database. What happens if the user then manually requests this?:
/park.php?park_id=2
Have they compromised your security? If they're not allowed to view park ID 2 then this request should fail appropriately. But is it a problem is they happen to know that there's an ID of 1 or 2?
In either case, all the user is doing is making a request. The server-side code is responsible for appropriately handling that request. If the user is not permitted to view that data, deny the request. Don't try to stop the user from making the request, because they can always find a way. (They can just manually type it in. Even without ever having visited your site in the first place.) The security takes place in responding to the request, not in making it.
There is some data they're not allowed to know. But an ID probably isn't that data. (Or at least shouldn't be, because numeric IDs are very easy to guess.)
No, there is absolutely no truth to it.
ANY data that comes from a client is subject to spoofing. No matter if it's in a query string, or a POST form or URL. It's as simple as that...
As far as "Google doesn't index URLs with a ?", who-ever told you that has no clue what they are talking about. There are "SEO" best practices, but they have nothing to do with "google doesn't index". It's MUCH more fine grained than that. And yes, Google will index you just fine.
#David does show one potential issue with using an identifier in a URL. In fact, this has a very specific name: A4: Insecure Direct Object Reference.
Note that it's not that using the ID is bad. It's that you need to authorize the user for the URL. So doing permissions soley by the links you show the user is BAD. But if you also authorize them when hitting the URL, you should be fine.
So no, in short, you're fine. You can go with "pretty urls", but don't feel that you have to because of anything you posted here...
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.
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
i've been seeing a lot of activation links sent via email and I implemented one but just isn't satisfied with it (the long activation links from other sites kinda looks cool but I can't see the point of it being so long). Here's how my activation link looks like
site/controller/method/4/MJKL
the 3rd segment is the user id and the the 4th one is a randomly generated token during registration...
i often see this implemented with url strings but what's the difference when using url strings and using url segments?
will it help if I pass any more information other than the user id and the token?
They might have a longer token in there to reduce the chances of an attacker guessing it correctly.
Don't bother passing any more information than you need. And don't be jealous just because the other URL is longer. Size doesn't matter, or so they tell me ;)
Is it the length you're concerned with, or the look of the URL?
I'm guessing you're using Zend Framework or something similar, that's why it shows "segments" as opposed to a parameter string.
Have you thought about using something like tinyURL? The Tiny API with PHP is super easy.
Edit: Another option if you are building html emails, is simply keeping the anchor text short
Click here to activate
I'm still assuming you want to make the URL shorter. If you want to make it longer, you could always append a session ID, a random hash or some other relatively useless information on the end of it that's ignored later.
If you're using an MVC setup, then it generally makes more sense to use the segmented (and also more SEO-friendly) URL: styles. However, this is no different than passing a query string, because the server (most likely Apache) is taking the input URL segments and passing them as a query string to the script anyway.
As for the long ID, that's not necessary. Either you can generate a custom, shorter ID tag, or use something like uniqid() to generate a shorter GUID for the user to activate with.