Sending Push Notification Subscription Info from Web App to Server Securely - javascript

Once a user subscribes to push notifications, I get the subscription info in my JavaScript code. I want to send this information to the server for storage to be used for future notifications.
I assume that the endpoint for the AJAX POST request should be public (the website itself is publicly accessible). Should the endpoint be completely open? Should I use some token generated on the server that expires after a certain period of time?
My concern is that, if it's open, it can be used maliciously to post data to my server. Should there be some validation of the data? If so, what kind of validation applies to subscription JSON objects?
What's the best practice for doing this securely (if any)?

Related

Storing Subscriptions for Web Push notifications securely JS/Node.js

I have read several introductory articles about implementing Web Push notifications for desktop browsers but am unable to understand the security part behind storing the obtained subscriptions from users's browser on backend server.
There are many websites that ask for permission to send you push notifications without authenticating/registering on those websites first. If I do grant them the permission and they store this permission string onto their backend server for later use, who's to say I wont generate another subscription string and send it to their backend server's endpoint that they used to save my subscription? and therefore flood their database with subscription entries.
What is the mechanism of identification and validation of received subscription on the backend server when there is no authentication/registration of users available on the website?
To illustrate better:
Website JS code asks browser for push permission -> I grant it by pressing 'allow' on the popped up window -> they take it and store it on their server using HTTP POST for example. Using a simple script I establish connection with the same HTTP endpoint and POST more subscriptions in the same format as the endpoint expects, therefore flooding the backend database.
After a lot of reading and consulting with one of the popular Web Push notification services I confirmed that it is indeed possible to flood backend server's database with forged subscription URLs when there is no authentication available on the website that uses the notification service.
The ways to defend against such attack are similar to the ways of defending agianst DDoS attacks: IP filtering, deleting database entries manually, etc.

Storing User-Id in Client Side App for API Request

I have a Node-Express REST API where I can make a GET request to a user controller - /users/:id - where :id is the user-id number stored in the database. I also have a React-Redux client side app that makes a call to the API. In order to make the request, the client app needs access to the user-id, but I’m currently not sure of the best way to store the user-id on the client side.
For additional context, my API sends to the client a JWT token on login that holds the user-id; the client app saves the token in localStorage. When the client makes a request, the API verifies that the user-id in the decoded token matches the Id contained in the URL before sending a response back to the client.
I see two potential solutions:
Decode the JWT token on the client and use the user-id stored in the token to make the API call. I think this is a potential security risk, since I believe I would need to store the secret on the client app. Also, anyone who has the token can gain access to the user’s information.
API sends the user-id on authentication, and the client stores it in localStorage. (I don’t think storing it in the Redux store would work since the user could refresh, clearing state of the user-id). My sense is that this is not best practice, since I don’t see many other client side apps taking this approach.
Which one of the two is a better solution, or is there another approach that I'm not considering?
You're right about option #1. Never decode the token client-side. That would require the client-side code to know the "secret", which would expose it to anyone looking through your Javascript.
Option #2 is good, assuming that you still send the token with every request for security purposes. For storage, yes you have to store it in a cookie or in localStorage, or as you say it will be lost on refresh.
To get the ID in the client-side code, have your client-side code read it from the cookie / localstorage. There are libraries for that; react-cookie reads cookies, for example. Either you can do that every time you need to access it, or you can read it once during the initial page load, and then dispatch it into the Redux store.
In your /users/:id endpoint you can check to see if an :id was provided and then if not, extract the id from your JWT token otherwise use the id that was passed into the API call.
If that isn't acceptable, then you could use option #2 but use sessionStorage instead of localStorage

Secure user token between SPA HTML5 app and web service?

Sorry if this has been asked a few times, but can't quite find out a solid response.
I want to secure the login procedure and session (kind of) between an HTML5 app and a PHP web service. I present the user with a login screen that uses HTTPS with the server, and then give the client a random GUID that is stored in a database with their time of login and last request time, and their actual user ID that I store for their row on a users table. So the GUID might be different every time but the user ID it maps to on login can only be seen server side.
I'm vary weary when it comes to authentication and never really dealt with a HTML5/JS app against a web service like this. I've usually developed ASP .NET sites and used sessions.
I've recently discovered JWT tokens which encrypts data stores in the token string that is contained on the client and passed to/from the server. Is this safer than what I'm doing? Should I be using JWT as opposed to this GUID mapping I have now?
What I'm aiming for is a session-less request to a web farm which could put you on to any specific web server, and the request is validated to see if that request has came from a valid logged in user.
Any advice would be welcome :).
Thanks.
Using a JWT token is totally safe provided you don't encode sensitive data in the token because the token can be decoded without the secret.
What you can do is to have two key pairs (private/public) RSA keys.
Private for encoding the token and sending it to the client on login success
the client saves the token to maybe a cookie, HTML5 localstorage e.t.c,
on every request, the client passes the token via the request header back to the web server, then the web server verifies the token with the public key. whilst decoding the token and getting the GUID from the token and can then proceed with the request.
This workflow can work across several server side languages as there are many JWT libraries for them.

OAuth2 flow in web frontend and REST API

