Restrict PHP API for specific domains which are saved in my database - javascript

I have created an API which takes the hostkey or API_KEY and then it validates and gives back JWT token. Everything is working fine, I can't access the restricted routes without Hostkey.
ISSUE
The major issue is that what will happen if someone gives this hostkey to others as it will no longer be protected or it will be misused. So what I want to do is not only validate the hostkey but also validate the domain from which request came from. It is kind of paid service and I really want to restrict is to specific domains. Just like google does with MAP Api as if we add that map key to other domain it throws an error.

The only way to do this is to check the origin and referrer headers.
Unfortunately, server to server this can't be done reliably as the referrer and origin headers would be set by the coder and so can be spoofed easily. For server to server calls you would be better off whitelisting IP addresses that are allowed to make calls to your APIS. In this case use something like How to get Real IP from Visitor? to get the real IP of the server and verify it against whitelisted IPs.
Assuming this is a JS call in browser and not server to server, and that you trust the browser, the only way this can really be done is by verifying the referrer and origin headers. This can still be spoofed with a browser plugin or even with a tool like Postman so I don't recommend it for high security. Here is a PHP example for verifying the origin or referrer.
$origin_url = $_SERVER['HTTP_ORIGIN'] ?? $_SERVER['HTTP_REFERER'];
$allowed_origins = ['example.com', 'gagh.biz']; // replace with query for domains.
$request_host = parse_url($origin_url, PHP_URL_HOST);
$host_domain = implode('.', array_slice(explode('.', $request_host), -2));
if (! in_array($host_domain, $allowed_origins, false)) {
header('HTTP/1.0 403 Forbidden');
die('You are not allowed to access this.');
}
Optionally also CORS headers are good as commented by #ADyson Cross-Origin Request Headers(CORS) with PHP headers

I would like to suggest making a quote or limit for the number of request, so when the paid API reach for 100 request the key will stop working, then the person who paid will not give the key for others. This is not perfect solution, but I would suggest it cause most API services uses it.

Related

Inclusion of header causes requests to not be send

I have react application where I want to add a request-id header to my requests, such that the frontend can tell the backend to undo a specific request. So requests (using superagent) are something like this:
let result = request(method, endpoint);
result = result.set("Accept", "application/json").set("Request-Id", getRequestId());
And when I add the ".set("Request-Id", getRequestId())" I get the error below.
I can see that I can send requests with postman with the request-ID header and I can see that the loadbalancer does not receive any requests other than options calls. CORS is enabled and exposing all headers for all origins.
Does anybody have ideas for what might be wrong? I'm quite new to frontend development.
The answer was I was that my corporate computer that has hardcoded in restrictions in the browser for not allowing custom headers. So I went in and found a standard header that in conjunction with the url could be used for the id so https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Date in my case.
Another evidence for this is that I could make post anything on my corporate computer on Facebook. Since the Facebook application uses custom headers.

How to fetch a Wikipedia webpage with AJAX or fetch()

I want to dynamically fetch a Wikipedia webpage in the browser in order to further process the XHTML with XSLTProcessor.
Unfortunately, this does not work because I can't get Wikipedia to send the "Access-Control-Allow-Origin" header in the HTTP response.
I tried to include the "origin" parameter as it is stated on https://www.mediawiki.org/wiki/Manual:CORS, but without success.
It is important to me to obtain the complete web page HTML as it is obtained by the browser when navigating to that page, so the MediaWiki API is out of the question for me.
This is what I have tried:
var url = "https://en.wikipedia.org/wiki/Star_Trek?origin=https://my-own-page.com";
fetch(url).then(function(response){
console.log(response);
});
Unfortunately, this does not work because I can't get Wikipedia to send the "Access-Control-Allow-Origin" header in the HTTP response.
No, you can't. It is up to Wikipedia to decide if they want to explicitly grant permission to JavaScript running on other sites access to their pages.
Since this would allow users' personal information to leak (e.g. logged in Wikipedia pages display the user's username, which could be used to enhance a phishing attack), this is clearly something undesirable.
var url = "https://en.wikipedia.org/wiki/Star_Trek?origin=https://my-own-page.com";
origin is an HTTP request header, not a query string parameter, and is automatically included in cross origin XMLHttpRequest/fetch requests without you needing to do anything special.

How do I permit cross-origin resource sharing selectively by authorization information?

