Authenticating WebSocket Connections - node.js

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

Related

Secure rest api node js

I would like to expose a problem to which I just cannot find a solution, although I have been informed several times on the web, the resources I find do not satisfy my curiosity.
The question is the following:
Suppose we have a rest API in node js (express) on the following endpoint -> / stars.
Suppose we want to sell this API with the endpoint/stars to a certain target of customers, the endpoint will therefore only allow customers who buy the API to use it.
The problem arises spontaneously, let's suppose that the pizza company buys my API and that I generate an access token for them, then they would call my endpoint with their token to have the resource, so far very good.
However, all the requests are easily visible.
Example Chrome> dev tools> network and I see not only the endpoint with the full address, but even the payload that is passed!
So as an attacker I could very well (without paying the API) catch the pizza industry using the endpoint/stars with a token, copy everything and slap it on my services by providing the same token and the same endpoint.
I already know the existence of tokens like jwt but they don't solve the problem anyway, as that different token only has the expiration.
Even if it expires after 15 minutes or after 3 minutes, just retrieve another one and provide an identical request with the same token, would anyone be able to direct me to a solution?
The only one I've seen to find a solution to this is Instagram that sends behind a payload of thousands of lines, is it really the only method?
note: it is not even public.
#xVoid
The first thing you can set an encryption/decryption module for your response data with the help of the crypto module in node.js, Here you send encrypted response and the your API client decrypt your response and use it.
You can set a key for your API it means every time your client or user send you a request they have to send that key in the body, not header so other people can't
get your data because they don't have that key, and in express you can set middleware to validate this key is exist or not if not simply return "You are not authorized"
If you aren't getting any point or you want to go deep on particular thing just let me know
You may simply use http-only cookie and send the token in cookie, instead of normal header
A customer using your endpoint should not be sharing their API keys with the end-users.
This means that any customer using your service should create at least a proxy server to your specific endpoint.
CLIENT GET /pizza FROM CUSTOMER -> CUSTOMER GET /pizza?apiToken=<...> FROM SERVICE
Obviously there can be a man in the middle attack between the CUSTOMER and your SERVICE but that's is unlikely to occur using SSL (Related: Are querystring parameters secure in HTTPS (HTTP + SSL)? )
If a CUSTOMER suspects that their api key was leaked they should revoke it and request a new one to your SERVICE.

How can I secure my Node.js backend api data?

