JWT is used as user authentication in my project.
If someone intercepts packets(using wireshark, etc), takes the user's jwt token, and then tries to log request in using the jwt token(replay attack)
how can i defend using jwt? (my project is using https)
ps. English is not my native language, so I am not good at it, so please understand the awkward sentences.
A JWT literally IS your access token. So you have to keep it secure and especially transfer it securely by all means. If an attacker was able to obtain a JWT (for example by sniffing an unencrypted HTTP connection) he can always* use it to perform any action the user (respectively the token) is authorized to. So it's more of a use than a "replay attack".
Therefore you cannot directly defend using a JWT. You can only make sure to send it always over an encrypted HTTPS connection and to prevent Cross-Site-Scripting attacks, which could allow an attacker to steal the JWT.
* Because of this, a JWT generally has an expiration time. So if you keep the expiration time short an attacker could use the stolen JWT only in a small time period. However, also a small time period may be sufficient to achieve permanent access. And the attacker could possibly steal a fresh JWT via the initial source.
Related
I'm working on implementing secure CSRF tokens into my nodejs backend & react frontend app that uses express-sessions. I have created this module to generate, validate, and store CSRF tokens in redis & include some extra security like separate secret per token for BREACH security, per-feature tokens, & support for multiple tabs of the same feature (thus the token IDs and keys).
I have read that CSRF tokens are encrypted and only the server knows the key, so that when the browser sends the token to the server the server can validate via the secret key that only the server knows. My question is why are they encrypted?
To my understanding, if an attacker somehow manages to steal the encrypted token then the encryption is useless, as when they submit a request w/ the token the server would validate it since it is essentially the same encrypted token. If that is the case, wouldn't it be more performant to just store the token on the server as well and check if the one the client submits matches? (Of course accounting for timing attacks in the comparison)
Thank you
CSRF tokens are not normally encrypted. In a textbook implementation using for instace the synchronizer token pattern in a normal web app, a CSRF token is just a sufficiently large random value, stored on the server and also given to the client upon form generation. The client can then send it back with the form, proving that the form it is sending was actually generated by the server, and not somebody else. (Even in case of other patterns like double posting, the token sent as something like a header field and a cookie is just a random token in the base case.)
However, there are two things to note.
The synchornizer token pattern (a classic CSRF token) needs a server lookup. This is not so big of a deal if there is a user session anyway, but that's not always the case, some applications are designed to be stateless. In that case you can't just have a random token, because you can't decide without checking server-side state whether it's valid.
The other thing to note is that you can actually increase security even more, if the token contains some information about the client. Like for example it's less useful to somehow steal a csrf token, if it's somewhow tied to the client anyway (for example if it is associated with the current client IP address in a more naive implementation). Again, you could store this additional information server-side, but that's again state, that some applications want to avoid to make things like load balancing easier.
So it comes down to stateless CSRF tokens, ones that you can just check as they are, without state (database) lookups on the backend.
What you can do (and what some frameworks do for you) is they create a structured token with some data embedded in it, and they encrypt it with a key only known to the server. The server then sends this as the CSRF token, and expects to receive it back upon state changing requests. When it receives it back, the server doesn't need a database lookup, it can just decrypt the token and see if it's a valid one that the server created.
Note that purely for this purpose, you don't actually need encryption, the crypto primitive more suitable would be a message authentication code, because you only care about the authenticity of the token, ie. that the server itself created it and not somebody else. However, the data some frameworks include in the token is many times further protected by encyption (and implicit message authentication by a suitable authenticated encryption algorithm). But in a very basic implementation, you could actually just include a timestamp and user id with hmac as a stateless CSRF token (but including more information, maybe even about the form fields generated would further increase security).
So in short, unencrypted random tokens are considered sufficient for CSRF, and in case of double posting, they can also be stateless (because of the same origin policy, an attacker cannot post the same random token to a different origin both as a cookie and as a header). But an encrypted, more information rich token can provide more security if that's needed, potentially even somewhat mitigating the stolen CSRF token threat too.
I read a lot about JWTs and found that it is pretty hard to use them in a secure CSRF and XSS proof way.
Until I realized that my tokens will probably not leave my unique domain...
This led me to this idea of implementation:
Use a refresh token along with an access token. That way I can set short expiring time to the access token and limit the database calls to verify the user and only when the access token expires a simple verification by asking the database that the refresh token is not blacklisted before sending a new access token to the user.
I understood that if I store a token in the local/session storage it would be vulnerable to XSS attacks but if I store it in an HTTP-only cookie it would be vulnerable to CSRF attacks.
As I don't need to access the token inside the JavaScript and that I only need this token in one website, I thought that I could store the access token inside an HTTP-only cookie (that way it is protected from XSS) along with the secure flag and the same site flag set to strict (preventing CSRF).
And regarding the refresh token I could store it inside an HTTP-only cookie that has the same secure flag but without the same site flag this time. Because the server will never execute any action only based on the refresh token, I think that it will therefore not be susceptible to CSRF attacks. The only thing the server will do with a refresh token is to send back a new access token which, if I understood it well, could not be read from the CSRF attacker. The CSRF vulnerability allows the attacker to make a request to the server (which will automatically contain HTTP-only cookies) but he cannot read the response of this request.
I don't know if this implementation of JWTs would be secure or if I missed something...
This is what I'm asking you (JWTs and web security experts) would that be a good JWTs implementation ?
First, a word on JWTs. An oldschool plain server-side session (with a long, random session id, correctly stored in a secure, httpOnly, maybe also SameSite cookie) is "more secure" than any JWT in most cases. The reason is that JWTs store state on the client, where it is more available to an attacker, offline attacks can be performed against the cryptography involved, also JWTs are plain text and only their integrity is protected (ie. they are protected against client-side change, but not against looking at the contents by default, though you could use JWE, and encrypted JWT too). Last but not least, implementation is more complex, and simplicity is great for security.
So you would use a JWT when you need a benefit that it provides.
One argument is that it's stateless. This is very often overrated though. First, in most applications the bottleneck will not be the database lookup needed to find the session data in the database. In some very high profile, high traffic applications it actually might be, but you are probably not developing something like that every day. Usually it's just ok to do a database lookup, and it makes the whole thing a lot simpler. Second, sometimes you need token revocation, ie. you want to be able to force-logout a user. Even if you used a JWT for statelessness, you would have to store something in a database, a list of revoked tokens for example, and checking that would also be a database roundtrip. Revoking JWTs simply cannot be implemented in a purely stateless way.
Another benefit is that you can use it for multiple origins. If you get a httpOnly session cookie, that will be managed by the browser, javascript cannot send it to other origins, like an API or something - that's the whole point, JS not having access. But sometimes you do need that, especially in single sign-on scenarios, where you have an identity provider (a component that provides logon), and services (eg. APIs) that you want to use your access token on. In this case a classic cookie would not work, and JWTs are very handy.
So in short, you would use a JWT when you really need statelessness, or the option to send the token to multiple origins. As a rule of thumb, if you can store the JWT in a httpOnly cookie, you most probably don't need it at all, and could just use a plain old server-side session.
And then let's say you decide to use JWTs, what about refresh tokens. They are another generally misunderstood feature of token-based authentication. The point in using refresh tokens is to be able to use short-lived access tokens, so if an access token get s compromised, it is at least time limited. But if you store the refresh token the same way as an access token, why would an attacker not get that too?
It only makes sense to have a refresh token, if you store it differently, otherwise you could just have long-lived access tokens, and that would not be less secure.
One typical thing is to have an identity provider ("login server", or IdP) that sets a refresh token (or just a plain old session id) in a httpOnly cookie for the identity provider origin, so whenever the client makes a request to the IdP, it "just works" if they are already logged in, and can provide a new access token without user interaction. The access token is then stored in something like localStorage (for the service origin), susceptible to XSS, but at least time limited. If you don't have this separation, a separate refresh token probably doesn't make much sense.
As a final note, all of this should very rarely be implemented by yourself. Any language or framework you use probably already has one or more known good, maintained implementation for authentication. You should just use those, but it's still very much worth to understand it of course.
Please note that in any actual application there might be subtleties and certain circumstances that somewhat change what you want to do, but the above is a general way to think about secure authentication.
I am working on an application where scalability is a big concern. In the past I've used session-based authentication, but decided to go with a stateless server this time around in order to facilitate horizontal scaling.
I am not security expert, but in researching JWTs, it began to seem like these are very insecure. The whole reason we hash passwords is so that if our database is compromised, the attacker cannot impersonate a user. With JWT, we store a secret on the server. If the attacker gains access to the secret, can't they impersonate any user they want? Doesn't this mean that using JWTs would have the same level of security as storing plain text passwords?
I have read that people will sometimes use reddis to cross reference JWTs, but then the server isn't stateless, and I fail to see the benefit of using JWTs at all.
Could someone help clarify this issue for me?
Session based authentication systems, at least any that are worth using, also store a secret on the server. Just like the JWT, the secret is used to sign the data stored in the cookie that session based authentication uses. So this is no different than a JWT.
All of this is totally unrelated to password storage, as the password is only used when you don't have a cookie/JWT.
EDIT:
Not sure what to say about using Redis in conjunction with a JWT... What is being stored in Redis, the token? That seems pointless, as all the server needs to know is the secret to decode the token.
Here are some of the benefits to a using a JWT:
It's stateless, as you've already mentioned
It's not subject to CSRF/XSRF attacks. These attacks work by tricking your browser into sending the cookie to a server that didn't generate the cookie. This can't happen w/a JWT b/c the browser doesn't send the JWT automatically like it does w/cookies.
JWT's are standardized. There is a well defined way to generate them, which means that JWT's are more portable and the process has been vetted by the security community.
The server consuming a JWT token (resource server) does not need access to any secret. All it needs is the public key that belongs to the private key with which the token is digitally signed.
The authorization server that issues the token needs to keep its signing key secret obviously. But the nice thing about token based authentication is that this server can be created by an external party with much more resources/expertise to keep these things secret (Google, Facebook, Microsoft etc).
The resource server does not need to check the database to validate the token as you would need in case of username and password. This helps the scalability of the system and takes away a single point of failure.
If a client/user loses the JWT token, an attacker can impersonate the client/user until the token expires. A good reason to keep the lifetime of tokens short.
I don't see the point of storing JWT tokens in in a Reddis cache. There's no need to share tokens between servers as each call comes with a token in the Authorization HTTP header. Storing them in a cache only increases the risk of tokens being stolen.
I am learning about JWT for the security of my project, but I have a question. If I recieve the token correctly after I did the login, but someone else (hacker) in other place steals this specific token, can he access to my session? The server that use JWT authentication is able to detect this and protect me? How?
Only the server should know the "secret" that is used to generate the JWT. If someone modifies the data contained in the JWT, the server will fail to decode it. So the server can trust any JWT that it can decode.
However, if a hacker got access to your computer, they could see the JWT that is stored in the browser and use it. This same threat exists w/cookies, so it's not really a flaw of the JWT.
One way to mitigate this threat is the expiration date of the JWT. For a banking app, your JWT might expire after a few minutes. For Facebook, it might expire after a few months. However, there's no bullet proof solution to this if someone gets access to your browser.
Another approach for hackers would be a "man in the middle" attack to intercept the network traffic between client and server and get at the cookie/JWT. The cookie/JWT should always be sent over HTTPS to prevent this.
IMPORTANT EDIT
Finally, to answer the question in your title, "How safe is JWT?": It depends on how you store the token. Local storage is not as secure as using cookies (reference) but cookies can be subject to CSRF or XSRF exploits.
This answer used to say JWT was safer than cookies, because cookies were subject to CSRF attacks. But storing JWT in local storage is not safe either. As a result, I'm no longer storing my JWT in local storage and using well known techniques to mitigate CSRF attacks.
When building SPA style applications using frameworks like Angular, Ember, React, etc. what do people believe to be some best practices for authentication and session management? I can think of a couple of ways of considering approaching the problem.
Treat it no differently than authentication with a regular web application assuming the API and and UI have the same origin domain.
This would likely involve having a session cookie, server side session storage and probably some session API endpoint that the authenticated web UI can hit to get current user information to help with personalization or possibly even determining roles/abilities on the client side. The server would still enforce rules protecting access to data of course, the UI would just use this information to customize the experience.
Treat it like any third-party client using a public API and authenticate with some sort of token system similar to OAuth. This token mechanism would used by the client UI to authenticate each and every request made to the server API.
I'm not really much of an expert here but #1 seems to be completely sufficient for the vast majority of cases, but I'd really like to hear some more experienced opinions.
This question has been addressed, in a slightly different form, at length, here:
RESTful Authentication
But this addresses it from the server-side. Let's look at this from the client-side. Before we do that, though, there's an important prelude:
Javascript Crypto is Hopeless
Matasano's article on this is famous, but the lessons contained therein are pretty important:
https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/august/javascript-cryptography-considered-harmful/
To summarize:
A man-in-the-middle attack can trivially replace your crypto code with <script> function hash_algorithm(password){ lol_nope_send_it_to_me_instead(password); }</script>
A man-in-the-middle attack is trivial against a page that serves any resource over a non-SSL connection.
Once you have SSL, you're using real crypto anyways.
And to add a corollary of my own:
A successful XSS attack can result in an attacker executing code on your client's browser, even if you're using SSL - so even if you've got every hatch battened down, your browser crypto can still fail if your attacker finds a way to execute any javascript code on someone else's browser.
This renders a lot of RESTful authentication schemes impossible or silly if you're intending to use a JavaScript client. Let's look!
HTTP Basic Auth
First and foremost, HTTP Basic Auth. The simplest of schemes: simply pass a name and password with every request.
This, of course, absolutely requires SSL, because you're passing a Base64 (reversibly) encoded name and password with every request. Anybody listening on the line could extract username and password trivially. Most of the "Basic Auth is insecure" arguments come from a place of "Basic Auth over HTTP" which is an awful idea.
The browser provides baked-in HTTP Basic Auth support, but it is ugly as sin and you probably shouldn't use it for your app. The alternative, though, is to stash username and password in JavaScript.
This is the most RESTful solution. The server requires no knowledge of state whatsoever and authenticates every individual interaction with the user. Some REST enthusiasts (mostly strawmen) insist that maintaining any sort of state is heresy and will froth at the mouth if you think of any other authentication method. There are theoretical benefits to this sort of standards-compliance - it's supported by Apache out of the box - you could store your objects as files in folders protected by .htaccess files if your heart desired!
The problem? You are caching on the client-side a username and password. This gives evil.ru a better crack at it - even the most basic of XSS vulnerabilities could result in the client beaming his username and password to an evil server. You could try to alleviate this risk by hashing and salting the password, but remember: JavaScript Crypto is Hopeless. You could alleviate this risk by leaving it up to the Browser's Basic Auth support, but.. ugly as sin, as mentioned earlier.
HTTP Digest Auth
Is Digest authentication possible with jQuery?
A more "secure" auth, this is a request/response hash challenge. Except JavaScript Crypto is Hopeless, so it only works over SSL and you still have to cache the username and password on the client side, making it more complicated than HTTP Basic Auth but no more secure.
Query Authentication with Additional Signature Parameters.
Another more "secure" auth, where you encrypt your parameters with nonce and timing data (to protect against repeat and timing attacks) and send the. One of the best examples of this is the OAuth 1.0 protocol, which is, as far as I know, a pretty stonking way to implement authentication on a REST server.
https://www.rfc-editor.org/rfc/rfc5849
Oh, but there aren't any OAuth 1.0 clients for JavaScript. Why?
JavaScript Crypto is Hopeless, remember. JavaScript can't participate in OAuth 1.0 without SSL, and you still have to store the client's username and password locally - which puts this in the same category as Digest Auth - it's more complicated than HTTP Basic Auth but it's no more secure.
Token
The user sends a username and password, and in exchange gets a token that can be used to authenticate requests.
This is marginally more secure than HTTP Basic Auth, because as soon as the username/password transaction is complete you can discard the sensitive data. It's also less RESTful, as tokens constitute "state" and make the server implementation more complicated.
SSL Still
The rub though, is that you still have to send that initial username and password to get a token. Sensitive information still touches your compromisable JavaScript.
To protect your user's credentials, you still need to keep attackers out of your JavaScript, and you still need to send a username and password over the wire. SSL Required.
Token Expiry
It's common to enforce token policies like "hey, when this token has been around too long, discard it and make the user authenticate again." or "I'm pretty sure that the only IP address allowed to use this token is XXX.XXX.XXX.XXX". Many of these policies are pretty good ideas.
Firesheeping
However, using a token Without SSL is still vulnerable to an attack called 'sidejacking': http://codebutler.github.io/firesheep/
The attacker doesn't get your user's credentials, but they can still pretend to be your user, which can be pretty bad.
tl;dr: Sending unencrypted tokens over the wire means that attackers can easily nab those tokens and pretend to be your user. FireSheep is a program that makes this very easy.
A Separate, More Secure Zone
The larger the application that you're running, the harder it is to absolutely ensure that they won't be able to inject some code that changes how you process sensitive data. Do you absolutely trust your CDN? Your advertisers? Your own code base?
Common for credit card details and less common for username and password - some implementers keep 'sensitive data entry' on a separate page from the rest of their application, a page that can be tightly controlled and locked down as best as possible, preferably one that is difficult to phish users with.
Cookie (just means Token)
It is possible (and common) to put the authentication token in a cookie. This doesn't change any of the properties of auth with the token, it's more of a convenience thing. All of the previous arguments still apply.
Session (still just means Token)
Session Auth is just Token authentication, but with a few differences that make it seem like a slightly different thing:
Users start with an unauthenticated token.
The backend maintains a 'state' object that is tied to a user's token.
The token is provided in a cookie.
The application environment abstracts the details away from you.
Aside from that, though, it's no different from Token Auth, really.
This wanders even further from a RESTful implementation - with state objects you're going further and further down the path of plain ol' RPC on a stateful server.
OAuth 2.0
OAuth 2.0 looks at the problem of "How does Software A give Software B access to User X's data without Software B having access to User X's login credentials."
The implementation is very much just a standard way for a user to get a token, and then for a third party service to go "yep, this user and this token match, and you can get some of their data from us now."
Fundamentally, though, OAuth 2.0 is just a token protocol. It exhibits the same properties as other token protocols - you still need SSL to protect those tokens - it just changes up how those tokens are generated.
There are two ways that OAuth 2.0 can help you:
Providing Authentication/Information to Others
Getting Authentication/Information from Others
But when it comes down to it, you're just... using tokens.
Back to your question
So, the question that you're asking is "should I store my token in a cookie and have my environment's automatic session management take care of the details, or should I store my token in Javascript and handle those details myself?"
And the answer is: do whatever makes you happy.
The thing about automatic session management, though, is that there's a lot of magic happening behind the scenes for you. Often it's nicer to be in control of those details yourself.
I am 21 so SSL is yes
The other answer is: Use https for everything or brigands will steal your users' passwords and tokens.
You can increase security in authentication process by using JWT (JSON Web Tokens) and SSL/HTTPS.
The Basic Auth / Session ID can be stolen via:
MITM attack (Man-In-The-Middle) - without SSL/HTTPS
An intruder gaining access to a user's computer
XSS
By using JWT you're encrypting the user's authentication details and storing in the client, and sending it along with every request to the API, where the server/API validates the token. It can't be decrypted/read without the private key (which the server/API stores secretly) Read update.
The new (more secure) flow would be:
Login
User logs in and sends login credentials to API (over SSL/HTTPS)
API receives login credentials
If valid:
Register a new session in the database Read update
Encrypt User ID, Session ID, IP address, timestamp, etc. in a JWT with a private key.
API sends the JWT token back to the client (over SSL/HTTPS)
Client receives the JWT token and stores in localStorage/cookie
Every request to API
User sends a HTTP request to API (over SSL/HTTPS) with the stored JWT token in the HTTP header
API reads HTTP header and decrypts JWT token with its private key
API validates the JWT token, matches the IP address from the HTTP request with the one in the JWT token and checks if session has expired
If valid:
Return response with requested content
If invalid:
Throw exception (403 / 401)
Flag intrusion in the system
Send a warning email to the user.
Updated 30.07.15:
JWT payload/claims can actually be read without the private key (secret) and it's not secure to store it in localStorage. I'm sorry about these false statements. However they seem to be working on a JWE standard (JSON Web Encryption).
I implemented this by storing claims (userID, exp) in a JWT, signed it with a private key (secret) the API/backend only knows about and stored it as a secure HttpOnly cookie on the client. That way it cannot be read via XSS and cannot be manipulated, otherwise the JWT fails signature verification. Also by using a secure HttpOnly cookie, you're making sure that the cookie is sent only via HTTP requests (not accessible to script) and only sent via secure connection (HTTPS).
Updated 17.07.16:
JWTs are by nature stateless. That means they invalidate/expire themselves. By adding the SessionID in the token's claims you're making it stateful, because its validity doesn't now only depend on signature verification and expiry date, it also depends on the session state on the server. However the upside is you can invalidate tokens/sessions easily, which you couldn't before with stateless JWTs.
I would go for the second, the token system.
Did you know about ember-auth or ember-simple-auth? They both use the token based system, like ember-simple-auth states:
A lightweight and unobtrusive library for implementing token based
authentication in Ember.js applications.
http://ember-simple-auth.simplabs.com
They have session management, and are easy to plug into existing projects too.
There is also an Ember App Kit example version of ember-simple-auth: Working example of ember-app-kit using ember-simple-auth for OAuth2 authentication.