I have a Javascript widget that people can embed on their site.
I want to use a simple cross domain get request to pull in a hash.
However I need my PHP script to only allow this cross domain request from a series of domains I have stored in an array.
What can I do in my PHP script (not in .htaccessor iptables) to find out the source (hostname) of the get request?
Considering the client (user's browser) can send you whatever it wants, I would say there is no way to be sure which website your script is called from :
As you want to know the URL of the website embedding your widget, and not the address of the user, $_SERVER['REMOTE_HOST'] will not help
$_SERVER['HTTP_REFERER'] could seem OK, but actually is not :
The client doesn't have to send it (and it doesn't always do)
As it is sent by the client, it can be forged / faked Quite easily
So, I'd say there is no real solution to this problem, at least on your server's side (If I'm wrong, I'm interested to know !)
But maybe you can do something on the client's side : when writing all this, I thought about google maps, and it's system of API Key :
you have an (unique) API key four your domain
When you load the JS scripts from google, your send this key
if the key is not registered for the domain on which you are trying to display the map, there is an alert message, saying "The Google Maps API server rejected your request. This could be because the API key used on this site was registered for a different web site."
but the map seems to be displayed anyway -- at least on my test server
this alert is really anoying for the end-user, and I don't think anyone would want an alert displayed on their site because they are using your service withot authorisation...
Maybe you can have a look at how this is done for google maps :-)
You could use the $_SERVER variable. In particular the $_SERVER['REMOTE_HOST'] but see below for caveat:
However, your web server must be
configured to create this variable.
For example in Apache you'll need
HostnameLookups On inside httpd.conf
for it to exist. See also
gethostbyaddr().
If the requests are coming from JavaScript, you could check the HTTP referrer header ($_SERVER['HTTP_REFERER']). However, it's optional - some proxies or security programs strip the referrer header out of HTTP requests.
Related
For my example , i'll use this variables :
first_site.com = my website where i will execute the cookie get commands
specified_site.com = my second website that the client is already logged in
my_server.com = my server adress where i have a php script to handle the received data
the user is already connected to first_site.com and specified_site.com
and i want to get cookies from "first_site.com" and save them to "my_server.com"
Any way to do that , with php or javascript ?!
Regards
If both sites are yours and you have access to the server-side code on both sites, then you can have the first server forward the cookies to the second server using server-to-server communication.
The "same origin" protections built into a browser try to prevent you from doing what you want to do from purely client code (without involving both servers).
This is because you can only retrieve cookies when your page is on the domain that the cookie belongs to. And, you can only send the cookie (using ajax) to a server on the same domain as the page. So, you can't send one domain's cookie to another server. This is an obvious security violation which the browser intends to block with its "same origin" protections. You can read about those protections here.
If, you have a cooperating server from the first site, you can have that server retrieve the cookie when it is sent along with the original page request and then that server could send the cookie along to your second site using server-to-server communications. If the first domain is not yours where you can modify the server-side code, then obviously you can't run code on that server to do this.
There is no way to do that, as it would be a hudge security flaw.
Imagine if I made a website saving all your PHPSESSIDs, I could access your profile on many websites...
These are few of the options. Not the best ones though. Some general pointers to get you started:
a. You can also consider setting up VPN. This whitelist the IPS from both the servers.
You can create a REST API containing your cookie info(not public though)!!
Make your cookie data available on App1;
Make your cookie available as a Cookie object that can be served through a Request/Response Object
using "same origin" policy; you can have app2 talk to app1
I am building this class in PHP to gather everything that is known to my server from a client,
this happens when a client redirects to my http://. DomainName . ending ,
I have looked for few basic things as a start : IP address , time , port , agent , host , host
Basically everything changing that $_SERVER includes, my question is :
What additional information I could gather to maximize available information about users that enter my domain?
I forgot to ask,will I have to filter and (how they say,santise?) date from global variables in this case the $_SERVER array ?
You might want to use geolocation checking in order to determine where your users are located.
https://stackoverflow.com/questions/5190734/php-geolocation
In case you will support multiple language for ur site it would be easier for you to redirect the users to the right site automatically.
$_SERVER contains almost everything you might want to know really.
You could begin recording what links they're using, what pages they're visiting and how often.
Checkout irongeek.com's browser info page for an example of what information is readily available. You can learn a lot about a client from javascript. Perhaps part of your PHP class should include an AJAX component. That said snooping information available to javascript could be a huge violation of privacy, I'm no expert on ethics on the web.
Another good example of information gathering is Google Analytics (GA) if you have a live site with with GA on it, you should login and look at some of different reports and data types it has.
You should also read about Do Not Track.
Background:
I am creating a REST api, that will require users to use only a JavaScript file, for that I made an ajax request that gets data from the server.
in order to do that I wrote the following like in php:
Access-Control-Allow-Origin: *
I have a few questions:
1) What is the security hole that is present if I open the ability of other domains to interact with me?
(Access-Control-Allow-Origin: *)
2) What should I do to secure it?
3) Does this "Allow-Origin" work in all browsers? (mobile...) - or it does not matter?
If you use the wildcard, that means any domain can make a cross domain request to your domain and get the page. For example, say you are logged into your GMail account. Naturally, when you open up a window to http://gmail.com, you will instantly see your emails and messages (there's some redirection happening, but let's assume not for the sake of the example and simplicity).
Well if I make a website (be it anything) and I manage to get you on that website, or alternatively, I manage to modify a website that you frequently go on, I could make an AJAX request to GMail, and if GMail had Allow-Origin: * and you were logged in, the AJAX request would return the HTML of the page that is usually shown to you; the list of your emails. At worst I get a list of all your emails and the persons you sent them to, at best I can also manipulate the requests and get a lot more information.
I wouldn't use a wildcard if I were you; I would use some sort of list of trusted domains.
The Allow Origin is enforced server side. As for cross origin AJAX support, it is supported in most browsers. For older versions of IE, you have to use a different object to make the requests.
I'm building out an API and have a question about how to track/know which domains use the call.
The API call is built in PHP, and doesn't require any authentication. A user will most likely use the API in an AJAX call on their server.
So for example, my domain that is serving up the API PHP file is called dev.yourmapper.com. Someone on the domain www.metromapper.org builds a page that creates a Google map, and calls my file using Ajax to overlay my data on their map.
Here is that example in action: http://www.metromapper.org/example/apitest.htm
(Click the center map marker to see a popup of all the PHP Server variables available to the yourmapper.com script.)
Note that HTTP_REFERER is likely going to be 'stackoverflow.com' if you click the link (or empty if you cut and paste the link). I would think that the referer would be metromapper.org, since that domain calls the yourmapper.com script after it loads, but apparently not.
Bottom line: what method can I use to determine which domain is calling my yourmapper.com script with Javascript? I can use other languages besides PHP if needed. Thanks.
"I would think that the referer would be metromapper.org, since that domain calls the yourmapper.com script after it loads"
That's incorrect actually. Firstly you should never rely on the HTTP_REFERER because it's a voluntary parameter passed by most (not all) browsers, and it can easily be spoofed. I can send your website requests using CURL that make it look like the referrer was whitehouse.gov if I want to. There's no security measures in place there.
That being said. The browser sets that parameter to the page that referred the user to the currently loaded page. Not script. So the reason you see the result you're seeing is because the user was referred to metromapper.org by a link on stackoverflow.com
Finally, let's get to the juicy part. You're using JS to code things in the browser. That's fine and there's absolutely no problem with that. But you have to remember that JS is open source. So people can (and will) mess with your code to play with your API just because they can. That being said. Your best bet is probably to pass the url of the site along with the request in your JS api. That's the best way to "track" what sites are using your script. You could check server side to make sure that a URL was passed. That would prevent people from modifying your API to remove the bit that sends their URL to your server. It won't, however, prevent them from modifying it to use someone else's url or a random unregistered one as the parameter.
Sure you could build a PHP API that they run on their server. The JS API connects to the PHP API and the PHP API is zend-guard encoded (or some other source protection code system) but then there's still going to be people who decode the file to get back to your source and mess with you. Granted there'd be far less people able to do that, and the average user would just rather use your API as it is. Then you also have the issue of people not being able to run your API on servers that don't have the ability to run encoded PHP files.
In the end you have to determine your level of desired security and authentication, but since your API is running in JavaScript in the client browser, there is very little available beyond obfuscation.
I'd say your best option would be to simply have your JS code snag the URL of the current page and send it with the API request. From there your server can process the URL to get the root domain and any other info you want to store.
If you want to prevent people from "spoofing" requests for other user's website urls, you could implement a PHP API that gets installed on the user's server at a certain place. For example http://www.domain.com/my-app-name.php
All JS API calls should go through that script. When the user downloads your API they should enter their website URL and some other info. Your system generates a "key" and injects it into the script before packaging it for them to download. That key is valid for their domain and used to encode all transmission to/from your API using say blowfish or another 2-way encryption algorithm. This way when your API receives a request from their PHP API file, you're getting the url of the page that request was made from, encoded with a key that only you and the admin of that site have. So the request comes through as something like this: metromapper.org/api?site=[url_encoded_page_address]&req=[encrypted_request]
Your server uses the page url to determine what key should be used to decrypt the data. It then decrypts the data. If the data is corrupted or doesn't decrypt into what you expect, then it's an invalid request and you should just exit returning nothing.
The reason I suggest using a PHP file for encryption as opposed to writing the encryption into JS is because you don't want to burden the client (each site visitor) with the load of encryption/decryption and PHP is going to handle it much faster than JS would since there are libraries made to handle those tasks for you.
At any rate that should get you on the right track to being able to keep track of and validate requests for different sites against your API.
You could generate a hash based on the domain name, and let the users of your API send the domain name and the hash in each request. Now since you're API uses PHP you'll have set the 'Access-Control-Allow-Origin' somewhere in the header. If you do this in PHP you can play around with that a bit. The script below is a simple example of an implementation that doesn't require php on the caller side (domain that uses you're API).
Caller Side (no php required):
<script type="text/javascript">
function callA() {
var xhttp = new XMLHttpRequest();
xhttp.open("GET", "//ajaxdomain.com/call.php?"+
"dom=www.callerdomain.com&"+
"key=41f8201df6cf1322cc192025cc6c5013",
true);
xhttp.onreadystatechange = function() {
if(xhttp.readyState == 4 && xhttp.status == 200) {
handleResponse(xhttp.responseText);
}
}
xhttp.send();
}
</script>
Ajax Server Side (PHP):
<?php
if($_GET['key']==md5($_GET['dom']."Salt")) {
header("Access-Control-Allow-Origin: http://".$_GET['dom']);
}
?>
This way the header would also be placed if the call came from a malicious domain, but rest will bounce because of a Cross Origin Exception, and thus no result will be given.
For the sake code space I used a md5 hash in this example, but you could use more complex hashes if you want. Note that you should (as always) keep the used salt secret.
I put a working example online at the following (sub)domains. The pages are identical.
cors1.serioushare.com - Only works on 'CORS 1' button.
cors2.serioushare.com - Only works on 'CORS 2' button.
I have a PHP script hosted on my site that outputs a value based on the GET parameters passed.
Other sites call this script from within their own PHP scripts via the PHP function file_get_contents with the url and get params and are served back just the value requested.
I am trying to allow only certain domains access to this script and have been using HTTP_REFERER to check who's calling the script.
if (isset($_SERVER['HTTP_REFERER'])) // check if referrer is set
{
echo $_SERVER['HTTP_REFERER']; // echo referrer
}
else
{
echo 'No referrer set'; // echo failure message
}
I am getting No referrer set when I use file_get_contents but if I use a clicked link from a page to a script with the above code the referrer displays correctly.
Am I using the wrong function (file_get_contents) to call the external script and can someone suggest the correct one or should this work?
Any help much appreciated.
Thanks
Bear in mind that the HTTP "Referer" header is an optional header -- there's no need for a site to send it to you, and it can be easily faked. If you really only want certain people to use your resources, you're better off using some form of authentication.
Typically Referer: is sent by web browsers, but there's no need for it to be -- for example, they won't send it if the referer is a secure site. With a PHP file_get_contents() there isn't technically a referer anyway; you're not being "referred" from anywhere.
Consider instead either:
Locking down by IP address (but bear in mind that multiple domains can share a single IP, and that a domain's IP can change.)
Using some form of authentication (preferably not one that transmits passwords in plain text!)
You should consider how secure you need this service to be, and what threats might attack it when deciding the right security to apply.
You would be much better to restrict based on IP address rather than domain, much more reliable. Just keep an array of allowed IP's and call in_array($_SERVER['REMOTE_ADDR'],$allowedAddresses) to validate it.
Or just require authentication via a cookie or HTTP auth...
You can't do this using HTTP_REFERER.
The HTTP_REFERER it set by the client, and it can be anything the client wants.
You have to use a password / key authentication mechanism instead.
May want to use something along the lines of a stream context to set extra headers.
http://us.php.net/manual/en/function.stream-context-create.php
Additionally, if needed, you could set a 'secret' header to authenticate the requests, rather then the referer.