I'm working on a project based on Phalcon which consists in two different stand-alone subprojects: a php + angular frontend and a php REST API.
I protected the API with OAuth2, using PhpLeague OAuth2 Server. The API server is the OAuth2's authorization server AND resource server.
This is the actual flow:
The user can browse the public endpoints of the frontend, and when hits a private page, gets redirected to the login page;
The login page has username and password, POSTs them to the frontend server;
The frontend server calls a public method on the API server, which is expecting a Password Credential Grant: it validates the credentials and sends back an access token and a refresh token;
The frontend server caches both the access and refresh token in session and uses it for some API calls: the first of those is the '/users/me', which gets info about the current user and its ACL on the frontend sections;
The frontend server sends the page to the browser, which loads its javascript files.
Now, OAuth2 states that access tokens should be short-lived and refresh-token should be long-lived: in the frontend server logic, the API calls which receives a 401 (caused by the expired access token) are retried by sending first the refresh token to obtain a new access token via a Refresh Token Grant. If this second call is rejected, I assume the user is no more logged in (refresh token expired / revoked).
The pages are using Angular to perform data and ux/ui management. My question is:
should the Angular code call directly the API server?
Actually the first thing my javascript code does is to get a config object from the frontend server, which contains the access token too, and uses it to make the calls to the API server. The problem with this is that i should rewrite again the "refresh token logic" in javascript (after it expires, i get 401s), and by what I have read on the subject i understood that it is better to not make the refresh token visible to the client (as it can generate new access tokens).
So i was thinking about a "two step approach", where every javascript API call goes to an endpoint on the frontend server which relays it to the API server, but this is obviously slower (JS -> FRONTEND -> API and API -> FRONTEND -> JS).
What is the correct approach? It's not very clear to me if the frontend should be considered as two clients (php + js) which should work separately or not, as I imagine that an hypothetical iOS app would be making calls 100% against the API server.
I have used the same approach in my own projects. The problem that we have is that the client is not secure. In order to generate / refresh a token, you need to pass secure information to the authorization server.
I have done the same as you basically, let the back-end handle the tokens and their temporary storage. You cannot and should not trust the client with important information which lets you generate tokens. In terms of delays, I wouldn't worry about it too much since you're not going to be doing that much extra work, you won't even notice the delays. I have a system like this built and used by hundreds of thousands of users with absolutely no issues.
Now, you have said a few things in here which make me wonder what you are doing.
OAuth2 is not a user authentication system, it's an application authentication system. You don't pass a user and their password and generate a token for them, you pass a ClientID and ClientSecret and they generate a token for you. Then you have an endpoint which gives you the user details for this user, you pass your userid or username and get the details of that user.
A token expired does not mean your user is logged out. Those are two completely different things. How are you going to expire a token for example, when your user wants to log out? You can't, your token will still be valid until it expires after the set amount of time has passed.
A token can be used for let's say half an hour, but your user may use the website for 1 hour. So before you hit any API endpoint, you could check ... has this token expired yet? if yes then you can go and refresh it and keep working without having to bother your user with a new login screen.
The whole point of an OAuth2 system is to make sure that only authorised clients can access it. A client is not a user, it's an application. You can have a website for example and you only want users of that website to access your API.
You can have endpoints like ValidateUser for example, where you take a username and a password and return a yes or no and then you log your user in based on that.
Irrespective of language/framework, second approach is secure and better than first one because to get access token by providing refresh token to Authorization server, it still requires Client ID and Secret which should never be passed to Browser for security reasons.
In first approach, to make a direct call it will not work if your Authz Server is hosted on different domain than your frontend server because of Same Origin policy of browsers. Even if they are on same domain, still you are exposing Client ID and Secret which will compromise your frontend server

Security of an API server: login with password and sessions

As described in a previous question, we are in process of rebuilding a web service using two completely separated layers (servers and domains) for the frontend (HTML5 web app) and the backend (probably using Node.js).
The frontend will be served by a CDN over SSL, on the "www" subdomain (www.foo.com), while the backend will be an API server on the "api" subdomain. The API server will of course communicate over SSL and will only provide JSON-formatted data (with PJAX as an option we are evaluating).
We would like some feedback on our current design proposal.
Login
User fills a form with username/password and submits it locally.
The client computes the hash of the password locally (PBKDF2) and submits it to the server (e.g. POST /login with the fields username and hashed password)
The server checks the hash against the one in the database, and if successful will respond with a session key.
The client stores the session key in its local storage (HTML5).
If the login is not successful, after 3 failed attempts a captcha will be required too.
We considered the use of OAuth for authorization, but because of technical reasons we need the client on the "www" subdomain to see the password in cleartext at least for a few seconds. (that's another story :) )
Session
The session key is sent in clear text (on SSL) along with every request and is used by the API server to authenticate the user.
Additionally, each request must contain a "seq" field (for example, timestamp in milliseconds) that has to be greater than the previous one used. If this doesn't happen, the session key is revoked.
The session key expires after 30 minutes.
Before expiration, the client may request a refresh.
The server itself may refresh the session key after 10 minutes along with a response to a request. (e.g. in the response for the method GET /something there is a field "session key" which contains a replacement session key).
When the session key is refreshed, the old one is revoked instantaneously (or after 30 seconds - even if two concurrent requests are extremely rare in our application).
Additional security: both the web server (www) and the API server will only respond to requests over SSL. The web server redirects users not using SSL to the SSL version (using HSTS: the redirect will happen only once for each user, hopefully reducing the risks for man-in-the-middle attacks).
Do you think this design (if implemented correctly) provides good protection? Is there any other recommendation you think we should consider? Thank you.

Categories