Almost every website has an HTML form for visitors to complete. But how do you know that the person who completed the form did so through your website? That is, how do you make sure that no one has 'spoofed', i.e., 'forged', a form submission?
How can you "spoof" a form submission?
Let's assume you have the following HTML form that is located at http://yourdomain.org/form.php:
<form action="/submit.php" method="post"> <select name="myvar"> <option value="foo">foo</option> <option value="bar">bar</option> </select> <input type="submit"> </form>
It would seem safe to assume that you will be able to reference $_POST['myvar'] and it will have a value of either "foo" or "bar." Assuming the user selects "foo," the request will look something like this:
POST /submit.php HTTP/1.1 Host: example.org Content-Type: application/x-www-form-urlencoded Content-Length: 9 myvar=foo
Now let's assume that someone does the following:
<form action="http://yourdomain.org/submit.php" method="post"> <textarea name="myvar"></textarea> <input type="submit"> </form>
With this simple form, this person can now submit anything as the value of $_POST['myvar']. In fact, there was nothing to prevent the person who manipulated your form from including unexpected form variables or anything that can be achieved with an HTML form.
More sophisticated attacks might just use raw HTTP rather than bothering to generate or modify a form for every desired type of attack. You can telnet to port 80 and type your requests. Below is a sample request for logging into the NYPHP forum.
POST /index.php?act=Login&CODE=01&CookieDate=1 HTTP/1.1 Host: forums.nyphp.org Connection: close Referer: http://forums.nyphp.org/ Cookie: session_id=12345 Content-Type: application/x-www-form-urlencoded Content-Length: 44 UserName=myname&PassWord=mypass&CookieDate=1
To use these raw requests, you would need to change three items.
A more advanced form of attack leaves out the typing and uses specific software written to automate attacks.
Since, from a strict protocol perspective, the only thing you know is that HTTP requests and responses are going back and forth, there is no definitive way to know that a form submission has not been "spoofed". Therefore, our recommended "best practice" reduces the possibility of a spoofed form submission by relying on the use of a "shared secret" and, reducing the possiblity of unwanted values being submitted by outlining a general architecture for handling data and forms. (See Note 1)
Also referred to as one-time tokens or hashes, the idea is typically the same. You create a secret that is intended to only be known by the server and the legitimate user. Implementations vary widely but they share the characteristics of being transparent to your users and difficult to exploit.
One implementation would be to store the secret in the user's session:
$secret = md5(uniqid(rand(), true)); $_SESSION['secret'] = $secret;
This would then be used as a hidden form variable in the form:
<input type="hidden" name="secret" value="<? echo $secret; ?>" />
Every time you display the form, you would regenerate this secret, so that the user always has a current, fresh, and correct secret.
The receiving page can check this by comparing the "secret" sent by the form with the "secret" that was stored in the corresponding session variable. You can improve the security of this method by restricting the timeout window rather than relying on the session timeout, which might be too large for your needs.
A solid "architecture" would assure that:
1 - A bad practice is the use of "generic" form handling scripts that rely on hidden form values to determine what form fields may be required, etc. Any user can, using the "Spoofed Form" technique noted earlier, manipulate the submitted values.
2 - Some have suggested the use of a CAPTCHA as a method to eliminate spoofed form submissions.
Unfortunately it does not eliminate spoofed form submissions. The original intent of the use of CAPTCHAs
was to determine if a human being, not a webbot, has filled out a form. However, CAPTCHAs can be of use in
reducing the possibility of a website being flooded with form submissions since it effectively slows
down the rate at which those forms can be submitted.
Nonetheless, CAPTCHAs - especially those that rely on letter and numbers - can be circumvented. One technique utilizes a form of OCR using something like GOCR (see: http://jocr.sourceforge.net/.
To learn more about CAPTCHAs, see http://www.captcha.net/. See also, on captcha.net, the section that describes the use of pictures instead of text.
3- Be sure you know which variables contain the values you want and whether you are inadvertently relying on register_globals. Though as of PHP 4.2.0 this particular ini setting is "OFF" by default, nonetheless, it is still common for this setting to be "ON" in shared server environments (some open source applications require register_globals to be on). It's considered "best practice" to write your code with the assumption that register_globals is off. For more information, see http://php.net/manual/security.globals.php.
Contributors to this note include the following:
Joel De Gan
the PHundamentals Team: Jeff Siegel, Michael Southwell
Free API and developer tools console for PageSpeed optimization.