Requests to webservers can be faked. Normally, requests are generated and responses are handled by the browser. But there is nothing unique about a request; it is simply a string of formatted data. An attacker can manufacture a request, often one that is similar to a regular request but with malicious modifications. This is also known as "request spoofing".
Faking a request requires only a small amount of technical knowledge. There are also many tools to assist: browser plugins, command line tools, and scripts which can make hundreds of fake requests while probing for an exploit. Faked requests can even duplicate forms and send cookie data.
This is an example of a typical request header:
Host: 55.66.77.88
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Content-Type: text/html; charset=utf-8
User-Agent: Mozilla/5.0 AppleWebKit/601.5.17 (KHTML, like Gecko) ...
Referer: http://example.com/some/page.php
X-Forwarded-For: 43.59.172.66, 98.33.212.7
Connection: keep-alive
Cookie: user_id=4
Any part of this request can be modified. All of these values should be considered unreliable for security purposes. Testing referer or user-agent strings often does offer a layer of defense, but it should never be relied upon as the only defense.
The most commonly spoofed parts of a request are:
cURL is a simple command line tool for sending requests. It is pre-installed on many operating systems.
curl http://sometimesredsometimesblue.com
curl http://localhost
curl --verbose http://localhost
curl -v --referer http://faked.com http://localhost
curl -v --user-agent "Mozilla-ish" http://localhost
The examples above demonstrate how easy it is to fake the referer and user-agent data.
From the perspective of a server-side application, is not possible to prevent incoming faked requests. They are not different enough from regular requests to make them easily identifiable. The primary defense is simply to be vigilant about this when developing code and always assume these values from incoming requests are unreliable. It can be easy to think that they are set by the system and are therefore reliable. They are not.
One simple protection is to check the HTTP Referer in order to enforce same-domain form submissions. The referer for forms should be one's own site. As shown above, the referer value is easily spoofable, but checking it does provide a small layer of defense that is still worthwhile. Use Defense in Depth to provide additional layers of security.
<?php
function request_is_same_domain() {
if(!isset($_SERVER['HTTP_REFERER'])) { return false; }
$referer_host = parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST);
return ($referer_host == $_SERVER['HTTP_HOST']);
}
?>
Another way to secure forms is to use the same protections as for Cross-Site Request Forgery (CSRF). CSRF protections can prevent a user from un-knowingly submitting a form, but they can also be used to prevent an attacker from submitting a form as a faked request.