I'm hosting a service which requires consumer to pass API key. It can be consumed by both server side (Ruby,Python etc) and client side applications using Javascript.
Is it possible to use the API key securely from a Javascript only app? I can't think of any way to achieve this at the moment
Not if the key is sensitive data.
All Javascript is visible to the users, so even an encrypted key could be decrypted. If the key must remain secret, it must never be used in any client-side code or content.
Communication of the key must be server to server, if the key needs to remain completely confidential. A javascript-heavy UI will still need to use a server as a intermediary to proxy calls to your service. A full javascript-only UI is not an option, unless the customer is willing to leak his service key to his users.
Related
I wanted to know how I can do that only my android application, developed with native react, can access my API node js. So my server will be accessible only from my site, using a simple whitelist of domains, and from my app
There is no way to guarantee this. A client controls everything that happens on client side. If an application contains protection mechanisms against client interference, it can be reverse-engineered.
A way to protect unauthorized clients from connecting to the backend is make backend requests with API key that is transmitted as encrypted (hashed) string and verified on server side. Abused API keys need to be blacklisted.
Since hashed keys can be extracted from API requests, a way to make this more complicated is to make hashed API key dependent on specific requests, e.g.:
fetchData(url + '&api_key_hash=' + md5(SALT + url + SECRET_API_KEY))
api_key_hash still can be verified on server side but is useless for a client who wants to get unauthorized access to backend API. The only way for a client is to get SECRET_API_KEY.
Since client application can be reverse-engineered to get unencrypted API key, a way to make reverse engineering more complicated is to not store the key as plain string and obfuscate the application.
Note that while these measures don't guarantee that the application won't be reverse-engineered to extract API key, obfuscation can complicate things for application developer, e.g. debugging and analyzing crash reports. To my knowledge, reverse engineering of React Native application that doesn't make use of any protection besides JS obfuscation is trivial.
I have been following this tutorial on how to create JWT authorization in an asp.net Web API application.
In my case the authentication server will be the same server holding the resources (ie all done in the one asp.net Web API application), so I can see that sharing the "secret" used in encoding the JWT is not a problem when it come to the route authentication and authorization.
However, I will have have an Mobile application (using the Ionic framework) where I would like to be able to validate and decode the JWT so that I can enable/disable different parts of the UI. So I will need to do this in JavaScript.
So, I would not want the application to have access to this "secret" string used to encode the JWT.
My questions are
How can I both validate and decode a JWT without having to have this "secret" key?
Reading other posts, perhaps the validation is not possible, but decoding is. In this case there is the possibility of incorrect UI enabling, but in the end the web API call will fails as this can do the validation as well. Is this the correct way to go about it
Is there another way of creating the JWT where we have private and public key, so the JavaScript can have the public key and use this for the validation?
Thanks in advance for any help!
You can use signing algorithms like RS256 that are based on asymmetric cryptography. This means that signing a token requires access to a private key, which can be safely stored server-side, and validating requires only access to a public key.
JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with HMAC algorithm) or a public/private key pair using RSA.
(source: Learn JSON Web Tokens; emphasis is mine)
As you mentioned, the decisions you make on the client application running on a user device should only be done from a user experience perspective and all authorization decisions should still be done again on the server-side.
The best analogy is the Javascript form validation that can be done on the browser to provide the user with instant feedback but that still requires the same or even greater validation to be done on the server-side as an attacker could easily bypass the client-side ones.
Additionally, you should take in consideration:
This interpretation of a token by a client application despite the fact that the token is intended for use in the API is acceptable if you're okay with having a really tight relationship between the client application and the resource server. From your description, all the parts of the system are under your control so this seems fine.
The use of RSA256 has associated performance costs when compared with the use of HS256 which is based on the shared secret you mentioned. If this is an issue you can even question yourself if you really need to validate the token client-side; if all the decisions you make are purely cosmetic why bother with the validation. The premise would be that someone trying to provide a fake token would only see options or links that would immediately fail when accessed due to the server-side rejecting the token
I have a private API, where I'm using basic authentication as my security layer. Right now the API is consumed by my iOS app, so no one is able to see the key pair.
I'm creating the same app for the web now, using React and Javascript and need to consume the same API using basic authentication.
How can I use my API key pair in Javascript without exposing that key pair to the public? Is such a thing even possible?
As #Andrew mentioned, that is not possible, you can just make it harder to get, but it'll be there somewhere on the client code, and that's enough to say you're exposing it.
If you're open to alternatives, I suggest you to use a per user authentication for the first request, and then a token based authentication for further requests. That token can be a JSON Web Token and it's the flow I'm talking about:
This is the way it works, taken from JWT's official documentation:
In authentication, when the user successfully logs in using their
credentials, a JSON Web Token will be returned and must be saved
locally (typically in local storage, but cookies can be also used),
instead of the traditional approach of creating a session in the
server and returning a cookie.
Whenever the user wants to access a protected route or resource, the
user agent should send the JWT, typically in the Authorization header
using the Bearer schema. The content of the header should look like
the following:
Authorization: Bearer <token>
TL;DR: No.
If the client needs to be able to connect to the API directly, there is no surefire way to prevent them from discovering the API key, as they must, by design, be able to access it in order to send it in the request. You can take measures to obfuscate it, by storing it encoded (but the client will have to have the decoding algorithm as well).
This is in fact also true with your iOS app. Someone can reverse engineer the binary or intercept the requests and view the header, discovering the API key.
A possible “solution” is likely to have each client get their own API key, be it temporary or permanent, that is in someway locked to their account/device/session to limit reuse.
CryptoJS has functions to create HMAC from a message and the secret key.
How can this be secure considering that the secret key must be stored in plain sight in the JavaScript source deployed on the client ?
Anyone can take the key and issue similar requests to the server under the identity of the original client of the API. Isn't "identity" the problem that HMAC is supposed to solve ?
All in all, I do not understand the purpose of HMAC in client side JS since the key can't be kept secret.
Is there a use case to computing HMAC in JavaScript ?
JavaScript now has WebRTC where two clients can communicate peer-to-peer, this would be a scenario where clients can generate and use their own "secret".
There are some cases where client -> server could be usable as well. If your server was "dynamically" serving the JavaScript then it could insert a "secret" based on the clients current session/login. Assuming you are using HTTPS (if not there could be a man in the middle slurping up the "secret") then it's not unreasonable to assume that communication to the server signed with that specific "secret" (even over unsecured HTTP) belongs to only that client.
How can this be secure considering that the secret key must be stored in plain sight in the JavaScript source deployed on the client ?
Each client should get their own key/secret which enables them access to the resources they are supposed to have access to. This is effectively no different than a user knowing their own username and password. Their user/pass combo only allows access to the resources they need. The same should go for the key pair.
Anyone can take the key and issue similar requests to the server under the identity of the original client of the API. Isn't "identity" the problem that HMAC is supposed to solve ?
Yes, of course if someone gets your key and secret they can issue requests as if they came from you. Simply don't give out your secret to others. Having it in JavaScript doesn't matter at all. Sure, the user can see it but unless they take that key and secret and put it somewhere else, it isn't a problem.
I have a system where a user logs in through normal means (username/password, OAuth, OpenID, etc.) and is immediately issued a key/secret for making API calls. The client-side application uses this key/secret to actually do its work. The issuance of this key/secret is done over HTTPS. I wanted to use HMAC for my API since I wanted the user to be able to pre-sign requests to be used in the open. This method enables me to keep HMAC for the usual administrative GUI as well.
I like the way Google Maps' api is consumed, using a script include, but I'm worried:
My api is "semi-private", that is, accessible over the internet but should allow for secure transmission of data and some kind of authentication. The data should remain private over the wire, and one consumer shouldn't be able to get at another's data.
How can I use SSL and some kind of authentication to keep the data secure, but still accessible "horizontally" from a plain HTML page with no server-side proxy required? Do I need to manage keys? How will the keys be posted to the server without being intercepted? Can I use OpenId (or some other 3rd-party authentication) to authenticate api users, or do I have to create my own authentication mechanism? I've been all over Google and can't find a good guide to designing and deploying my API securely.
Right now I'm using REST and AJAX to consume them, but cross-domain calls are impossible. Any help or a pointer in the right direction would be much appreciated.
I'd probably use a dynamically-generated script tag with an SSL URL that included a key in the query string that was public-key encrypted. The server would use the private key to decrypt the query string parameter and return script that included the relevant information (or didn't, if the key was invalid). Or something along those lines. But I'll admit that I haven't actually had to do it in practice.
I'd also look for prior art, like Amazon's S3 service.
So:
User provides secret
Client-side code uses public key to encrypt the secret
JavaScript appends a script tag that includes the URL
Server handles the script request, decrypts the secret, checks it, and sends back the relevant response.
You may well need two cycles, because otherwise the request to the server could be re-used via a man-in-the-middle attack. That would be:
JavaScript appends a script tag that requests a unique key (probably with some confounding information, like the source IP and some random further key)
Server responds with a one-time key tied to that IP
User provides secret
Client-side code uses public key to encrypt the secret, including the unique key from #1
JavaScript appends a script tag that includes the URL
Server handles the script request, decrypts the secret, checks it, and sends back the relevant response.
The response could well be encrypted (to some degree) using the random key included in #1
None of which I've actually done. (Or have I? BWAa-ha-ha-ha...) FWIW.
OAuth might help with this situation by having the user login to the 3rd-party application and allowing your application to access the 3rd-party on their behalf by using a request token when you make xhr requests. http://oauth.net/documentation/getting-started/
========
The reason for using a server-side proxy boils down to the Same-origin policy built into web browsers: http://en.wikipedia.org/wiki/Same_origin_policy
Essentially the browser only allows requests to be made to the address in which the page comes from (e.g. facebook.com can only make requests to facebook.com URIs). A server-side proxy solves this issue by making requests to servers outside the current origin. Server-side proxies are also the best practice for making requests like this.
Check out the opensource javascript Forge project. It provides a javascript TLS implementation that allows secure cross-domain xhr requests. It might be of use to you:
http://digitalbazaar.com/2010/07/20/javascript-tls-1/
http://digitalbazaar.com/2010/07/20/javascript-tls-2/
https://github.com/digitalbazaar/forge
One potential solution:
Set up an Apache server to run your site.
Get an SSL certificate for your site.
Install the apache mod that comes with Forge to setup a cross-domain policy that allows other sites to access yours.
Host Forge's TLS implementation on your site along with your site's certificate in PEM format.
Tell other sites to include the javascript from your site and use it to make secure calls to your site to do whatever it is you want to.
(3rd party) Page uses OAUTH or something similar to authenticate the user and get a token from your server.
Page loads an IFRAME from your server via SSL passing the token along for authentication.
The IFRAME can communicate securely to your server via SSL
Use easyXDM or something similar to communicate between the IFRAME and the 3rd party page, using some limited RPC-like or socket-like API you create.
Or if you really don't trust the third party - do your authentication inside the iframe (no need for oauth then, just use a plain html form) and communicate anything the outer page needs to know about the user using easyXDM.
Not too sure of what the question is exactly, I take it you're attempting to do a jsonp-like call to [https://secure.com] in order to process/display data on [http://regular.com]?
Can the two servers talk to each other? How about something like this:
User logs in on [https://secure.com]
Upon authentication, secure.com generates an token (lets call it syntoken) and passes it directly to regular.com (server-to-server), maybe like a session_id, some arbitrary message, and an otp cipher (lets call it syncipher).
Broswer receives a session_id cookie, and Secure.com then redirects the browser to http://regular.com/setcookieandredirect?session_id=blabla&otpencryptedsynmessage=blabla
Regular.com looks up otp cipher using session_id as a key, and decrypts otpencryptedmessage "blabla."
If decrypted message matches the original message in the syntoken, we can verify user is logged in [regular.com] and regular.com generates another token (lets call it acktoken, lolz) and passes it directly to [secure.com], consisting of session_id, some arbitrary ack message, and a different otp cipher (lets call it ackcipher).
Regular.com then sends the browser a cookie consisting of otpencryptedackmessage (let's name this cookie "verified_session").
Finish loading the page.
From there, you can do jsonp-like calls to
https://secure.com/getscript.js?query=dataname&verifiedtoken=(verified_sessions_cookie_value)
where secure.com/getscript.js will take the verifiedtoken, lookup the ackcipher based on the original cookie session_id sent by [secure.com] as the key, and decrypt the otpencrypedackmessage. If the decrypted message matches the ack message, render the script file.
It's kinda like a 3-way handshake. The secret sauce is that the servers have to be able to talk to each other directly to pass secret keys discretely. You don't have to use the same session_id for both servers, I was just using that as an easy point of reference to find a way to access the syn/ack otp ciphers. The ciphers must be completely hidden from public.