Securing requests between HTML/JavaScript-frontend and backend (authentication) - javascript

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.

Related

How to handle the JWT on the client layer?

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?

Using JWT to send username, password to authenticate

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.

Authentication with JWT

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.

Cookie without httpOnly, how insecure it is?

Im developing a web application which requires cookie to be set httpOnly = false.
Since, I find no other way to pass authentication cookies(for checking whether user has logged in successfully) from server side to be accessible via Javascript in my front end. This cookie is then used to send an AJAX request to my server side(added to the header). (Please do correct me if Im wrong and suggest me any other way)
My question:
How insecure is httpOnly = false? Is it safe enough with just forcing it to use cookieSecureOption = true so that it will always be send via HTTPS.
How can I protect it from XSS attack?
A "non-HttpOnly cookie" isn't a vulnerability in itself.
An "HttpOnly cookie" mitigates the risk of an XSS attack. That is, any attacker injected scripts into your website will not be able to grab the value of this cookie, thus protecting the session.
If your application requires the use of the cookie value to add as a header, then you cannot mark this cookie as "HttpOnly". You can change the request handler to look for the value in the cookie rather than in the header (so you can set the flag), however this may put your site at risk of CSRF. The most secure approach is for your handler to check authorisation via a "HttpOnly" cookie, and to use another token value in a header ("non-HttpOnly") to check for CSRF. If these values are different, e.g. in the encrypted token pattern or the synchronizer token pattern, then there isn't much value in attacker in only retrieving the one value via XSS because they can't use it to authorise requests. Note that any XSS vulnerability is usually a bigger problem than a CSRF vulnerability, because the attacker could always use their XSS attack in order to submit requests directly from your site, however it is a much harder attack to accomplish. At least with "HttpOnly" they cannot grab the auth cookies from your site in order to remotely login.
The other cookie flag you mentioned is the secure flag. This will limit the cookie scope to https connections only, and is recommended if you are using https (which is also recommended). This does not affect whether JavaScript can access the value though.
If you do use a "non-HttpOnly cookie" then you can still mitigate the threat of XSS as follows.
Move all script code into external js files and set a Content Security Policy to prevent any inline scripts from executing.
Make sure you are correctly encoding all user input when output (e.g. < becomes < in HTML) and run a web security scanner against your application.
If you do not have HTTPOnly flagged, your users are still more vulnerable to XSS than they otherwise would be, as the cookie can still be accessed from JavaScript. From your description, you should not need access to the variable from JavaScript, simply access the cookie from the server side (which is still possible with HTTPOnly flagged, cookies are sent with every request including AJAX calls) to retrieve authentication information. The Secure flag and HTTPOnly flag defend against completely different attacks.
There is a hybrid way of doing this. I say hybrid because it involves half of what your doing and a mix of what bksi mentioned in a comment.
Since I do not know your full scenario this answer assumes you are just looking for a way to authenticate the user before allowing them to make changes or start a process server side; login, viewing an account page, and so on. You should never rely solely on httpOnly = false I would recommend using it with what is below.
A Solid Solution
Set a normal cookie when a user logs in successfully, this does not need to be sent over HTTPS although it would be nice. This cookie should be a randomly generated token for their session. I usually hash (md5 encrypt in PHP) their user id (assuming you use a database) and a time stamp of when they logged in. This insures the token is unique.
Now that you have a token saved on their local machine as a cookie also make sure to save this token in a PHP session which is server side. Now any time they visit a page or an AJAX request is sent you can compare the local cookie to the PHP session value server side. This is the fastest way you can authenticate a user interacting with your server. If the values match they are legitimate.
Now this is not entirely secure. The local cookie can always be edited which is something we usually don't care to much about because this will only harm the user by invalidating their session. On the flip side a crafty hacker could alter the PHP sessions and that could invalidate other users because their session was erased or hijacked. A hacker would have to get a legitimate session token and make a cookie to match.
The Better Solution(s)
1) On the server side you could use a database instead of PHP sessions. The process remains the same but now you need to do a bit more work of keeping the sessions table in your database up to date. Usually this is done by saving the token with a time stamp and updating this time stamp every time the token is checked. If the token is checked and the last time stamp is really old (you decide how long that is) you can un-authenticate the user by destroying their local cookie and having them sign in again. This is more resource intensive though and can slow down sites with large traffic loads.
2) Use a form of double authentication. This would be using PHP session 90% of the time for simple things but when an extremely important process comes up, say updating personal information or providing credit card information, check with the database as well. This would require two different cookies to be saved on the users machine. One if for checking PHP session for authentication and the second is for checking the database. This scenario would be really hard for a hacker to break through to the more important things because they would need to figure out both tokens and the database one is not easy to steal.
Final Thoughts
This is a fairly secure answer but you should still implement extra security precautions. It seems you are misunderstanding how cookies work in general; your recent comment sounds like your using cookies and ajax backwards but maybe I'm misunderstanding. Here is how I do it:
[User]-> Tries logging in to website with a login form
[Server]-> Checks this information against the database Pass, log 'em in.
[Server]-> Generate and set a random token as a cookie
I use PHP here and usually store this cookie with a name like sessionToken. This cookie immediately exists now on the users computer and we, the server, always have access to it server side; we can call it up any time. This is not really secure though because people could copy the cookie without the person knowing/ steal it as we send it to them. I'll deal with that in a minute.
[Server]-> Create a PHP session (session id: abc123) server side that has this same token.
This is step one in security. PHP sessions are not as easy to steal or hack. So even if someone steals our users token cookie when they try to use it on their computer it will fail. Here is a vaild user:
[User]-> (PHP session id: abc123) Tries to access secured page or content. PHP session is called up and is checked against the cookie token. If they equal each other this attempt passes.
Here the user has a session on the server they don't know about that recognizes who they are and can be accessed only by the server; usually. It is here where your AJAX request come into play. Every time the user tries to do something that you want to see if they are even allowed to do, send a request via AJAX to a PHP script that authenticates the user. All it does is send back PASS or FAIL. Then you can use AJAX or Javascript to do whatever you need. Here is a hacker exmaple:
[Hacker]-> Steals a cookie from a user over a cafe's wifi.
[Hacker]-> Tries to access the website you are on with it.
[Server]-> (PHP session id: ???) Doesn't have one, destroy the cookie and ask this user (the hacker) to login again.
This is as much information and help I can give. Your latest comments are starting to sound like new questions you should post on Stackoverflow.

What is the challenge/response method to securely authenticate with a Server without HTTPS (without sending out password)?

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.

Categories