9

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.

Henke
  • 4,445
  • 3
  • 31
  • 44
Akhilesh
  • 927
  • 1
  • 6
  • 21
  • 1
    AFAIK Google APIs are only restricted in the way you describe when calling then via AJAX. And the reason for that is primarily CORS restrictions. If you call them from a non-AJAX context then that doesn't apply. And it can't apply - "domain" isn't really a concept in a more general HTTP request context. A request can be made from a home computer to an API, and that machine is not part of any domain, yet the request is still legitimate – ADyson Feb 21 '21 at 16:07
  • Also, to further the comparison with Google, they generally only use API key authentication for requesting data which is already public - e.g. public calendar data etc. If you wanted to access something private (e.g. email) you have to use a stronger authentication method. Ultimately though, no matter what authentication system you use, if someone decides to share their credentials with someone else on purpose that's their problem, not yours. and there's not a lot you can do about it. – ADyson Feb 21 '21 at 16:10
  • 1
    @ADyson Thanks for reply, But the idea of this API is to provide Video service and play it on their window after successful authentication so as in this case we only want to play video on those domains which are allowed. Otherwise if they share their API it is gonna be our loss as we are providing video access for free. – Akhilesh Feb 21 '21 at 16:13
  • Well you can implement CORS restrictions for Ajax access, which restricts access to specific domains. but it's unclear how your actual video playback works. Maybe you can also implement maximum concurrent logins like Netflix does. It's not very clear if you are providing this service to websites, or to consumers directly? The context makes a difference to how you implement it. – ADyson Feb 21 '21 at 16:17
  • 1
    How can I do CORS restriction ajax, as the whole point where i stuck is how do i can know from which domain i get the request. – Akhilesh Feb 21 '21 at 16:22
  • In PHP you can check `$_SERVER['HTTP_ORIGIN']` - if it's an AJAX request then normally this is populated with the domain the request came from. You can then use that to set appropriate CORS response headers. See https://stackoverflow.com/questions/8719276/cross-origin-request-headerscors-with-php-headers – ADyson Feb 21 '21 at 16:36

2 Answers2

7

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

Andrew Winter
  • 1,116
  • 1
  • 8
  • 27
  • But then how does other API's does it ? – Akhilesh Feb 25 '21 at 07:49
  • 1
    @Akhilesh they do it using combinations of the methods mentioned. They may whitelist by IP. They use CORS. They use stronger authentication for more valuable data. They use mitigations like limiting concurrent use. I already explained to you how Google API does it. You seem to think there is some magic answer that we are deliberately not telling you. There isn't. – ADyson Feb 25 '21 at 08:16
  • 2
    @Akhilesh if your project is a serious one and you have big concerns about this issue, you should employ a security consultant with experience of web applications and APIs. Then, when they have analysed all your requirements and constraints and use cases in greater detail than is possible here, you might get some more bespoke advice and a roadmap. Out of necessity, in this volunteer-run site, you will tend to get general advice and we don't have time to ask you about every single detail of your app in order to suggest the idea solution for your exact scenario. That's work you need to do. – ADyson Feb 25 '21 at 08:27
  • 2
    @Akhilesh P.S. of course there are non-technical mitigations too. Set terms of service which make clear that the user's account can be revoked if they share the credentials or API keys inappropriately with others, and that someone using them inappropriately can be banned from the service. And copyright/license your content in an appropriate way such that there would be legal consequences for mis-use of it. This will not deter everyone but it might help. Consult a lawyer with relevant experience for more details. – ADyson Feb 25 '21 at 08:29
  • 1
    @Akhilesh potentially some other considerations here too: https://www.quora.com/How-does-Netflix-prevent-users-from-downloading-streamed-video-content . I suspect Netflix clients are authenticating with the server using more than just a simplistic host key. – ADyson Feb 25 '21 at 08:35
1

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.

Evara
  • 75
  • 8