I can speak to CSRF generally, but not to the Spring framework (which I haven't used). Since I can't verify your claims with Spring itself, I'm going to take your claims at face value. Namely:
- You can fetch a CSRF token by making a valid call using any session of your choice
- If you force any other user to make a request with your CSRF token, Spring will accept it as a valid token
Assuming that your findings are accurate (again I'm not doubting you, I just can't verify it myself), these are my immediate thoughts:
- CSRF tokens should not be allowed to cross sessions like this.
- I would certainly consider this a security vulnerability.
- Additional details about how Spring validates CSRF tokens are needed to decide whether or not there is a realistic attack vector here.
In detail, CSRF tokens should definitely not be able to cross sessions. Each CSRF token should be associated with the session that generated it, and it should not be a valid token for any other session. As you point out, allowing tokens to cross sessions make it possible for an attacker to generate valid tokens before hand. This can definitely be a problem. However, there are a few circumstances which can mitigate the potential threat here:
More than just token verification
Tokens are just one way to protect against CSRF attacks. Personally, I find them to be the most straight-forward and reliable way. However, they are not the only way. Another option is to check for REFERRER and ORIGIN headers. If Spring is also checking for REFERRER and ORIGIN headers then this weakness in their CSRF token is unlikely to be exploitable. The test you did (manually changing the CSRF token via browser tools) will still leave you with proper REFERRER and ORIGIN headers, which means that you will pass both CSRF checks. However, it would not be possible for an attacker to reproduce this. It works for you because you were on the actual application page and edited the application page directly. An attacker will make a CSRF attack happen from somewhere completely different, and can't force the REFERRER and ORIGIN headers. So if Spring is also checking REFERRER and ORIGIN headers, then you are fine.
Does Spring do both? I don't know. Why would Spring do both? I'm not sure, although it would be in line with the concept of "Defense in depth", so it wouldn't be crazy for it to do both tests. If it is doing both, then obviously even a large weakness in the CSRF token won't matter. If however it does both and ignores one or the other in certain circumstances, then there might be an attack vector if you can make it ignore header checks and also spoof the CSRF token.
CSRF token expiration
There may also be a token expiration that will make it hard to turn this into an exploitable attack vector. In fact, it almost certainly has a token expiration. As an attacker you can generate a valid CSRF token, but if it has a short expiration then you need to get that in front of a target quickly. Say you built a CSRF attack vector that effectively elevated your user account to admin when an admin views a malicious page you generated. This will only do you any good if you can trick an admin into viewing your attack page before your token expires. Depending on your delivery method and the length of the token expiration, this may be very difficult.
To summarize: is this the norm for CSRF? No, in fact it is potentially dangerous. Is it exploitable? That's harder to answer. As always, the devil is in the details. Is it worth digging into more? I would say so.