I may be a little confused about how backend servers work. Let's say I have a frontend React app with a login. The login information is stored in a database (i.e. MSSQL, MySQL, MongoDB) and I have a Node backend with routes for my app to fetch that information when a user is logging in or doing anything. When both my React app and server are hosted, I would make calls to the api and no confidential information (such as passwords) would be sent back to the client (just maybe a "success" message if the login information appears to be correct on the backend). My question is, what is stopping someone from finding the backend route and putting it into Insomnia to get the password or other sensitive information?
My first thought was to use express-session and auth on the backend to require a user to be logged in to an account to make such requests, but I think there are two issues with that:
How will that work when multiple users are logging in at once? Since the users are not technically physically visiting the api routes themselves, does session still know who is signing in to what account on the frontend? Will the second person logging in override the first person's session even though the first hasn't logged out yet?
If the auth doesn't kick in until a person is logged in, wouldn't someone be able to get the response password data from the login route itself?
Sorry if the question sounds dumb I'm just having a little trouble understanding the security aspect.
It sounds like there's a bit of a misunderstanding of how auth sessions work. There are two primary way sessions can work - either storing the sessions on the backend (older way), or storing session data in a cookie, typically a JWT (JSON Web Token). Cookies are bits of data that are passed from the server to the browser and anytime the browser makes a subsequent request to your server, it passes the cookie back too, so your server will always be able to get that data. The way this works for auth is the following:
A user signs into your application with credentials (username and password).
Your server validates the credentials by checking your database or wherever you're storing them and rejects the request if it fails. (Check out Auth0, Firebase Auth, or other auth services as doing this yourself can be a pain and open yourself up to potential vulnerabilities)
If the credentials are valid, the server generates a signed JWT token that includes data, like the username of the user.
The server responds with the body as well as a cookie containing the JWT, which the browser then stores.
The user requests some user-specific data from your server, and the browser sends the cookie with the JWT back to your server.
Your server validates that the JWT is valid by checking the signature. If it is valid, it uses the username from the token to get the user-specific data. If it is not valid, it rejects the request.
Because the signature occurs entirely on the server side (typically with some hashing algorithm and a secret key that you don't vend publicly), it would be nearly impossible for someone to spoof a JWT token signature. Therefor, your server is able to 1. trust that the JWT token is indeed valid if the signature is correct, and 2. find out what user is requesting data.
Here's a video that helps explain and visualize this: https://www.youtube.com/watch?v=soGRyl9ztjI
And here's a library for creating and validating JWTs in Node: https://www.npmjs.com/package/jsonwebtoken
Hopefully that answers your question!

Technique to detect request modification on server side using JWT

I want to know a technique with which server can identify if data coming in the request is not modified by an attacker. We are having REST APIs on server side which will be invoked from a mobile app client or a browser. I was thinking of using JWT (JSON Web Tokens). But not sure how it will achieve this. People have used JWT for session management purpose mostly. I do not need the session management. I just want to detect the request data modification. need some help here...
It depends on what type of attacker you wangt to protect against, but the TL;DR is you don't have to do anything as any such protection is either unnecessary (with some special case exceptions as detailed below) or useless.
Protecting against a valid user modifying his own requests
There is no point in this. Any secret you would use for such protection (for signing requests, essentially) would have to be sent to the client so that it can use it to sign whatever it wants to. But if it is sent to the client, the user already has it and can use it to sign any modified request. You have to architect the application in a way that security is enforced on the server side and valid users can't forge requests that they are not supposed to make.
Protecting against a man-in-the-middle attacker
Let's suppose you want to protect requests against somebody between the user and the server. If you access the server over a secure channel (https), it already does this for you, you don't have to implement anything in addition to that.
However, I can think of special cases. First, you may be worried about intermediate proxies that terminate SSL, like for example a company proxy that serves https websites with its own certificate, set as a trusted root on company clients. This is fairly common practice, but usually you as the application developer don't want to deal with this. The other thing is when you don't want to use SSL, but I'd say it's rather a special case when you are worried about request integrity, but not about confidentiality.
Anyway, if you are in a situation where you do in fact need to maintain integrity in another way besides (or instead of) https, you could give your client a secret and sign requests with that secret, like for example using HMAC or another message authentication protocol. You would take relevant fields from request headers and also the whole request body, create an HMAC of them with the secret and attach that to the request. The server, having the same secret for the client could create the same hash and verify if the client had the secret and also that the request sent is the same as signed by the user. Note that to prevent replay attacks, you would also have to include a timestamp and/or a nonce header in the signature.
The question then is how you get this secret to the client securely, and depending on your circumstances, this can be a tricky one to solve.
Edit
I just realized you had csrf as a tag to the question. Be aware that csrf has nothing to do with modified requests, and you do have to implement protection against csrf in general.
The JSON Web Signature is a cryptographic mechanism designed to secure data with a digital signature unique to the contents of the token in such a way that we are able to determine whether the data of the token has been tampered with or not.
source: php-authorization-jwt-json-web-tokens
You can use JWT to verify client requests but the client need to request a token (at least once) before any verifiable request.
Tokens are created on server side only using a secret key (never sent to the client) used to encode/sign the token, the client can decode and access the token but doesn't modify it, just send it back as it is.

Font End secure authentication only allowed to come from a specific website

I have a private rest API. Each of our clients websites currently performs server side authentication over SSL to start an order with us. Each client has a unique client id so I can identify which client is making the request and reject any client id which doesn't exist in our system. Is there a way to do this securely from the front end of a clients website with javascript? I can't put the client id in the client code since any developer could look at the source code and figure out how to spoof requests from another site. I think checking referrer headers is not reliable as well? Would really like to know the best practice for situations like this.
Not sure if I understand your question correctly, but typically you would encode your client id as a claim in the security token issued when authenticating your users. As the security token is signed by the issuer, you can verify that the token is not modified when you receive the token on each request.
Obviously you will need to use the https protocol to prevent the token from being stolen. See here for more information.

How do I secure REST API calls?

I'm developing the restful web app that using some popular web framework on the backend, say (rails, sinatra, flask, express.js). Ideally, I want to develop client side with Backbone.js. How do I let only my javascript client side interact with those API calls? I don't want those API calls to be public and be called by curl or simply by entering the link on browser.
As a first principle, if your API is consumed by your JS client, you have to assume, that it is public: A simple JS debugger puts an attacker into a position, where he can send a byte-for-byte identical request from a tool of his choice.
That said, if I read your question correctly, this is not, what you want to avoid: What you really don't want to happen is, that your API is consumed (on a regular basis) without your JS client being involved. Here are some ideas on how to if not enforce, then at least encourage using your client:
I am sure, your API has some sort of authentication field (e.g. Hash computed on the client). If not, take a look at This SO question. Make sure you use a salt (or even API key) that is given to your JS client on a session basis (a.o.t. hardcoded). This way, an unauthorized consumer of your API is forced into much more work.
On loading the JS client, remember some HTTP headers (user agent comes to mind) and the IP address and ask for reauthentication if they change, employing blacklists for the usual suspects. This forces an attacker to do his homework more thoroughly again.
On the server side, remember the last few API calls, and before allowing another one, check if business logic allows for the new one right now: This denies an attacker the ability to concentrate many of his sessions into one session with your server: In combination with the other measures, this will make an abuser easy detectable.
I might not have said that with the necessary clarity: I consider it impossible to make it completely impossible for an abuser to consume your service, but you can make it so hard, it might not be worth the hassle.
You should implement some sort of authentication system. One good way to handle this is to define some expected header variables. For example, you can have an auth/login API call that returns a session token. Subsequent calls to your API will expect a session token to be set in an HTTP header variable with a specific name like 'your-api-token'.
Alternatively many systems create access tokens or keys that are expected (like youtube, facebook or twitter) using some sort of api account system. In those cases, your client would have to store these in some manner in the client.
Then it's simply a matter of adding a check for the session into your REST framework and throwing an exception. If at all possible the status code (to be restful) would be a 401 error.
There's an open standard now called "JSON Web Token",
see https://jwt.io/ & https://en.wikipedia.org/wiki/JSON_Web_Token
JSON Web Token (JWT) is a JSON-based open standard (RFC 7519) for
creating tokens that assert some number of claims. For example, a
server could generate a token that has the claim "logged in as admin"
and provide that to a client. The client could then use that token to
prove that they are logged in as admin. The tokens are signed by the
server's key, so the server is able to verify that the token is
legitimate. The tokens are designed to be compact, URL-safe and usable
especially in web browser single sign-on (SSO) context. JWT claims can
be typically used to pass identity of authenticated users between an
identity provider and a service provider, or any other type of claims
as required by business processes.[1][2] The tokens can also be
authenticated and encrypted.[3][4]
Set a SESSION var on the server when the client first loads your index.html (or backbone.js etc.)
Check this var on the server-side on every API call.
P.S. this is not a "security" solution!!! This is just to ease the load on your server so people don't abuse it or "hotlink" your API from other websites and apps.
Excuse me #MarkAmery and Eugene, but that is incorrect.
Your js+html (client) app running in the browser CAN be set up to exclude unauthorized direct calls to the API as follows:
First step: Set up the API to require authentication. The client must first authenticate itself via the server (or some other security server) for example asking the human user to provide the correct password.
Before authentication the calls to the API are not accepted.
During authentication a "token" is returned.
After authentication only API calls with the authentication "token" will be accepted.
Of course at this stage only authorized users who have the password can access the API, although if they are programmers debugging the app, they can access it directly for testing purposes.
Second step: Now set up an extra security API, that is to be called within a short limit of time after the client js+html app was initially requested from the server. This "callback" will tell the server that the client was downloaded successfully. Restrict your REST API calls to work only if the client was requested recently and successfully.
Now in order to use your API they must first download the client and actually run it in a browser. Only after successfully receiving the callback, and then user entry within a short frame of time, will the API accept calls.
So you do not have to worry that this may be an unauthorized user without credentials.
(The title of the question, 'How do I secure REST API calls', and from most of what you say, that is your major concern, and not the literal question of HOW your API is called, but rather BY WHOM, correct?)
Here's what I do:
Secure the API with an HTTP Header with calls such as X-APITOKEN:
Use session variables in PHP. Have a login system in place and save the user token in session variables.
Call JS code with Ajax to PHP and use the session variable with curl to call the API. That way, if the session variable is not set, it won't call and the PHP code contains the Access Token to the API.

Resources