Securing a POST Request in NodeJS from Backend Application - node.js

I'm wanting to receive a POST request sent from a backend java application that sends user account information (e.g. username, email, etc.) and will create an account with the given information. What method can I go about where the api I have can only be used from my java backend (so people can't just start creating accounts themselves)? I assume a method would be using an api key but I have had trouble finding resources on how to implement that. Could someone help me and steer me in the right direction?

The most common method is by the use of API Keys.
You would have a list of valid clientsIds for your NodeJS Server (Note that the JAVA backend server would act as a client for your Node JS server when creating users).
Along with the list of valid clients, you would also need to store a valid API Key for each client.
The Java Backend would send you its clientId and the API Key in the POST request. You would need to validate the client id and the API Key for that client.
Once both are validated, you can assume the request to be from your Java backend.
Both the list of valid clientIds and the associated API Keys should be stored in environment variables. The API Keys should be different for the same client in different environments.
Another way I have implemented this in the past, and I consider to be more secure, is by use of RS256 Algo JWT Tokens with the use of Public and Private keys.
Your Java backend should generate a Public/Private key pair and provide the Node backend the public key.
Along with the POST Request, the Java Backend will generate and sign JWT token using the Private Key and send it to your NodeJS Backend.
Your NodeJS backend should verify the token using the public key.
The JWT Token generated by the Java backend should be short lived.
Every time the Java Backend has to send a POST request, it should generate a new JWT token.
The use of JWTs are more secure as they can be short lived and you dont have to worry about a token being leaked. If the API Key gets leaked, you will have to co-ordinate between the two backends to start using a new API Key. However, if a JWT token gets leaked, the same token cannot be used once it expires. It would be safe to have the JWT token short-lived, may be 1-2 minutes. Since the Private and Public keys are not being sent along with each request, there is a lesser chance of it being leaked.

Related

Correct Application Structure to Safely Verify Cognito JWT Tokens

I'm building a React application that uses API Gateway and Lambda on the back-end. I'm going through the process of integrating Cognito authentication. I've completed the following:
Generate user pool
Upon login redirect to my React application with Auth Code
Extract Auth Code and send it to Token Enpoint
Receive back the id, access and refresh JWT tokens
I covered all that in detail in a post here: AWS Cognito Notes
What I'm confused about is the concept of verifying the signature of the JWT tokens. The AWS Docs describe how to do that here: https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html
In short I have to download the JSON Web Key and then match it to the key on the tokens. It's not clear to me how this makes the process any safer. That key is publicly available. If I was conducting a man in the middle attack I could simply get that key and then attach it to my phony JWT token.
Which makes me think that I have a fundamental misunderstanding of this process. Should the Auth Code and JWT tokens not be sent to the React app in the first place?
Should I be setting the User Pool redirect URL to API Gateway, and have that trigger a Lambda function (that contains the client secret), to retrieve the JWT Tokens and THEN send the JWT Tokens to the React app? But then I would have the same problem of not knowing if the Tokens were legit I think? The tokens much be verified AT THE CLIENT, right?
If anyone has any insight on this or could point me to a good article I would much appreciate it.
You can use an API Gateway Authorizer to do this for you. It will check the header for ID Token and check if it is valid for your userpool. Expired and invalid tokens are rejected.
You can read more about this here: https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-integrate-with-cognito.html
The answer to this was that the JWK can be stored in any capacity with the client. The JWK is publicly available, however the public key cannot be used to fake the signature itself, because the signature can only be generated with the PRIVATE key.
I did a full write up on this topic here:
https://ncoughlin.com/posts/verify-decode-cognito-jwt-tokens/

NodeJS Authentication for Multiple RESTful API services

