1

i need some advice. i want to build a JS app that will run on a client browser and communicate with ajax with my server. the problem is that i want to give this client some api-key so i can authorize it on my server. security wise its a problem because as long that this key is sending through the ajax call, anyone can replicate this call. i don't want to ask the client to create some proxy server and "curl" the request. i want it to be directly from the client to my server. what is the best practice for that except verifying the client by his IP or domain?

Paz Lazar
  • 229
  • 5
  • 14
  • AJAX cannot be done cross-domain. JSONP is a different matter. – Charlotte Dunois Mar 18 '16 at 20:01
  • @CharlotteDunois orly? And what's CORS? – Matías Fidemraizer Mar 18 '16 at 20:02
  • @CharlotteDunois Orly? Yarly :D You're wrong. Static files like stylesheets, images and even scripts are cross-domain per se. CORS was introduced to allow cross-domain requests for AJAX (aka XmlHttpRequest). – Matías Fidemraizer Mar 18 '16 at 20:09
  • @CharlotteDunois For example, when you perform a request agains any Google Maps API resource, your browser will first perform a request with verb OPTIONS to get the required CORS headers so the actual request can be done by-passing default same-origin policy – Matías Fidemraizer Mar 18 '16 at 20:11
  • Duplicate? http://stackoverflow.com/questions/15496915/how-to-implement-a-secure-rest-api-with-node-js – Roman Dibikhin Mar 18 '16 at 20:24
  • Adyen does something like what you want, they will send you a custom build script file with all the code needed to work with payments, including an encrypt code using SJCL, and a public key that their script will use to encrypt the card data so you can HTTP it throw your server and then into their API. Somehow they know a private key in their end and it changes per request, i don't know how they do it, but i know they do it :-) – Zorkind Dec 23 '17 at 11:09

2 Answers2

1

You could use something like a JWT.

You create an authentication object

{
  apiKey: asd-dfgdf-e3234,  // not even necessary (read on)
  expires: 12213493434,
  ip: "x.x.x.x"
}

You base64 encode it and then sign it with a private key (or hash function on your server) and attach the signature as a base64 string to the "payload".

eyBhcGk6IDEyMzQ1LTU2Nzc4LCBhcGk6IDEyNy4wLjAuMSB9.Tm90IFNlY3VyZSE=
|  -------- payload ----------------------------| -- signature -|

Pass this to your client. Every request sends this token. It can be examined and verified to be tamper free (match the requesting IP no key necessary).

Wainage
  • 4,892
  • 3
  • 12
  • 22
  • it doesnt help because if i can encrypt it with JS, any other hacker can decrypt it, or even worse - just using it... – Paz Lazar Mar 18 '16 at 20:58
  • You don't encrypt it. You sign it. You take the base64 text and sign it on your server. That "hash" is not currently reversible unless the hacker has your private key. The hacker can try and modify the token but a quick check on on server (is this payload signature valid) will reveal the forgery. If it is valid you check the IP with the requesting IP to make sure they match. – Wainage Mar 18 '16 at 21:18
  • @Wainage BTW this isn't enough... source IP address can be also impersonated........ – Matías Fidemraizer Mar 18 '16 at 21:19
  • You're essentially sending an ID card to the client. If a hacker intercepts it you server will fail on IP or signature and you will be able to tell they are using someone else's ID – Wainage Mar 18 '16 at 21:19
  • @Matias IP cannot be impersonated. That would send the traffic elsewhere. If you mean man-in-the-middle attacks then I'm hoping you're using https ... otherwise all your secrets belong to the NSA. – Wainage Mar 18 '16 at 21:22
  • @Wainage http://stackoverflow.com/questions/24576394/is-it-possible-to-spoof-or-impersonate-a-destination-server-ip Check the part of "Evil transparent proxy in your LAN"....... – Matías Fidemraizer Mar 18 '16 at 21:25
  • @Wainage Check that, at the end of the day, OAuth2 doesn't sign access tokens... One can use an access token from other client, but in order to get this access token, they should first attack some client's machine and steal the whole access token, and if this happens, the whole client can re-generate their API key and all previous issued access tokens are automatically invalidated, since the API key can be used as the private key to encrypt the token... – Matías Fidemraizer Mar 18 '16 at 21:29
  • @MatíasFidemraizer But in this case they would have to compromise your server. Stealing the token is of no use since they can't change and sign it. Any changes will invalidate the signature and a "fake" signature will be spotted on your server. This method is super light weight and orders of magnitude easier to understand than OAuth2 – Wainage Mar 18 '16 at 21:46
  • @Wainage At least with .NET I've been able to create an OAuth2 authorization server in minutes. No one is implementing OAuth2 from scratch, because implementing a security layer from scratch is a bad design decision: you don't have the resources to evolve an own security protocol and make it stable enough to consider your API secure. – Matías Fidemraizer Mar 18 '16 at 21:51
  • Rolling your own is ALWAYS a bad idea. JWT's however were created by the team at [Auth0])https://jwt.io). It's been battle tested. – Wainage Mar 18 '16 at 21:55
