I was wondering is there a way in PHP that you could tell where a form was submitted without using hidden fields or anything of the like where the user would only need to tamper with the html a little?
For example i am trying to work out if a form that was submitted was actually on my website or whether the form was saved offline and submitted that way.
An hidden field is not easily spoofed if it contains a UID (if you encrypt a time stamp you will be able to tell how long the user has been on the page)
Of course the user can enter whatever he wants in the field, but unless he can generate a valid UID, he can't make your php script believe it came from somewhere else.
You can also track a user's visited pages through $_SESSION and use that instead of the HTTP referrer (store each visited page in an array inside $_SESSION, and when your script is called, you simply check whether the last page was yours? Variation of that are possible depending on what you need).
You can attempt to use the referral header set in HTTP requests, do note however that not all browsers set these correctly, or users have them turned off, or that they are very easily spoofed.
Without a hidden field containing an unique identifier that is used to identify the form for that one single submission there is no good way of identifying whether the form is being forged or not.
I could be wrong but wouldn't the referrer header tell you this?
This gets you what you are after:
$referer = ($SERVER["HTTP REFERER"] == null);
This actually fetches it from the HTTP Header where it looks like this:
...
Referer: http://foobar.com/page.php
...
It is easy for anyone to spoof this but for most purposes it is reasonable.
Trivia: Referer should actually be spelt referrer which is the correct spelling but the spelling mistake made its way into the HTTP specification and has stuck since.
You can't really tell. Why would it matter? If you're trying to detect if someone has forged a request, you can't.
Amended: The green solution above does help some issues, but it doesn't address the question of if it came from your site, or if it was modified.
Related
I'm implementing a message system (private messaging, if you will) and I'd like to be able to display the list of messages a user has by a text link so I don't need a button to open it. The message_id (unique value in the databse) would be passed through the URL. (something like www.example.com/message/view/16).Assuming I check to make sure the session of the userid matches the userid that the message is sent to, is this OK? To make it safer I could just append a random number and set that as as session, and then just check for that upon viewing.
Should I forget this idea and just stick with a submit button to view the message?
A POST request would not provide any more safety than a GET request: any half-decent web debugging tool can forge POST requests. You should simply never trust user-input data. Always double-check authorizations for safety!
That said, GET request semantics match what you're trying to do here.
The HTTP standard says that a GET request should be repeatable without any non-trivial consequence. For instance, it's adequate to view data with a GET request (and possibly do small things like incrementing a counter, since these are pretty trivial consequences). In fact, GETand HEAD are the two request methods that are considered "safe".
On the other hand, POST requests are expected to have non-trivial consequences, like sending a message or placing an order. Stuff that you don't want to perform twice accidentally. Most browsers these days also respect this by warning users when reloading a page would cause a POST request to be performed again.
Using GET values for viewing messages is much better idea, because assuming a user stays logged in, it would allow them to bookmark messages, etc.
I want to implement a system where I want to know where a POST request cam from.
For example: I have a form with a submit button in it. When the User clicks on the submit button it goes to the page. But I want to know the source from where the post request came.
This is the code till now:
<form action="profile.php?id=<?php echo $user->id; ?>" method="post" name="formAdd"><input name="btnAddUser" type="submit" value="Add User"></form>
Should I use a hidden input element? Would that be a good way OR maybe something else?
First of all, there is no reliable way - users can tamper with requests if they want to.
Besides that, there are two ways to get the kind of information you want:
The referer, available via $_SERVER['HTTP_REFERER']: It contains the full URL from which the request came, but some people use extensions/firewalls/etc. that block or even spoof referers
As you suggested, a hidden form element. This always works unless the user actively wants to tamper with the data sent. So that's the preferred way.
The $_SERVER['HTTP_REFERER'] will let you know where the request came from.
More info:
http://php.net/manual/en/reserved.variables.server.php
It really depends on how secure and reliable you need it to be. A hidden form field would work although it means you'd need to add it to every form that points to your processing script. It's also easy to fake if someone wanted to. Alternatively you could use $_SERVER['HTTP_REFERER']. This isn't always reliable - I believe it does depend on what browser you're using but should be good enough in most simple scenarios. Another alternative would be to store something in the session and use that. That's probably the most secure as it's all server-side and can't be tampered with, but it is probably the hardest to implement (not that it's rocket science).
You could save the page in a session variable ($_SESSION["something"] = "page.php"), that is the most secure way, I think, because a hidden input in a form could be changed by the user, and $_SERVER['HTTP_REFERER'] is not always avaliable.
I would use a hidden field where the value="name_of_referring_page".
This way, no matter what the user's settings, firewall, browser, etc you get the info that you want.
I have a form where a user submits data from various text fields on my webpage to mysql database. Is there any code I can use were it will not let them submit/update the data again? e.g it will redirect them to a page saying sorry wwe have already received your data.
I have a unique number for each user if this helps. any help is appreciated.
Use tokens, it will avoid double submits and CSRFs.
Simply add tokens to an array, $_session most likely, and pop them when used.
Also, disable the submit button with JS after a submit.
You can also set a var in the session user that says he already performed an action, exampled uploaded his picture. Unset it if there is an error in your upload script for instance.
When you receive the post, query the database for the unique user number. If you get back a non-empty result, then display the error. Otherwise, save the data to the database.
The biggest thing you need to determine is what your unique identifier will be. It sounds as though you already have one (you mentioned unique user number?) Your unique identifier could be an email address, or even the full set of submitted data.
There are other ways to emulate this, such as setting a cookie on the user's machine, or disabling the submit button, but, none of these are completely under your control. The user could easily get past them if they tried. Therefore, determining a unique identifier and validating server side is probably the best way to do it.
The answer hugely depends on the reason for which user might send the data twice.
in case of an accident, there is one technique, and all other won't help you even a bit.
in case of intentional duplication the technique is completely different and again there is no general solution - everything depends on the certain scenario.
If you care to explain your certain case, you will get a proper solution.
For the most silly case of pressing "Reload" on a page with post results, you have to redirect browser using Location: HTTP header, e.g.
header("Location: ".$_SERVER['REQUEST_URI']);
exit;
I'm making a register page, signup.php, and basically what I want it to do is check for errors and if there are none, redirect to register.php. That is fine and whatnot, but register.php is the page where the actual account is made (e.g. mySQL query). Of course, in order to do that, I actually need the params gathered form signup.php. I was wondering if I could do something like this..
header("Location: register.php, TYPE: POST, PARAMS: {user,pass,email}")
Obviously I can not use $_GET as I am transmitting sensitive data (e.g. passwords).
Any ideas/suggestions?
EDIT: Thank you all for your answers. I am now storing the parameters in a $_SESSION variable.
I see no point in such redirect.
Why not to post right away to register.php?
And then check for errors and save data in database in the same register.php?
without any redirects
No, you can't, and such data would be just as insecure to any determined attacker.
Store the data in a session variable for use in the next page.
Even if this is possible, you will hit another brick wall - the implementation of redirects in the popular browsers. While the standard requires, that it asks the user if a post is redirected, all popular browsers simply interpret the redirect as a GET. In short: you can't redirect a POST that way, you'll have to find another way without a round trip to the client, or use GET.
Also, you should be aware that unless your requests are done via https, both GET and POST will present the sensitive information to any listener, as POST simply buts the query string into the http request and not the url. Security wise, both are the same.
You could store them in the $_SESSION and refer to those in the register.php page, doing some checking to make sure someone has actually filled out the information and didn't just navigate to it.
I have a simple signup form that needs to track number of hits from one specific external referer. This is a simple task with PHP's:
$_SERVER['HTTP_REFERER']
however, it is blank. After doing some research i tried to use some javascript:
document.referrer
Still blank. :(
I really dont need anything elaborate, but am trying to NOT use awstats.
Is there any other way to get the referer (hacks accepted)?? Or am I stuck with the stats???
-thanks
In short: If the user don't want it, you will never know, where he comes from. However, a more "reliable" solution may be to add the referrer to the link from the origin site to yours. Something like
Visit example.com
This requires, that external sites cannot just link to your site, but always needs to add their personal id. If this is not possible there is not much you can do.
At all its possible, that someone may change this id too.
The referer is possibly sent in the HTTP request's header.
It is possible that the browser will not even send it, or some kind of proxy, firewall or security suite strips it out or even changes it. You cannot rely on it.
There is only one thing you can do: if it is empty, consider that you don't know the referer.