I want make a logout service with controller. I try the next code:
#GetMapping("/logout")
public String getLogoutPage(HttpServletRequest request, HttpServletResponse response){
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null)
new SecurityContextLogoutHandler().logout(request, response, authentication);
return "redirect:/login";
}
I am actually do test with postman
the next url request authentication ("/example") but when do a logout i still can go to this url with the same token and that's not right.
You can't really log out a JWT token, or not as you would with an opaque token. What makes a JWT valid is the correctness of its signature with the public certificate used to control it and its expiration time.
As long as those two conditions are met, the token will be valid. A traditional logout from a JWT based system usually consists of simply removing the token on the client-side.
In case of a security breach, you can rotate the keys used to generate JWTs, but that would log out everyone in the system and is not possible as a per-user strategy.
If you want to handle it on the server-side, you could create a deny list of JWT, add the token you want to log out, and check on every request if the token is in the list. Just be careful on how you implement this to avoid a major overhead in your system (store the expiration time with the denied token and have a job cleaning it regularly).
If your system is distributed with one authentification authority, and multiple different consumers that would only "fix" the logout locally if not properly done. Which means trouble at one point or another. You should also take that in consideration
A good set of rules to work with JWT are :
Don't store them in any kind of place where you can't easily remove them and effectively make a client-side logout.
Have a short expiration time and refresh them often.
Rotate the keys used to generate JWTs every so often depending on your security needs
Have a contingency plan to deal with some use case that pure JWT can't handle: password change, immediately blocking a user...
If those security tradeoffs are something you can't work with, you should consider moving to opaque tokens which can easily be revoked without breaking the model.
Related
When you log in, you store the Access Token in the client header and the Refresh Token in Redis. And when the validity period of the AccessToken expires, the logic is used to check the expiration period of the RefreshToken by using the AccessToken as a KeyValue and reissue the AccessToken if it is valid. At this time, if the attacker steals the AccessToken, the attacker will also be able to obtain a new AccessToken even if the AccessToken expires, and it is expected that the attack will continue until the RefreshToken expires. When renewing AccessToken, I wonder if other conditions should be added instead of just checking the key value or if it is okay as it is. Also I wonder why this is ok
the logic is used to check the expiration period of the RefreshToken by using the AccessToken as a KeyValue and reissue the AccessToken if it is valid.
This part is wrong. The client needs to send the refresh token to the Authorization Server in order to get a new access token. Ideally, the refresh token endpoint should require client authentication, e.g. the client has to send a secret or present a concrete certificate in a TLS connection. Unfortunately, this can't be achieved when you have public clients, like SPAs (unless you use some kind of middleware, like the Token Handler.
Anyway, in order to get new access tokens, the attacker would have to get hold of the refresh token, not just the access token. If the client is confidential, then the attacker would also have to steal the client's credentials (like a secret or a certificate's private key)
The idea is that you will make the lifetime of an access token very short and share it across different APIs without worrying. However, for refresh tokens you would be more careful and don't use it any where except the authorization server. (Do not store in the browser nor in other APIs).
This will ensure the safety of the refresh token and the short lifespan of the access token will ensure its safety.
I had the same concern before and I got clear explanations that you can check here
how is using JWT refresh token secure?
I have a mobile application that uses my Spring Boot backend for things like authentication and accessing data. A part of the Spring Boot application accesses data from a resource server using OAuth2. I stumbled across an oauth2 client library for Spring that does its magic and everything just works out of the box.
As I'm trying to figure out how this library does its work, I can't seem to find an answer to the way it handles refresh tokens. I'm aware that the oauth2client is bound to a session for each user but what happens when the session ends? Wouldn't the access and refresh tokens get lost?
I was looking for ways to persist the refresh token for each user in my database but I didn't find any support for that in the library. This leaves me wondering if I have to implement this myself or if there's even a need to do so.
Any advice is appreciated!
Basically OAuth2 architecture is used for 3rd-party authentication and authorization. In this mechanism the credentials remains secured and aren't passed on while everything works upon tokens! But you can use it to work implicitly for your own authentication too.
In your case first when you hit "/oauth/token"(default endpoint) along with the client-secret and client-Id and rest of the user credentials the algo checks for the user details in the DB and matches the secret and Id present in the header of the request. If everything goes fine it'll generate a bearer type - access and refresh token and will store these tokens in different collections in the database.This particular user is mapped to these tokens and can access /api's using them only.No user creds are required. You can use MongoTokenStore if you're using MongoDb for storing and accessing stored tokens.
Next you have to configure WebSecurity/AuthorizationServer/ResourceServer for checking endpoints and header tokens tokens, authentication and authorizaton of users and providing valid tokens access to the resource respectively.
Lastly when you have a valid access token and hit an api with a correct header request the server grants you permission to access the resource!
This is the basic functionality of the OAuth2.0.
Normally Access Tokens have a shorter lifetime while refresh tokens have comparitively larger lifetime. Once Access Token gets expired a new Access Token can be generated using the Refresh Tokens. If the Refresh Tokens gets expired then you have to hit the "/oauth/token" api again,complete the flow cycle and generate tokens again.After expiry when you hit an api with existing access token they are removed from the collection. This is the default architecture of this mechanism, rest you can make custom classes and modify its functionality according to your needs! This architecture is quite secure and is a good practise.
Screenshot Flow Diagram
Check this post from digitalocean.
Edits ----
Personally I used MongoDB where I made two collections -
AuthAccessTokens and AuthRefreshTokens namely where these two were
stored. Access Token object has an Id of associated RefreshToken
which helps to map these two together. Rest custom additional Info.
can also be added using TokenEnhancer. Therefore tokens will always
be present in the DB unless expired. And in layman's terms if you
are just focussing on Backend stuff you can always check for your
access tokens by hitting "/oauth/token" with correct user creds and
it will return the assigned token by fetching it from the DB, else
if you're developing full stack after generating the tokens on first
step just store them on client end either in browser's local storage
or app. And if you want to deliberately end the session like for
example in Logout just remove these tokens from their respective
collections.
I am using Spring Security OAuth2 and JWT tokens. My question is: How can I revoke a JWT token?
As mentioned here
http://projects.spring.io/spring-security-oauth/docs/oauth2.html, revocation is done by refresh token. But it does not seem to work.
In general the easiest answer would be to say that you cannot revoke a JWT token, but that's simply not true. The honest answer is that the cost of supporting JWT revocation is sufficiently big for not being worth most of the times or plainly reconsider an alternative to JWT.
Having said that, in some scenarios you might need both JWT and immediate token revocation so lets go through what it would take, but first we'll cover some concepts.
JWT (Learn JSON Web Tokens) just specifies a token format, this revocation problem would also apply to any format used in what's usually known as a self-contained or by-value token. I like the latter terminology, because it makes a good contrast with by-reference tokens.
by-value token - associated information, including token lifetime, is contained in the token itself and the information can be verified as originating from a trusted source (digital signatures to the rescue)
by-reference token - associated information is kept on server-side storage that is then obtained using the token value as the key; being server-side storage the associated information is implicitly trusted
Before the JWT Big Bang we already dealt with tokens in our authentication systems; it was common for an application to create a session identifier upon user login that would then be used so that the user did not had to repeat the login process each time. These session identifiers were used as key indexes for server-side storage and if this sounds similar to something you recently read, you're right, this indeed classifies as a by-reference token.
Using the same analogy, understanding revocation for by-reference tokens is trivial; we just delete the server-side storage mapped to that key and the next time the key is provided it will be invalid.
For by-value tokens we just need to implement the opposite. When you request the revocation of the token you store something that allows you to uniquely identify that token so that next time you receive it you can additionally check if it was revoked. If you're already thinking that something like this will not scale, have in mind that you only need to store the data until the time the token would expire and in most cases you could probably just store an hash of the token so it would always be something of a known size.
As a last note and to center this on OAuth 2.0, the revocation of by-value access tokens is currently not standardized. Nonetheless, the OAuth 2.0 Token revocation specifically states that it can still be achieved as long as both the authorization server and resource server agree to a custom way of handling this:
In the former case (self-contained tokens), some (currently non-standardized) backend interaction between the authorization server and the resource server may be used when immediate access token revocation is desired.
If you control both the authorization server and resource server this is very easy to achieve. On the other hand if you delegate the authorization server role to a cloud provider like Auth0 or a third-party component like Spring OAuth 2.0 you most likely need to approach things differently as you'll probably only get what's already standardized.
An interesting reference
This article explain a another way to do that: Blacklist JWT
It contains some interesting pratices and pattern followed by RFC7523
The JWT cann't be revoked.
But here is the a alternative solution called as JWT old for new exchange schema.
Because we can’t invalidate the issued token before expire time, we always use short-time token, such as 30 minute.
When the token expired, we use the old token exchange a new token. The critical point is one old token can exchange one new token only.
In center auth server, we maintain a table like this:
table auth_tokens(
user_id,
jwt_hash,
expire
)
user_id contained in JWT string.
jwt_hash is a hash value of whole JWT string,Such as SHA256.
expire field is optional.
The following is work flow:
User request the login API with username and password, the auth server issue one token, and register the token ( add one row in the table. )
When the token expired, user request the exchange API with the old token. Firstly the auth server validate the old token as normal except expire checking, then create the token hash value, then lookup above table by user id:
If found record and user_id and jwt_hash is match, then issue new token and update the table.
If found record, but user_id and jwt_hash is not match , it means someone has use the token exchanged new token before. The token be hacked, delete records by user_id and response with alert information.
if not found record, user need login again or only input password.
when use changed the password or login out, delete record by user id.
To use token continuously ,both legal user and hacker need exchange new token continuously, but only one can succeed, when one fails, both need to login again at next exchange time.
So if hacker got the token, it can be used for a short time, but can't exchange for a new one if a legal user exchanged new one next time, because the token validity period is short. It is more secure this way.
If there is no hacker, normal user also need exchange new token periodically ,such as every 30 minutes, this is just like login automatically. The extra load is not high and we can adjust expire time for our application.
source: http://www.jianshu.com/p/b11accc40ba7
This doesn't exactly answer you question in regards to the Spring framework, but here's an article that talks about why if you need the ability to revoke JWT's, you might not want to go with JWT's in the first place, and instead use regular, opaque Bearer tokens.
https://www.dinochiesa.net/?p=1388
One way to revoke a JWT is by leveraging a distributed event system that notifies services when refresh tokens have been revoked. The identity provider broadcasts an event when a refresh token is revoked and other backends/services listen for the event. When an event is received the backends/services update a local cache that maintains a set of users whose refresh tokens have been revoked.
This cache is then checked whenever a JWT is verified to determine if the JWT should be revoked or not. This is all based on the duration of JWTs and expiration instant of individual JWTs.
This article, Revoking JWTs, illustrates this concept and has a sample app on Github.
For Googlers:
If you implement pure stateless authentication there is no way to revoke the token as the token itself is the sole source of truth
If you save a list of revoked token IDs on the server and check every request against the list, then it is essentially a variant of stateful authentication
OAuth2 providers like Cognito provides a way to "sign out" a user, however, it only really revokes refresh token, which is usually long-lived and could be used multiple times to generate new access tokens thus has to be revoked; the existing access tokens are still valid until they expire
What about storing the JWT token and referencing it to the user in the database? By extending the Guards/Security Systems in your backend application with an additional DB join after performing the JWT comparison, you would be able to practically 'revoke' it by removing or soft-deleting it from the DB.
In general, the answer about tokens by reference vs. tokens by value has nailed it. For those that stumble upon this space in future.
How to implement revocation on RS side:
TL;DR:
Take a cache or db that is visible to all your backend service instances that are verifying tokens. When a new token arrives for revocation, if it's a valid one, (i.e. verifies against your jwt verification algo), take the exp and jti claims, and save jti to cache until exp is reached. Then expire jti in cache once unixNow becomes > exp.
Then on authorization on other endpoints, you check everytime if a given jti is matching something in this cache, and if yes, you error with 403 saying token revoked. Once it expires, regular Token Expired error kicks in from your verification algo.
P.S. By saving only jti in cache, you make this data useless to anyone since it's just a unique token identifier.
The best solution for JWT revocation, is short exp window, refresh and keeping issued JWT tokens in a shared nearline cache. With Redis for example, this is particularly easy as you can set the cache key as the token itself (or a hash of the token), and specify expiry so that the tokens get automatically evicted.
I found one way of resolving the issue, How to expire already generated existing JWT token using Java?
In this case, we need to use any DB or in-memory where,
Step 1: As soon as the token is generated for the first time for a user, store it in a db with the token and it's "issuedAt()" time.
I stored it in DB in this JSON format,
Ex: {"username" : "username",
"token" : "token",
"issuedAt" : "issuedAt" }
Step 2: Once you get a web service request for the same user with a token to validate, fetch "issuedAt()" timestamp from the token and compare it with stored(DB/in-memory) issued timestamp.
Step 3: If stored issued timestamp is new (using after()/before() method) then return that the token is invalid (in this case we are not actually expiring the token but we are stop giving access on that token).
This is how I resolved the issue.
Is it enough to request one XSRF token from the server and reuse it over the whole session or should I request for each protect-worthy action like save, edit or delete a new XSRF token first and then perform the actual request?
This question arises because I don't understand why my XSRF protected request is working even though I am not requesting a new one:
public void saveName(Long shopId, Long languageId, String name, OnSuccessCallback<String> success, OnFailureCallback failure) {
Request.<String> doRequest(this.shopService,
asyncCallback -> {
this.shopService.saveName(shopId, languageId, name, asyncCallback);
},
(String result) -> {
// ..
success.onSuccess(result);
}, failure);
}
Here Request#doRequest() will simply perform a request but won't ask for a new XSRF token first. I would have to change it to XsrfRequest#doRequest() which does the same thing basically but will request a XSRF token first.
The thing is that saveName() is supposed to be protected:
#XsrfProtect
#RemoteServiceRelativePath("shop")
public interface ShopServlet extends RemoteService {
// ..
String saveName(Long shopId, Long languageId, String name);
}
Please note: Before saveName() is getting called there are several other requests of which some of them already get XSRF tokens. But since I can save a new name without requesting a new one I have the feeling that the previous requested token is getting reused here. Is this okay that way?
Another thing I noticed is if I add #NoXsrfProtect to saveName()
#NoXsrfProtect
String saveName(Long restaurantId, Long languageId, String name);
that the request will still contain XSRF token information:
7|2|9|http://localhost:8080/app/|424F33664CAA93E2F8A4A94C57DA5827|com.google.gwt.user.client.rpc.XsrfToken/4254043109|..ShopServlet|saveName|java.lang..
Why is the token being sent here even though the method is declared as #NoXsrfProtect?
Could somebody clarify this to me? I don't want to make any mistakes - especially in security related matters..
Is it enough to request one XSRF token from the server and reuse it over the whole session or should I request for each protect-worthy action like save, edit or delete a new XSRF token first and then perform the actual request?
Lets ignore GWT RPC's built-in XSRF protection for a moment and look at the title question and this remark: What is XSRF and how do we protect against it?
What is XSRF
XSRF stands for Cross Site Request Forgery - the idea is that a malicious site could somehow forge a request, and force one of our users to correctly send it to our application, as if they had intended to do it themselves. For example, if all it took to transfer money from one bank account to another was
GET /transfer?from=me&to=attacker&amount=10000USD
then an attacker could very simply make a request to our server as an image, css, or js file, from their own site:
<img src="https://securebank.com/transfer?from=me&to=attacker&amount=10000USD" />
Setting aside other details ("okay, that works for a GET, how did they manage to send a POST to my GWT RPC service?"), lets look at the idea of a XSRF "token" preventing this attack: what is it that a friendly client knows or can do, that an attacker cannot know or do?
Mitigation
The idea is that the client should have a way to indicate to the server that it is trusted - that it knows something which only a valid client could know, which indicates that the user is willing to make the specified action. One option is to require the user to perform a captcha, in such a way that the action cannot be scripted by the attacking site, and the user must consciously perform. Another option is to make some data available to a real/trusted client, such as cookies (that can only be read from a page loaded on the same domain), or as part of the HTML page as it loads or some other request (which might be possible to be sent by some other means, but the results can't be read).
OWASP refers to this latter piece of data as a "Synchronizer Token":
The synchronizer token pattern requires the generating of random "challenge" tokens that are associated with the user's current session. [...] When the user wishes to invoke these sensitive operations, the HTTP request should include this challenge token. It is then the responsibility of the server application to verify the existence and correctness of this token.
So, in this case, we could write some value to a cookie so that only the client can see it, and the client can then use this to generate a token. That token then should be passed to the server on each request that must be verified. But from this description, we see that it isn't necessarily important to only have one valid token at a time.
But if the attacker can get an XSS, they can just read the token and force the request again! Or MitM!
That's true, but if they have an XSS, then any request that your own JS can make, the attack can make as well. You've lost, pack up shop, time to go home. Likewise if they own the connection between the user and application and can read and write at will. XSRF protection isn't a magic wand that solves all problems, its a specific attack, and only needs to be addressed on its own: a lock in your home isn't considered faulty if the window can be broken.
Okay, back to GWT
So how does GWT do this? As you've noted, the #XsrfProtect annotation marks a service type as needing to be checked on the server. The client then must request a token, and then make sure the client's service is aware of that token for future requests.
So how does the server generate a token? The XsrfTokenServiceServlet RPC service on the server generates the token, as part of each call to the server, as you've observed, XsrfProtectedServiceServlet.validateXsrfToken then verifies that this is correct. If you wanted custom behavior, you'd have to modify each side of that system, and you could build it to invalidate each token once it is used, but this is not the default (nor, according to OWASP, is it encouraged).
Another thing I noticed is if I add #NoXsrfProtect to saveName()...
Note that validateXsrfToken is only called in one place in GWT, from in AbstractXsrfProtectedServiceServlet:
#Override
protected void onAfterRequestDeserialized(RPCRequest rpcRequest) {
if (shouldValidateXsrfToken(rpcRequest.getMethod())) {
validateXsrfToken(rpcRequest.getRpcToken(), rpcRequest.getMethod());
}
}
The method shouldValidateXsrfToken then checks if the method expressly has the protection disabled. If so, it will return false, and no check will be performed. But when building up the RPCRequest object, RPC.decodeRequest always appends the token, even if that token happens to be null:
RpcToken rpcToken = null;
if (streamReader.hasFlags(AbstractSerializationStream.FLAG_RPC_TOKEN_INCLUDED)) {
// Read the RPC token
rpcToken = (RpcToken) streamReader.deserializeValue(RpcToken.class);
}
So if the client is configured to send the token, it will always be sent, though the server might ignore it.
More reading:
https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF) and https://www.owasp.org/index.php/CSRF_Prevention_Cheat_Sheet
http://www.gwtproject.org/doc/latest/DevGuideSecurityRpcXsrf.html
This question is in some way related to the below linked question. However, I need a little more clarity on some aspects and some additional information. Refer:
REST Web Service authentication token implementation
Background:
I need to implement security for a REST Web Service using token
The webservice is intended for use with Java client. Hence, form
authentication and popups for credentials are not useful.
I'm new to REST security and encryption
This is what I have understood till now:
For first request:
User establishes https connection (or container ensures https using
301)
User POSTs username and password to login service
If credentials are valid we:
Generate a random temporary token
Store the random token on server mapping it to actual username
Encrypt the token using a symmetric key only known to server
Hash the encrypted token
Send the encrypted token and the hash to the client
For subsequent requests:
Client sends this encrypted token and hash combination (using
username field of basic?)
We make sure the encrypted token is not tampered using the hash and
then decrypt it
We check the decrypted token in the session-tracking-table for a
not-expired entry and get the actual username (expiry to be managed
by code?)
If the username is found, based on allowed roles, allowed operations
are configured
More details:
Since client is a java client, the first request can be a POST
containing the credentials. However, this looks like it may expose
the credentials before the https gets established. Hence should
there be a dummy GET to a secured resource so that https is
established first?
Assuming above is required, the second request is a LoginAction POST
with credentials. This request is handled manually (not using
container's authorisation). Is this right?
The above LoginAction returns the user the combination of encrypted
token + hash
User sets it to the header that is used by BASIC authentication
mechanism (field username)
We implement a JAASRealm to decrypt and validate the token, and find
the roles allowed
The rest of authorisation process is taken care of by the container
with the WebResourceCollection defined in the web.xml
Is this the correct approach?
Why not simplify it to the following?
For first request:
User establishes HTTPS connection to server (service does not listen on any
other ports) and POSTs credentials to login service.
Server replies with HSTS header to ensure all further communication
is HTTPS.
If credentials are valid we:
Generate a random temporary token which is securely generated using a CSPRNG. Make this long enough to be secure (128 bit).
Store the random token on server mapping it to actual username.
Send the random token to the client
For subsequent requests:
Client sends token in a custom HTTP header over HTTPS.
Token is located in the DB and mapped to the username. If found access is configured based on allowed roles and allowed operations.
If not found user is considered unauthenticated and will have to authenticate with the login service again to get a new token.
On the server side the token will be stored with an expiry date. On each access to the service this date will be updated to create a sliding expiration. There will be a job that will run every few minutes to delete expired tokens and the query that checks the token for a valid session will only check those that have not deemed to have expired (to prevent permanent sessions if the scheduled job fails for any reason).
There is no need to hash and encrypt the tokens within the database - it adds no real value apart from a touch of security through obscurity. You could just hash though. This would prevent an attacker that managed to get at the session data table from hijacking existing user sessions.
The approach looks ok. Not very secure.
Let me highlight some of the attacks possible with the request.
Man-In-the-middle attack in a POST request, the user can tamper with the request and server does not have any way to ensure the data is not tampered.
Replay attack: In this, the attacker does not tamper with the request. The attacker taps the request and sends it to the server multiple times in a short duration, though it is a valid request, the server processes the request multiple times, which is not needed
Please read about Nonce.
In the first step, the user sends his credentials i.e username and password to the login service and if you have a web based application that also uses the same password it might be dangerous. If in case password in compromised, API and web everything is exposed, please use a different PIN for API access. Also, ensure decrypted token as specified by you, expires after a certain time.
Ensure the service (application server) tomcat. jboss never returns a server page in case of internal error, this gives the attacker extra information of the server where the app is deployed.
-- MODIFIED BASED ON SECOND POST --
Yes your correct if your using mutual SSL, but in case its a one way access you don't have the client certificates. It would be good if you just double ensured everything in the request, just like signed (signature) SOAP, one of the strong data transfer mechanism. But replay attack is a possibility with HTTPS, just handle that. Rest use tokens encryption is good. And why not ask the client to decrypt the token with the password and return the output of the decryption by this you can validate the output, if it is present in your database ? This approach the user does not send the password over the wire even if it is HTTPS ?