PHP Security, Access-Control-Allow-Origin: * - php

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.

Related

How to secure Cross-Domain request; allowing third website to POST data

I have done some researches on how to prevent fake cross-origin requests and have found a lot of useful information. However, none of them seems to directly resolve my concerns, and because my application has to deal with this specific situation, I would like to understand it completely.
I have a simple php mailing website: mailsite.com
This site will allow other pre-defined addresses, for instance, user.com, to send POST data to it, and process the information that contains to and mesaage; then send them an E-mail from mailsite.com to to with the message message.
Currently, I am using $_SERVER[ "HTTP_ORIGIN" ] and $_SERVER[ "HTTP_REFERER" ] to check where the requests come from; and process them if it is from the pre-defined domains. However, I've read some articles that say:
HTTP_ORIGIN is not even indexed in PHP documentation, because it is pretty much per-browser sort of thing, so browsers that refuse to send those information will not work. HTTP_REFERER is easy to fake.
Tokens are good in preventing CSRF.
However, the request I allow is coming from a third pre-defined website, how does Tokens work in this situation?
My question is: If I allow specific domains to POST data to my site, how can I make sure (or the most secured way) that those requests are coming from the sites I expected? Is HTTP_ORIGIN not even safe enough to use? I dare to think about allowing third website to POST data to my site because I've seen Facebook allowing people to access their database. There must be some possible solutions for checking where the requests come from.
It sounds like you have multiple solutions possible:
Use a token permission system. Give user.com a private token to add as a hidden value to the input form. Upon submitting this form, the browser will give your server the token, and the user shouldn't have to know about the token. You check the token against your own database. If you find the token, allow the mail to be sent.
Use CORS (Cross-Origin Resource Sharing). When an Ajax request is sent to your server from user.com, there should be multiple Access-Control headers. You check if these exist and what their values are using $_SERVER['HTTP_ACCESS_CONTROL_header'] where header is one of the Access-Control header names. If these values match up to your expectations, respond with multiple header('Access-Control-header: value'); calls so that the browser knows you accepted the preflight request, otherwise don't add any extra headers. The browser will send another request after the preflight, and this is when you'll actually send the mail.
If this is being sent from user.com's server rather than a visitor of user.com, most likely the server's IP address won't change (though it may or may not use a defined range of IPs, so be mindful of that.), so you could verify that the $_SERVER['REMOTE_ADDR'] matches a value in your database. You can keep a table of approved IP addresses in your database for this purpose. If you find the IP address in your table, allow the mail to be sent.
Hope this helps.

Embedded iframe - Verify source/origin of GET request

I'm seeking to utilize an iframe to embed some html in customers websites that will list some information from my database using a simple GET request like so:
// customer would copy/paste this code onto their site
// value of key would be unique key for that customer
<iframe src='http://mydomain.php/api?key=1234j1lj1hj124kh' ></iframe>
Now I want to be able to verify that the request is coming from customer that owns the key, and not just anybody who copy/pasted that code onto their page.
I've done some research and found that $_SERVER['HTTP_REFERRER'] can give me this information, but with mostly mixed reviews saying it isn't always reliable (and most of the questions I came across were a couple years old).
QUESTIONS
1.) Is this method of using an iframe/GET request the standard way of achieving this functionality?
2.) Is there a standard, SECURE and RELIABLE way to verify the origin of the GET request?
Unfortunately this is not possible in a secure way.
To answer your questions: In fact this is not a standard functionality itself. I mean, there is no standard secure way of allowing content to be loaded only through iframes from allowed websites.
There are three parties in this communication:
1) Your website
2) Customer website that loads your website's data in an iframe
3) End user visiting customer website
When an end user visits customer web site, he will perform a GET request to your website through the iframe. At this connection, 2nd party above (customer website) is not involved. In this case, there is no reliable way for your website to know whether this request is coming through the iframe or not. Only favor that party 2 does here is adding HTTP_REFERER header to end-user's request. But this header cannot be trusted.
For example, if I want to abuse this and show that content on my website, I can create a proxy page on my application, where I perform a back-end call to your app (adding a valid HTTP_REFERER header) and display results back.
Personally I would never use iFrames for this functionality. I am assuming that this has to be reasonably secure, which is why only your specified customer can view it? If for whatever reason you can't use PHP to embed the content you need to display (through the use of an "included" file for example), I would instead use AJAX which would still use any PHP user verification you have in place to dynamically load content into a secure webpage.
This is because your PHP user verification will (should!) use cookie/session information to determine which customer is viewing the page and therefore decide whether the content should be delivered, since Session variables are determined by a single unique code stored client-side, which match up to as much information as you want to collect about a user server-side (Which could include the last page they visited, which is what the "HTTP_REFERRER" variable would give you, if they came from another page on your website).
'$_SERVER' variables aren't reliable because they rely on the information given to them by the web browser when the request is made, and such information can easily be forged, by most people who have a basic understanding about how headers are sent.
In summary, use a NONCE (cookied), validate IP and user agent.
Steps:
When you deliver the outer frame, generate a unique identifier
(totally random, long string) and return that in a cookie with the
HTML content.
At the same time, note the IP and the user agent string you have
sent that unique identifier to, and store in a DB with the time.
When requesting the inner frame, assuming the same domain, the
cookie will come too. (If a different domain, you'll need to attach
the unique identifier as a visible string, but that's not really of
concern, just uglier)
If the user agent or IP do not match those you stored against the
unique string, or the request is too long (i.e. after an hour, or
whatever is reasonable for your application) or the unique string is used more than once
(or whatever other restrictions you place on it) then reject the
request and invalidate (delete) the unique identifier.
Not 100% foolproof, but just combine more options to make it less and less likely to be abused.

Save cookies from specified site to file on my server

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

Loggin a user across different domains

two years ago I had to design a system to share authentication data across multiple domains, all of them shared the same server/db. I was able to pull this off with a complex system of cookie sharing which, to date still works.
I'm now in the process of redesigning the system and I was wondering if there are better ways to achieve this without having to write cross domain cookies.
Basically the system MUST do this.
Once logged in one site the user must be logged in all of the other site seamlessly, not only following a link, but even by directly writing the domain name on the address bar.
To my knowledge the only way to achieve this are cross-domain cookies, if there are alternatives please tell me.
Thank you very much
My Idea would be to include a login-Javascript from a third domain which gets includet in all sites. This javascript sets and reads the session-cookie and calls the current domains server via ajax with the result. (No validation should be done in the JS - this simply sets and reads the cookie)
If cross domain AJAX does not work, you can still call the thirds domain server which acts like a proxy and calls the current domains server.
The StackOverflow sites have implemented something similar to this. Check out the details at the following links.
Here is a post giving an outline of how they did it.
And here is even more detail.
For this you do have to use cookies, but you can vary what you store in the cookie. The cookie doesn't have to contain user credentials but can instead contain something more like a token that you use to "centralize" your sessions.
Easies way would be to let all hosts share a single memcached server and use the content of the users cookie as your key.

PHP - Source (hostname) of a GET request

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.

Categories