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
Related
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.
Ok, so I have simple website which force user to start from last finished step. Whenever user refresh page he needs to call at application initialization to:
REST /user/{id}/step
This endpoint will tell where user finished. The problem is I am using http only cookie. So I cannot get this {ID} from cookie in javascript.
At the moment I have added additional cookie(NOT http only) named clientId. So application can get his id from cookie, and call to this particular endpoint.
It is working but I feel that it is kinda not best approach. It has few side effects like taking care of clearing this stupid cookie on logout, etc situations.
What is best practice ? I've been thinking about creating additional endpoint which will be used on every application initialization
REST /user/status
// I want to be restfull, so I dont want REST user/logged/step
which will return setCookie clientId="" or setCookie clientId={ID} whenever user is logged or not, in this case I even don't need to care about clearing cookies on frontend side, any ideas?
The problem is I am using http only cookie.
So this http only cookie contains what? I presume a user's session? Then why do you need to specify this user ID in the URL if you should be able to get the ID from the session token?
I believe you should just have the following endpoint REST /user/step which returns the step number for a current user (defined by the session token in the http only cookie) or it returns 401 code (Unauthorised) if the user is not logged in..
How specifically is the state parameter related to the _csrf token in Spring OAuth2? Is state an encrypted version of _csrf as we would expect it to be?
Also, what specific Java syntax should be used to encode and encrypt a new _csrf value before encapsulating it into a new state parameter in Spring OAuth2?
THE CONTEXT
A client app redirects the user's web browser from the client app to the authorization server's authserver/login page. Then, in the authorization server app, a custom implementation of OncePerRequestFilter is used to redirect a request to /oauth/authorize?(list of params) into additional authentication steps, which ultimately redirect back into a new request to /oauth/authorize?(list of params). The problem is that the _csrf token changes during the additional authentication steps, and the documentation indicates that _csrf is used as the state parameter. This implies that the state value probably needs to be updated by the authorization server to reflect the new _csrf value.
HOW state IS GENERATED
The problem is that the encoded and encrypted value for state has already been set by the client app before the client app uses an OAuth2ClientAuthenticationProcessingFilter to transfer information for the authentication server to use while authenticating the user via the authentication steps mentioned above.
Some research indicates that the state key is generated by the client using a DefaultStateKeyGenerator, which in turn uses a RandomValueStringGenrator to generate a 6 character state value.
For example, in the original request made to /oauth/authorize?(list of params), the raw _csrf value is encoded into fupS1L, as shown in the following url:
/oauth/authorize?client_id=acme&redirect_uri=http://localhost:8080/login&response_type=code&state=fupS1L
If the _csrf value changes to a69fd23a-a393-4b27-a685-a323fd31db9a during the redirect flow, the value of fupS1L in the state parameter will no longer be valid, and the resulting token will not be authorized to permit access to protected resources.
What specific syntax do I use in order to convert the new _csrf value into an encrypted value similar to fupS1L that can be passed into a functional state parameter?
Also, is there any relationship between the state variable and the _csrf token? The RandomValueStringGenerator used by DefaultStateKeyGenerator seems to simply create a random 6 character String. I would like an authoritative answer by someone who has worked deeply with the code or even written it. I am doing a deep review of the code, so a casual passer by who reads the RandomValueStringGenerator source code and says state is not related to the csrf token would not be adding any value. The author of the API, however, would help us all out a lot by telling us how this works.
NOTE TO SPRING
It should not require this much digging to find documentation of such a simple thing.
I know it's quite old since its been asked. Still sharing what I know now, as I have worked through a similar requirement to pass a deeplink in the 'state' parameter. I wanted to redirect to this deeplink when flow comes back from the auth-server after a successful oauth sign-in session.
Primarily I followed this SOF answer -> https://stackoverflow.com/a/52462787/5107365. This suggests to extend the DefaultStateKeyGenerator to use the deeplink parameter from the request to AAS to encrypt+encode to set into the 'state' parameter. And, then the custom implementation of OAuth2ClientAuthenticationProcessingFilter.AuthenticationSuccessHandler is used to override determineTargetUrl method to decode+decrypt the state parameter when the flow comes back after successful auth. Hopefully it will help somebody who is in need of a similar requirement.
My initial code generated tokens for the requests that could alter state of my database, like CRUD operations. The token was generated for each request. Sent to client side in JSON-format along with other data and I expected this token to be returned with the request and changed it after completion of the request. But, as I implemented it to only parts of my code (CRUD operations), I was told to redo it and make it web-app wide. I think the best way to do this is with filters.
My problem is, how do I make the client send "the token" for each request? Do I set it in cookies? What are my options? Please advice.
best way is , all links should be GET request, and within get requests no modification should be made to application state. So for GET requests there will be no need for CSRF tokens.
For POST request s which make modifications in application state you have to generate, csrf hidden fields in your forms and validate the token in server during form submit.
I have a non-gae, gwt application and it have a module that allows users to create documents online via google docs api.
To do that, i first ask user to enter the name and type of the document, than create a new document via google docs api with the given parameters and onSucces part of that servlet returns edit link which is used in client side to open a new page to edit the created document.
Problem that, eachtime i try to open that editLink user have to enter login informations. To solve this i try to use Google Client Login but i am totally lost i think.
First i have username and password of user and can directly use them, after searching i tried some examples which usually returns a token like this and that. Now what should i do with token? How can it be used to complete login process or should totally find another way to do login? All those oauth1,oauth2 and etc. documentations confused me a little bit.
here are my steps;
Server side;
LinkedHashMap<String, String> hashMap = new LinkedHashMap<String, String>();
// Login
DocumentList docList = new DocumentList("document");
docList.login(ServletUtil.googleDocsLoginInfo().get("username"), ServletUtil.googleDocsLoginInfo().get("password"));
//Create document with a unique suffix
String docName= parameterName+ "-Created-" + new Date();
docList.createNew(docName, dosyaTur);
// Find the created document and store editLink
DocumentListFeed feed = docList.getDocsListFeed("all");
for (final DocumentListEntry entry : feed.getEntries()) {
if (entry.getTitle().getPlainText().equals(docName)) {
hashMap.put("editlink", entry.getDocumentLink().getHref());
}
}
return hashMap;
And Client side;
#Override
public void onSuccess(LinkedHashMap<String, String> result) {
String editLink = result.get("editlink");
Window.open(editLink,"newwindow","locationno");
}
Thanks for your helps.
If I may suggest using OAuth instead of Client Login, which is outdated and less secure.
The functionality is basically the same (for OAuth 2.0 there are more ways to handle the login).
I know, trying to understand how to access the api via OAuth is very confusing, so I try to break it down a little:
If you use OAuth 2.0 you may want to use a library like this one or you can try out my own (although I wrote it for Android, this could work with other Java Apps including Web Apps)
This is what happens when a user logs in the first time with your app:
> Your App sends an authorization request containing some information about your app - for example your app needs to be registered with google and therefore has a special application key
< The Server sends you a url, open it in a new browser window and let the user login. There he will be asked to allow your app to access his account (or some parts of it) - when he confirms he will be prompted an Authorization Code which he needs to copy
> The user gets back to your app, where you will ask him for the authorization code. After he gave it, your app connects again with the server and sends the code as some kind of authorization grant of the user.
< The Server answers with a access token
All you need to do is use this access token (also called a bearer token) in all your requests to the server hidden in the header message.
I am sorry I can't give you a more precise answer right now, since I never used GWT. All I can say is, try using OAuth2, it is actually very simple (after you learn what all this confusing things like authorization flow, bearer token etc are) and really comfortable for your user, once the he has done the first login.