Just started looking a JWT and the examples I have seen first require the user to do a POST request with the body of the request containing the username and password in plain text.
After this request has been authenticated, a JWT is sent which is then used is further requests.
Clearly I am missing something here but have I not just sent unsecure data on my first request? Is this where I would need HTTPS?
JWT doesn't give you security out of the box it's main point is to make sure that the Token wasn't changed by untrusted authority. It just verifies that the data inside is correct.
However, the JWT itself, the data block of it is readable by anyone, you can just parse it on the client, and read the userName / email / from it, if you want to, so an attacker could read it too, if the data block itself is not encrypted.
HTTPS would encrypt all the data wich is passed between client <-> server. It has nothing to do with authentication, its just a protocol, you should use it anyway, either with JWT or not.
JWT are used for authenticating a user that already authenticated himself to the server before, and are really useful in stateless environments, not really in stateful environments.
The purpose of JWT is to store enough data on the user, so that the server that receives it can use it to decide if the user is legit and what he can do. They are really useful in distributed environments, because then you can just pass the JWT from one server to another, and as long as they all hold the signing key, they will be able to authenticate the user only based on the token.
The username and password are only required for the server in the first request, so the server can authenticate the user against a database of users for example, and then, every request after will use the token, making the server to be able to authenticate the user without another round trip to the database on every request.
As far as HTTPS goes, I would say - use it for everything. In today's wireless networks everywhere, your data is much more exposed than before.
Related
This is a subjective question, although I believe this is not opinion based. The only reason of asking it here is that I could not find satisfying answer even after reading multiple articles on JWT Authentication.
I recently started learning JWT and found that it is a 3 part token issued by server to client for authenticity along with passing data like user-scope/roles/permission etc in forms of claims.
My question however are:
The claim part of token still is base64 encoded string which can easily be parsed using atob/btoa. So is the transmission really secure ? What is the real gain here ?
There are multiple articles on generating and sending token to UI. However, almost no good articles on what UI does exactly with it. Is it a common practice to decode the token using atob and use the content within it ? Or is there a different way of validating and retrieving data from it.
Is it really secure to transmit data via headers. I mean is it safe against things like MITM, XSS etc.
I would really appreciate some efforts from the expert in resolving these queries ?
For question #1, the gain is not on the client side. If you can't trust what you received from the server, you can't trust it no matter how it's obfuscated/encoded/encrypted/. The point is that you send this token back to the server. On the server, a quick check will tell that this token is legitimate. Imagine a complex login scenario, where MegaCorp looks up permissions for the user across 739 subsystems, combines them into a single payload, and then doesn't have to do that again on further requests. When the client sends the token back, it validates that you are properly logged in and uses the permissions to do further processing.
For #2, you can put whatever you like into this payload, so long as it isn't meant to be too secure. I mostly use it for basic user info and for application permissions. So I can paint the user's name and offer a link to the specific user settings page. I can check whether the user has access to an administrative page or whatever permissions I need to check. While a malicious user can fool the system by manipulating that data client-side, and can therefore, say, see the admin page, when the call goes back to the server to get the data for that page, the token is either illegitimate and the request will be rejected, or it won't contain the proper permissions and, again, it will be rejected.
I don't really know enough about security to attempt an answer to #3.
Some people use JWT only for isLoggedIn, which is fine, but I think misses some useful possibilities. Used properly, this can be the single mechanism to capture user information for both the client and the server. But the important side to my mind is the server. This can be done in many ways on the client. But it's hard to find something better for the server.
The claim part of token still is base64 encoded string which can
easily be parsed using atob/btoa. So is the transmission really secure
? What is the real gain here ?
The transmission is secure (cannot be read/modified by others) if you send the token via https. JWT contains 2 important parts: a payload and a verify signature.
The signature can be produced and verified only by one person and prove that the payload is legit for that person.
Here is a simple use case:
Client send is credential to the Auth server to receive the right to publish something
The server receives the credential and valid them through a complex process then send back to the client a JWT saying: {I give Client the right to publish signed the Auths erver}
The Client store locally the token
When the client needs to publish something he sends the JWT and is work to server B which share the signing key with Auth server.
Server B verify easily the token and publish the work of the client
Another example of usage is authentication via mail only.
There are multiple articles on generating and sending token to UI.
However, almost no good articles on what UI does exactly with it. Is
it a common practice to decode the token using atob and use the
content within it ? Or is there a different way of validating and
retrieving data from it.
In general, the client wants to obtain a token from some server to send it back later. The client cannot verify the signature because he does not share the private key with the server, he is not a source of trust.
Is it really secure to transmit data via headers. I mean is it safe
against things like MITM, XSS etc.
Using https it is safe: Are HTTPS headers encrypted?
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
I've been following this blog post (https://auth0.com/blog/2015/04/09/adding-authentication-to-your-react-flux-app/), and am confused on an aspect of JWTs.
The post above seems to test if the user is already logged in by checking to see if there is a JWT stored as a cookie, and if so, it simply decodes it to find the username and other information, and redirects the user to the authenticated page.
I'm wondering what is stopping someone from adding a fake JWT cookie to gain access to an authenticated portion of the app? I must be missing something obvious. In other words, when maintaining a session, how does the frontend ensure that the JWT is one that was "signed by the server" or something, and not one that was fraudulently created to try to gain access?
In many apps, someone can add a fake JWT to gain access to parts of the front end that you only want them to see if they are logged in. But then, they also have the front end running on their own computer and can change the code to do the same thing.
The back end server encoded the JWT using a key that should not exist on the front end, and when you pass the JWT back to the server the server will decode it BEFORE processing your request. So it knows that someone used your login credentials earlier, that it sent out the JWT in response, and that someone is sending it the JWT again. This blocks attacks on your API from people without the (real) JWT.
It also has advantages over session cookies in that it is stateless on the server side and it makes certain cross-site request forgery attacks harder in traditional browsers because an attacker can't embed a request to your site and trust the browser to add your session cookie.
But it's only one part of a larger security solution.
The key here to JWT's security is the "secret"-- a key that should only be on trusted servers (or with your authentication provider, if using a third party). JWTs are encrypted using this secret. It can be a passphrase, but JWT also supports public/private key encryption, so the secret can also be a private key.
So, in your case, what's preventing the user from creating new JWTs on their end is, unless they know the secret, the encryption they use to create their own JWT will not work on the server, which, if coded correctly, will prevent the user from authenticating the way they wish to.
What is the challenge/response method to securely authenticate with a Server without HTTPS (without sending out password)?
I have an app (Javascript client) that connects over CORS (authenticate) to our backend which in turns will return a token containing the claim (JWT) over non-HTTPS. The REST is stateless so we do token-based and not have session at all.
When the client gets that token, (containing claim) it is added to the header for each request of the client and therefore the backend knows which User Id is doing that request and do the appropriate thing. So far this works for us. My concern is with the authentication process and with the security of each request.
To authenticate the clients sends out email and hashed password pair, however I want to know if there's a more secure way even without using HTTPS for now. I've read to not send the password but do a challenge/response, but what is the implementation of that idea?
And last question would be, even if we get around with the authentication process securely, how about on each request which contains the token with claim can it be secured also?
There is no possible way to do this securely without HTTPS. For your server to authenticate users, you need some kind of token (cookie, adding to requests like you have, etc.) However, the problem is that, without https, an eavesdropper can add javascript to your page. They can then capture the token and use it themself (stealing all the user's data), or modify it. If you want your product to be in any way secure, you need HTTPS.
Edit: I guess you could store some information about the device sending the request (user agent and such), and only allow the token to be used on that device. However, an attacker could just fake the user agent when they reuse the token, so this wouldn't be too hard to bypass.
Challenge response is a mechanism to send passwords in non-clear way.
1°/ client and server must share a cyphering key : best is to manually add certificate on client but could be a little bit heavy. Another solution is to store the key only one time into localStorage.
2°/ client requests a challenge to server : this is a "phrase" generated by server
3°/ client concats its password with this "passphrase", ciphers and send response to server : Challenge => Response
4°/ server decrypt message, search and remove its passphrase to get password.
I am trying to create a secure way for users to log in to and perform certain authorized actions on my custom website. I am trying to have good security without the use of SSL.
At login now, this is what I am trying to improve:
User types in credentials (e-mail and password)
Client browser (JavaScript) one-way-hashes password with SHA-512, sends credential as login-request
Java-based backend receives request, further encrypts the received password-hash(with salt etc) to fit the hashing in the database (which was created on registration), checks for match, and returns a cookie containing a fresh token.
Backend also connects token to user in the database, and the backend will therefore know who future requests is coming from based on this token (without ever sending credentials in the request)
The idea is that if someone manages to pick up such a cookie (or the initial request), it's impossible to get the user's password.
This is great and all, but there's still the problem with repeat-attacks and man-in-the-middle-attacks, when 'bad guys' pick up a request, and uses the token to do stuff on another user's behalf.
By reading up on how to prevent this from happening, I have found that an acceptable method of preventing this could be adding a 'counter' to the token in the cookie, to show how many times the token has been used.
Let's say the cookie initially contains a token and a counter of 0, like this cookie-content: "abc123:0", where the token is abc123, and the counter is 0. It's suggested that the client increment the counter every time a request is made. Let's say a user wants to send a chat-message to another user. The cookie attached to this request will then contain "abc123:1". The backend stores the counter as well as the token, and checks both values. If the received counter is more than the stored counter, awesome. If a 'bad guy' picks up the requests and try to repeat it, the counter will still be 1, and the server will reject it, as the stored counter also is 1(or more).
This sounds great, but I'm not sure how this is any more secure? The 'bad guy' can simply edit the counter-value in the cookie to be 99999 and succeed?
I figured the content of the cookie (the token and the counter) should be hashed in some way, so that the content isn't plain-text. However, the client is HTML/JavaScript; the 'bad guy' can simply check which encryption-method is used, and decrypt it. All scripts are public.
I read something about improving this by sending a one-time 'secret' from the server to the client before the request is made, but I don't see how I can implement this. I guess, on requesting www.example.com/chat, I could generate a random 'secret', and send this to the client, and the client can add this to the cookie when sending a chat-message, or use it as a key, so that an encryption would be more secure, but how would the server know the secret upon receiving the request? How can the server reverse this? The server has to know the secret when decrypting it, so where should it be stored? Plain-text in the cookie next to the hash? Then the 'bad guy' can do the same thing. In the database? Upon requesting www.example.com/chat, should the backend know WHO is requesting it, so that it can be stored in the database along with that user? In that case, how should the backend authenticate the user, to be sure that there's not a man-in-the-middle or repeat-attack requesting /chat?
What is this method of security called, and is it possible to use it for what I need (with HTML/JavaScript)? If not, what are my options, beside SSL?
It's called bad security that does not rely on trust.
The client needs to fully trust the server, otherwise everything - including the page that is used to enter the password - cannot be trusted. Currently the only way of establishing trust is the certificate store that is provided within the browser (you should be able to trust the browser!). And the only software that is able to use it across browsers is SSL/TLS.