1

I am developing a plugin for Nylas N1 (implements Node). The plugin will be using an implicit flow to authenticate the user, as I understand that is the best way to handle client-side applications. I have a vague understanding of how state (or nonce) works, but do not know how I should verify the requesting application.

The source code of Nylas plugins are not encrypted and are easily browsable on the end-users file system. It seems to me that an app could pretend to be Nylas by modifying headers and other parameters when requesting the nonce from my server, so I am unsure of how I should go about validating these requests.

TylersSN
  • 111
  • 2
  • .. what? Nonces **by definition** are *random* values that are *generated on the fly* and are used to avoid replay attacks. So ... they should never appear in the source code. You should only have: `nonce = random()`, you encrypt this value together with the message for the client, and when the client responds you check that the reply contains the same value. Are you sure that you are talking about *nonces* and not something else? Your question is too vague... Clarify exactly what kind of protocol you are dealing with and how "nonces" come into play. – Bakuriu Sep 22 '16 at 13:43

2 Answers2

2

I'm one of the core maintainers of Nylas N1. I think the other answer is good general advice, but here are a couple more tips specific to N1:

  • If you want to secure a process or algorithm, you can write it in a native node module which is distributed in binary form. We don't currently do this, but many other JavaScript based apps do (Spotify's DRM is in a C++ library they distribute alongside the JS.)

  • If you want to authenticate the client with a service, use 3-legged OAuth. With 3-legged OAuth you distribute the Application ID but not the Application Secret in the client. When the user signs in, a Code is returned, and you hand that Code to your own server (the third leg), where the Application Secret is used to exchange the code for a token, which is sent back to the client. This process is a pain to implement, but ensures that the only sensitive tokens the client ever has are for accounts the user authenticated.

  • If you want to store tokens, user API keys, etc. client-side, we suggest using node-keytar. It's already available in N1 via require('keytar'). It provides a simple API for storing secrets in the user's keychain on Mac, Windows, and Linux. We currently use it to store N1 API tokens.

Hope that helps! Feel free to reach out to me or other Nylas engineers on our community slack channel at http://slack-invite.nylas.com/

Ben Gotow
  • 121
  • 2
1

In general, you cannot trust ANYTHING from the client - this is the problem that https://en.wikipedia.org/wiki/Trusted_Platform_Module is intended to solve, but that's a long path to go down. The best thing to do is authenticate the user and ensure all actions by that user are authorized, regardless of whether they come from a real client app or from someone playing around with your api, via MITM or via direct access.

As @Bakuriu notes above, nonces are random values, used once, different all the time - they are used to prevent replay attacks and as tokens in CSRF prevention schemes, for instance. What you are thinking of is, perhaps, an API key - a value used to authenticate a user (where user could be a program). As you say, you cannot bake that into the application, since the user can access it via disassembly, source code inspection or via network traffic inspection.

So, go down the route of not trusting the client. That means that each user needs to be authenticated, regardless of what client they use. Then you verify that that user has permission to do the action you want. You can issue api keys to each user.

One potential scheme : have them verify who they are by logging in to your website and generate a key for them that they can provide to the app - the app can save it in the user's keychain if you want to keep it convenient. When they try to perform an action, verify the api key against your database. As long as this is all done over secure channels, this is reasonable and used by many services.

Another : have the user authenticate to your service (potentially via Login with Facebook or whatever - oauth/openid are good). Then verify the user directly on each requests.

Both have the advantage that they are easy to revoke and that you can limit the user to what they are allowed to do, regardless of how they make the request.

ALL authorization verification and authentication verification should happen on the server side, always. The client is in enemy territory and can never be trusted (short of TPM ugliness).

crovers
  • 6,311
  • 1
  • 19
  • 29