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?
Related
There is something very basic I do not understand. In order for JWT to be secure both the client and the server must share a secret.
However, the client is typically a JavaScript application running in a browser on some remote completely unknown client machine.
Suppose I am the author of both the server and the client code, how am I supposed to ensure the safety of the shared secret on the client side?
You assume the secret is shared. It doesn't have to be. (And it only ever should be shared between systems trusting each other. You usually cannot trust the client that executes your JavaScript.)
A typical use for JWT is for the Server to produce signed data using the secret and sending the signed data (without the secret) somewhere (e.g. a client) without persisting it. When it gets the data back, it can verify (using the secret rather than a persisted copy of the data) that the data hasn't been tampered with since is has been signed.
What application does that use pattern have? You can e.g. implement token-based permissions that way and thus have authentication without identification:
Let's assume you provide a cloud storage service. A user can upload a file, to which you assign some identifier, let's say 5. You generate a shareable URL that has the JWT-signed data "may access file #5" as one of its parameters and display that URL to the user. The user and everyone they share this link with can then access that file through that URL. You just have to verify that the signature is a valid signature created by you and that the signed data indicates the correct file. Of course, if someone with whom the user has shared the URL distributes it further, other people may get access that way, too. But without knowledge of the URL, the file isn't accessible.
It is the same as sending cookie to client on auth and then relying to it for other actions.
Yep, you can't ensure safety of client's cookies, they can be stolen. Same as jwt token can be stolen.
Good part about jwt is that token itself is not being the part of comminication as cookie, so you can use it even in http communications - even if somebody gets the payload or header of user's request he wont be able to create new request with other data, which is possible in case of cookies usage.
I have designed a simple HTML/CSS and JS/jQuery application, and now it's the moment of authentication integration. On the server side, I have done a REST API which allows clients to get some data. But, now I want to authenticate each request with access and/or session token.
I read many websites to find agreements or advice to establish security between the client (JS) and the REST API (PHP), but unfortunately I found nothing or not interesting.
So I ask you to enlighten me (if you want) to know what to do, what to implement, conventions, etc.
What I read:
Designing a Secure REST (Web) API without OAuth
Token Based Authentication for Single Page Apps (SPAs)
I cannot post more links according to my reputation...
Just give me advice, ways how to store private token (RSA) or access/session token for API.
Don't hesitate to give your reaction, and tell me if I'm not exact or something else.
You need to use a token-based authentication for your REST API. JWTs are the best in this particular case.
Why Use JSON Web Tokens?
Tokens are stateless. The token is self-contained and contains all the information it needs for authentication. This is great for scalability as it frees your server from having to store session state.
JWTs can be generated from anywhere. Token generation is decoupled from token verification allowing you the option to handle the signing of tokens on a separate server or even through a different company such us Auth0.
JWTs have fine-grained access control. Within the token payload you can easily specify user roles and permissions as well as resources that the user can access.
This will be your typical authentication flow process:
A user signs up/logs in, during the login process, you generate a JSON web token from the server and return it to the client. Since you are using PHP, you can use this library for the generation and signing of the token.
Store the JWT returned to the client on the browser Web Storage(local/session storage). It can also be stored in a cookie.
For subsequent HTTP requests from the client to the server, you send the token via headers/query, then the server validates the token. If it's valid, the user is authenticated otherwise the user is rejected.
BTW, if you don't want to implement authentication yourself, you can use Auth0, check out VanillaJS SPA and PHP quickstart
I hope this information helps. Cheers!
Authenticating REST API's with JavaScript front-ends is difficult because the JavaScript code is completely readable by anyone visiting the site so storing any kind of login credentials is no good.
With a standard Server to Server set-up simply using basic auth over HTTPS is more than enough but basic auth is no good for JavaScript SPA's as the credentials are in plain view.
For SPA's you need to be looking at JSON WebTokens, as your back end is in PHP you need to be looking at PHP-JWT from firebase. You can get the code here: https://github.com/firebase/php-jwt or recommended using composer:
composer require firebase/php-jwt
The package makes implementing JWT super simple see the docs for a complete code example. Also check out the JWT for a complete break down https://jwt.io/
I suppose Jwt (https://jwt.io/) is good solution for your question.
On the client side you can store the token on the localStorage or some global variable (for SPA).
You can transfer token on the HTTP header or as request parameter. It works.
Also you can see https://auth0.com/blog/angularjs-authentication-with-cookies-vs-token/
I've been investigating JWT and I'm very interested in using it. I like that it doesn't require state checks on the server, due to the digital signature and payload contents.
The thing I'm having a hard time is validating the client. I understand that the signature allows the server to say "yes I issued this token, it is valid", but I don't totally understand how the server can verify the client is who it says it is.
Digital signature makes sense from the server side, but the client can't sign anything to verify who it is because browsers can't keep secrets. This is the one part I haven't been able to wrap my head around. If the browser can't keep the secret, how can it add data to the token (like a nonce, or information about the resource it's requesting) to be included in the signature, similar to how oAuth 1.0 works.
Is this not supported? Are there other way to validate the browser is who it says it is? What if my client has a security hole that leaks tokens? If the client isn't validated, couldn't anyone use those tokens? I don't think "short expiration times" is a good solution to that problem.
Can someone help me wrap my head around this part of JWT?
To add on to what Tim B said, I have used tokens where the secret key has the browser AND ip appended to it like so: (PHP Example)
$secret_key = 'kajsdfkljk' . $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT'];
That does seem to work, however, if you're bouncing around from network to network, then you would have to login each time, in which case you could just use the user agent and not the ip.
Another thing to note here is that if there was a leak of some sort, you could always change the secret key, in which all tokens issued from your server would no longer be valid.
Also, without using https connections, tokens can be very dangerous to use for authentication.
Verifying the client isn't compromised isn't really possible, as it could definitely leak a token. Token expiration helps mitigate a leaked token being dangerous for too long, but as you mentioned isn't a fool proof solution. You could do something use the requesting user's current IP address as part of the signing key to help mitigate against a leaked token being used elsewhere. It could still be used via XSS locally, but not as easily used by phishers.
My understanding is that the client wouldn't add information to the token, it would simply pass it beside the additional info. Separate POST vars -- a token to "verify" identity, the other vars to define additional parameters.
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.
I'm working on a new site that utilizes a service-oriented architecture, with pure JavaScript on the front-end, accessing web services for data via RESTful AJAX calls.
It shouldn't be of particular importance but my stack is:
javascriptMVC
jQuery
Bootsrap
ASP.NET Web API (C# on .NET 4.0)
MS SQL
From this article I've figured out some good ways of securing my web service calls once I have a private key shared between the client (JavaScript) and server (REST services via Web API). However, I'm struggling with how to establish the private key to be used for encryption.
Bad Idea #1
The initial though was to set it at log in which would occur over HTTPS, then store it on the client in a cookie for reuse. The problem is that our SSL cert is for https://secure.example.com, while our site is on http://www.example.com - so I wouldn't be able to access the secure.example.com cookie from www.example.com.
Bad Idea #2
My next thought was to pass it encrypted and signed via a URL parameter from the HTTPS login to the HTTP post-login page like so:
http://www.example.com/processLogin?key=[encryptedKey]&sig=[encryptedSig]&user=[userid]
encryptedKey and encryptedSig would both be encrypted with another private key that only exists just for that transaction. It would be created at log-in and assigned to that user in the database. On the HTTP side, all of this gets passed to the server which decrypts it, validates the signature, removes that private key (to guard against replay attacks - essentially a nonce) and returns the decrypted private key ([encryptedKey] decrypted).
From then on out, the decrypted value of [encryptedKey] would be used for all future transactions. The problem is that the decrypted private key would have to be sent over the line via HTTP, which sucks.
Bad Idea #3
It also briefly occurred to me to have a hard-coded key in the JavaScript that's used to decrypt this value but no matter how I try and obfuscate it, it could be found and used by a hacker.
Bad Idea #4
I've also considered some sort of key exchange using Public-key cryptography at the initial handshake, but as noted elsewhere, you can't really be confident on the client-side that there isn't tampering during this initial handshake unless it's over SSL - putting me back at square one.
The Big Question
So, how do you guys manage such things without everything going over HTTPS? Do I have to have the same domain name for my HTTP and HTTPS so that I can store this private key in a cookie?
Note that the non-SSL portions of the site wouldn't be sharing credit card or login information or the like. I just don't want to leave this sucker wide open.
You can not have secure and encrypted communication between a javascript client and a server without implementing SSL. It is impossible. If what you really want to accomplish is not to encrypt the traffic but simply insure the client you are talking to has been authorized to make the request and that the client is not an impersonator, then OAuth may be sufficient. See http://www.dotnetopenauth.net/ for the standard OAuth .net implementation.
If OAuth is not what you want to get involved in and you simply want to build on what you already have built, you should distribute a token and a public and a private key to the javascript client. The public key and the token is what gets sent back and forth for every request while the private key is never sent back and forth and is instead used to generate some type of signature hash. Every request should have this signature and a time-based nonce to prevent replays. You should also expire the token on a very frequent basis and require the client to request a "refresh" token with their sig and their public key. In essence, what I have described is OAuth 1.0a, and if you do want to take this route, I would refer back to DotNet OpenAuth instead of trying to roll it yourself.
However, to reiterate, without SSL, you will still be vulnerable to other types of attacks. Also, unless you SSL encrypt the initial token request, a hacker could always sniff the initial delivery of the token/public/private key pair, therefore, eliminating all your hard work to make things secure in the first place.
An alternative to the above is to have a proxy server sitting between your client and the REST API. Requests to the API can only go through the proxy server. The client logs in and gets a cookie from https://secure.example.com using basic auth. The client then continues to make requests to secure.example.com and secure.example.com then makes requests to your API and returns the data back to the client.
Anyway, hopefully enough info to give you food for thought.
You can view how to work with sub domains and cookies by checking out this answer: Creating a javascript cookie on a domain and reading it across sub domains
Regarding Bad Idea #3:
I've known for awhile that I can use http://jsbeautifier.org to deobfuscate anything that is obfuscated using http://dean.edwards.name/packer/ with the "Shrink variables" checkbox &/or the "Base62 encode" checkbox. So JavaScript is totally insecure & shouldn't be relied upon for saving any sort of SSL encryption, nor user auth tokens, nor editable account stats in the browser. Otherwise someone would simply try to edit their game account & give themselves +10 million game coins.
When everything goes over SSL it only protects against "man-in-the-middle" attacks. It's really a "server-bot-in-the-middle" attack. It doesn't prevent the end-user from being a hacker themselves.
In this next illustration, SSL would prevent servers a through e from seeing any data that's being passed from the client to the terminus server, but without SSL server C would steal data. This is how server hops work, without encryption, where the client + all servers can read the data:
client > a > b > server c's bot sniffs http traffic > d > e > terminus server
Server c's bot logs a credit card number, which is an encrypted bank account number. (Most people don't realize that a credit card number is an encrypted & transformed bank account number. If the credit card number is compromised, it's easy for a bank to re-issue a new encrypted CC# from a bank account number & send out a new card in the mail. They don't have to change the original bank account number nor printing new checks, which have the bank account number printed on the bottom of them.)
Server hops with TLS/SSL/https encryption would work like this, where only the client & server could read anything:
client > all servers from a-e are blind & pass the data through > terminus server
Server c's bot sees junk like: as65a89as7df08 instead of 1234-5678-9012-..., if they can read anything at all using SSL.
What's cool about iOS, is that it makes it harder to read the JS code when it's used with HTML 5 & CSS. User can't right-click to inspect on their iPhone, like they can in a desktop browser. It's easy to hide a password in the terminus server using a back-end language.
It's currently impossible to prevent JavaScript from being hacked by the end-user (client). Every end-user can be a hacker. If I figure something else out, I can post it here for future developers to read.