0

Sadly, you can only check the Referer header, and issue API keys with a whitelist of allowed referers.

The main issue here is Referer isn't secure at all: it can be changed. That is, anyone can impersonate a client...

AFAIK, the point is your clients should be able to re-create their API keys, and they should do it once they've realized that someone is impersonating them. And they should keep re-re-re-creating until the bad guy stops impersonating them...

Make it as hard as possible...

One possible approach to make things harder to unwanted clients impersonating actual clients can be using access tokens with expiration.

Also, a good practice can be that one client can request a limited number of access tokens everyday. If these access tokens have a 24 hour expiration time, and there's a limit of 3 or 4 access tokens per API key and per day, if many bad guys try to impersonate one of your clients, well, only 3 will be able to do so.

You can also define a limit of an access token per day. This could make things even harder.

BTW, you can argue that anyone can steal the whole access token too. Well, this is the time to re-generate the API key and get a new one. Finally these bad guys will get tired of getting their access tokens invalidated...

Best solution

Actually, if your API needs to be secure and it's private as you've said in some of your comments on my own answer, there's no choice here: you need to go the server proxy way.

I would check node-oauth2-server to use OAuth2 to secure your API.

Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206
  • So its still doesnt help. If i check the ip or domain, is it secure enough? Like i want to have a domains white list and check the referrer on the server. Hacers can replicate this request? – Paz Lazar Mar 18 '16 at 20:23
  • @PazLazar IP can be also modified... You can be sure that your best bet is working to make things hard, but there's no way to be 100% sure that youre API will be consumed by the expect and actual consumer – Matías Fidemraizer Mar 18 '16 at 20:41
  • @PazLazar My advise is also the design decision by well-known companies like Google. Their Maps JavaScript API works this way... the API key is public like yours, and you can configure allowed referrers and there's a quota limit of requests per day... – Matías Fidemraizer Mar 18 '16 at 20:42
  • you must understan - i dont want to try and limit - i must. this is not some weather or maps api the i can limit and make the bad people work hard. the data stored on the server is very private and my clients can't let anyone see it. so generating some token for the client will not help, nor using referrer. the only thing i can do is just to ask the client to use server proxy for generating token this the api-key i give him for the first call and then using this token for the next calls... – Paz Lazar Mar 18 '16 at 20:56
  • @PazLazar I already understand this, but you're asking to avoid a request proxy... If you want a 99% secure system, then you must go this way. BTW, some can mimic some web site or HTTP client just pasting a request in something like Fiddler or Postman, and use the whole access token. And if you don't store the access token in your browser, then anyone can make a request from Fiddler or Postman to your API through some client site............ – Matías Fidemraizer Mar 18 '16 at 21:15
  • @PazLazar Actually the 99.9999999999% security can be got using client certificates. But sadly I doubt you would have any success forcing any visitor of the whole site to install the whole certificate.......... – Matías Fidemraizer Mar 18 '16 at 21:16
  • @PazLazar So, yes, the server proxy is the best you can get if you implement it in the right way. You should use OAuth2 since it's actively developed and you shouldn't try to implement a security algorithm yourself because you'll end up with a lot of security flaws... – Matías Fidemraizer Mar 18 '16 at 21:18
  • well... so thats what i'll do then... i will build for my clients some php file that they should add on the server... and a config file so they will modify its api-key. now i should hope their server will not stuck for every second ajax call... – Paz Lazar Mar 18 '16 at 21:30
  • @PazLazar And why you don't want to use Node? I've provided some link in my updated answer ;P – Matías Fidemraizer Mar 18 '16 at 21:36
  • @PazLazar You can build an OAuth2 server easily – Matías Fidemraizer Mar 18 '16 at 21:36