Some users of my service wish to be able to access our REST API (which requires user credentials) via javascript in a browser. I will not allow this generally due to all of the vulnerabilities associated with violating the same origin policy. But if a specific user needs it and understands what is going on... I wish to add him to a "can make cross origin request" whitelist.
However, I cannot figure out how to selectively return a Access-Control-Allow-Origin header based on http authorization information.
If I do this in javascript:
$.ajax({'url':'url', 'beforeSend': function (xhr) { xhr.setRequestHeader("Authorization", "Basic " + 'base64encodedcreds' ) } })
The browser first sends an ORIGIN METHOD request without the Authorization header. Consequently, there is no way for me to know if I should include Access-Control-Allow-Origin in the response.
Is there some setting in the xmlhttprequest to get it to send an ORIGIN with the authorization? Or is there another way to selectively grant cross-origin access?
There's no way to bypass this behavior -- passing an authorization header is one of the bits of behavior that AAAO is trying to restrict. But you can sidestep it:
Create a separate endpoint URL for this user.
Have this endpoint always return an Access-Control-Allow-Origin that permits access. (Or whatever.)
Have this endpoint also always return 401 (not authorized) for any user other than the one you're trying to permit.
Based on duskwuff's answer that this was impossible I took this close route to not have to create new urls:
Always accept the options query with access-control-allow-origin
If a GET/POST comes in, check the options header. Check user credentials and 401 if user is not whitelisted.
(Very easy to pull off with django middleware)

Difference between localhost and IP address in Ajax request sending

I have a strange problem with native Ajax request invoking.
I am creating the Ajax object and sending the request like follows:
var xmlHttpObj = new XMLHttpRequest();
....
xmlHttpObj.open("GET","http://192.168.16.254:8080/ajax/demoExample.html",true);
xmlHttpObj.send();
When I access the servlet with the URL something like http://localhost:8080/ajax...,
then I am not able to get the response in the client side. But I can see the response in the server side.
Pretty similar way I invoked the request with
xmlHttpObj.open("GET","http://localhost:8080/ajax/demoExample.html",true);
and my URL is http://192.168.16.254:8080/ajax..., then also I am not able to see the response in my client side.
I know the best way to fix the problem.
I can invoke the request with
xmlHttpObj.open("GET","../ajax/demoExample.html",true);
xmlHttpObj.send();
then I don't have any problem with either localhost or IP address.
But still I think why is the difference between localhost and IP address in ajax requesting.
It's more of a security feature than a problem :
The same origin policy prevents a
document or script loaded from one
origin from getting or setting
properties of a document from another
origin.
localhost and 192.168.16.254 are considered different origins. The same goes for two hostnames that point to the same address as they could (and probably will) point to a different site/application on the same server. AFAIK the only way around this is to use iframe for content or JSONP for json. Although in your case relative URLs is the way to go.

Cross-domain website promotion

I'd like to offer a way to my users to promote my website, blog etc. on their website.
I can make a banner, logo whatever that they can embed to their site, but I'd like to offer dynamic content, like "the 5 newest entry's title from my blog".
The problem is the same origin policy. I know there is a solution (and I use it): they embed a simple div and a JavaScript file. The JS makes an XmlHttpRequest to my server and gets the data as JSONP, parses the data and inserts into the div.
But is it the only way? Isn't there a better way I could do this?
On the Internet there are tons of widget (or whatever, I don't know how they call...) that gain the data from another domain. How they do that?
A common theme of many of the solutions, instead, is getting JavaScript to call a proxy program (either on the client or the server) which, in turn, calls the web service for you.
The output can be written to the response stream and then is available, via the normal channels, such as the responseText and responseXML properties of XMLHttpRequest.
you can find more solution here :
http://developer.yahoo.com/javascript/howto-proxy.html
or here :
http://www.simple-talk.com/dotnet/asp.net/calling-cross-domain-web-services-in-ajax/
CORS is a different way than JSONP.
Plain AJAX. All your server has to do is to set a specific header: Access-Control-Allow-Origin
More here: http://hacks.mozilla.org/2009/07/cross-site-xmlhttprequest-with-cors/
If you go the JSONP route, you will implicitly ask your users to trust you, as they will give you full access to the resources of their page (content, cookies,...). If they know that they main complain.
While if you go the iframe route there is no problems.One famous example today of embeddable content by iframe is the Like button of facebook.
And making that server side with a proxy or other methods would be much more complex, as there are plenty of environments out there. I don't know other ways.
You can also set the HTTP Access-Control headers in the server side. This way you're basically controlling from the server side on whether the client who has fired the XMLHttpRequest is allowed to process the response. Any recent (and decent) webbrowser will take action accordingly.
Here's a PHP-targeted example how to set the headers accordingly.
header('Access-Control-Allow-Origin: *'); // Everone may process the response.
header('Access-Control-Max-Age: 604800'); // Client may cache this for one week.
header('Access-Control-Allow-Methods: GET, POST'); // Allowed request methods.
The key is Access-Control-Allow-Origin: *. This informs the client that requests originating from * (in fact, everywhere) is allowed to process the response. If you set it to for example Access-Control-Allow-Origin: http://example.com, then the webbrowser may only process the response when the initial page is been served from the mentioned domain.
See also:
MDC - HTTP Access Control

Categories

Resources