I would like to seek help from you guys.
I have multiple RESTful API services running in NodeJS Express. Each API is hosted by different NodeJS with different port. And in our front-end, it is accessible via reverse proxy.
We are now moving to a secured services. However, there's a problem in authenticating with the services. The front-end should request 1 auth token upon login that can be used in accessing the internal API services (API is also accessible in our public domain /api/).
How can we solve this problem?
Current Setup
You could issue a signed JWT token upon login (see https://jwt.io/).
The front end application has to send the token back with each API call.
Each API server has to know in advance the key (public key or symmetric key depending on the type of the signature algorithm) and use the key to check the signature of the token is valid.
If it is valid, the API server knows it can trust the token content, and decide whether to serve the request. The token would contain the identity of the user, expiration time, ...
Note that signing the token does not encrypt the data: if you need to convey sensitive data through the token, it needs to also be encrypted
Thus it is not necessary to establish a session and then share the session across the many API instances. Knowing the key is enough to trust the token content
To pass the JWT in API calls you can use a header:
Authorization : Bearer theBase64EncodedToken
Of course, it is up to you to check if this scheme satisfies the security concerns related to your application.

What are the recommended strategies for authorising API calls from my react native application to my node server?

I have a react native application that I want to make API calls from. I am getting confused about how I should be authorising these calls on the node back end.
Method 1:
User logs in to application and authenticates, I then return a JWT with refresh token. This is then stored client side / in react native app and is sent upon each request. If token expires, then refresh using refresh token.
Method 2:
Create API key for each client. When a user creates an account, I create an API key (or maybe access key and secret key like AWS does) and send that with each request.
Is there a preferred / recommend method out of these two? Perhaps they are not mutually exclusive? Do I still need to provide an API key to my react native app so that it can make API calls and then I use JWT for authenticating users?
In my personal opinion,
You may go for the Method 1, since it is not secure to store / create API keys or Secret keys on the client side.
JWT are more secure, you may read the following article
In the Method 2, you will most probably try this approach
Generate Api key based on client IP or the device token, whatever suits you, and set an expiration time including the AES techniques, then decrypt it on the server, check the client's IP against the requestor IP and also the expiration time.
Complexity and time taken to do Method 2 is much more that Method 1, also considering I might have not covered all the security use cases.
Do I still need to provide an API key to my react native app so that it can make API calls and then I use JWT for authenticating users
You can make the http calls normally. The recommended way is call your token generation api and then authenticate other valuable api's based on that token if you're using JWT
Hope it helps.

Authenticating WebSocket Connections

This may seem like a pretty noobish question, but I just recently got into Node.js and am needed to make sure that the same kind of Authentication that occurs in my Laravel App happens in Node.js.
Clearly, I need to use an API, but I am confused about how to do it in a manner that is secure. I have looked into this article:
https://www.ida.liu.se/~TDP024/labs/hmacarticle.pdf
And have looked through their algorithm into building an API. But I do not understand how it would be secure.
According to the post, you store a public and private key in a Database. The public key can be seen by everyone but the private key is, well, private. However, when sending it to the server, you send a hashed version along with other data, of the private to the server.
This sounds all well and fine. However, does that not mean that the public key and the hash is public, thus the private key is exposed as well?
For example lets say I try to establish the following connection
ws://example.com/pull?public=A89-3NJ2-KAN-NKSN1&hash=QmFzZTY0IHRoZSBoZWxsIG91dCBvZiBtZSBiYWJ5Li4uLi4u
What stops another user from just sharing this link giving an unrelated user access to it?
The article you linked to describes how to authenticate one single request, not an entire session. That is, the user sends the public api_key along with some request data that describes the specific request for the API (like, { "action":"latest_price", "symbol":"GOOG"} for a stock market API).
To authenticate, the user also uses a shared API-access secret key as an HMAC key to compute HMAC(secret, api_key+request). No one else can compute this if they don't know the secret. Only the user and the server should know secret, because it's basically the user's password to use the API.
The situation you describe is very different: you're using a WebSocket, so I assume you'll be sending requests interactively. If you want to authenticate the entire socket session, this approach doesn't make sense, since it's designed to authenticate a single request. You can apply this approach to individual requests inside the WebSocket connection.
For authenticating a new connection (i.e., "what logged-in user is opening this connection?") using auth cookies is appropriate, just as you would for a traditional HTTP connection.
Below, I'll assume that the purpose of the Web Socket is to send only one request (which really makes me wonder why it's a WebSocket), so that the request-level authentication makes sense.
What stops another user from just sharing this link giving an unrelated user access to it?
Nothing. Do you want someone else to submit a specifc request, while impersonating you? Then by all means, give them that link and tell them to use it.
The credentials in the link include an HMAC of the API request (plus your identity) that only you can generate, as the sole owner on your API secret key. If you give that HMAC to someone else, they can submit it and impersonate you for that specific request. However, they cannot create more requests, because they don't have your API secret to make more HMAC values for different requests.
In fact, if you didn't want that request to be submitted, you should not have used your secret to create the authenticating HMAC in the first place! Why did your authenticate a request that you didn't intend to be submitted?
Have a look at this
Essentially
make a "websocket preauth" request to the backend from the browser using the site's normal auth
backend returns a CSRF token in the response body and sets a "websocket auth" cookie with SameSite=Strict in the response headers
attempt to establish a websocket connection with the backend, with the addition of the CSRF token in a query parameter
the backend checks
that the websocket auth cookie and CSRF token are valid
that the value of the Origin header matches an approved domain
the backend sends a response and upgrades the connection to use websockets

Restricting traffic to server from only my mobile application

I have a requirement to secure my JAX-RS resources and only accept requests that originate from authorized mobile applications. Is this possible? How can this be done?
All of my resources are protected already with user authentication, the goal here is to reduce user ID fishing attempts. I know one solution would be to keep the response error with an invalid user ID generic, but the application is very large and at the moment this isn't possible.
One idea I came up with is to use JWT tokens signed with a shared secret. Then I could add an Authorization filter on the server to check the signature. If it doesn't validate then discard the request. Does this sound like a viable option?
My concern is the security of the shared secret on a mobile device, could it be compromised with a rooted device?
Using tokens is the preferred way. But the secret key is not shared. Only the server has access to it. That secret key is used to generate the message authentication code(MAC) of the JWT. Since secret key is only known by the server, no one else can generate a JWT with a valid signature. Secret may be persisted or application scoped.
Once a client is authenticated using credentials, server must send a signed JWT to the client.
That JWT must contains necessary information to identify the client and state(if necessary).
Then client send that token in a header field along with all the other requests.
Server validates the JWT using secret key and process the request.
Even though client can change the JWT body, he cannot get it verified. That's the whole point of using a signature.

Resources