New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixes for the CSRF filter #1737
Conversation
@jroper, a huge thanks for putting this together so quickly. One question: is it possible to make the token comparison pluggable? If the custom token generator produces a signed token value (ie, a signature is happening, but outside of the Play filter code), it may need a way to check the signature instead of a literal string comparison. Instead of taking in trait TokenManager {
def generateToken: String
def compareTokens(tokenA: String, tokenB: String): Boolean
} The default Play implementations of this class could be something like: class SignedTokenManager extends TokenManager {
def generateToken: String = Crypto.generateSignedToken()
def compareTokens(tokenA: String, tokenB: String): Boolean = Crypto.compareSignedTokens(tokenA, tokenB)
}
class UnsignedTokenManager extends TokenManager {
def generateToken: String = Crypto.generateToken()
def compareTokens(tokenA: String, tokenB: String): Boolean = Crypto.constantTimeEquals(tokenA, tokenB)
}
class CSRFAction(next: EssentialAction,
tokenName: String = CSRFConf.TokenName,
cookieName: Option[String] = CSRFConf.CookieName,
secureCookie: Boolean = CSRFConf.SecureCookie,
createIfNotFound: RequestHeader => Boolean = CSRFConf.defaultCreateIfNotFound,
tokenManager: TokenManager = new SignedTokenManager()) extends EssentialAction {
// ...
} Apologies for not thinking of this earlier, but it seems like a more robust and consistent API. What do you think? |
play2-PRs #772 SUCCESS |
That would probably make the code neater. I'll have a go. |
The biggest problem with this is that it wouldn't work with CSRF.getToken, since that doesn't know what the TokenGenerator should be, and in the case of the BREACH vulnerability needs to be able to resign the tokens. Of course, anyone using a custom TokenGenerator could simply not use that method to get the current token, but implement their own. |
If we wanted end-to-end consistency with the CSRF implementation, we'd probably need to either:
Either option would be accessible to |
Agreed. Anyway, PR is updated, I've called it |
// Extract the signed token, and then resign it. This makes the token random per request, preventing the BREACH | ||
// vulnerability | ||
.flatMap(Crypto.extractSignedToken) | ||
.map(token => Token(Crypto.signToken(token))) | ||
token.flatMap(Crypto.extractSignedToken) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should these few lines be using the defaultTokenProvider
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'd have to add a resign() method to the TokenProvider for these lines to make sense in that context. Since there's no way of supplying a TokenProvider to the method yet, it didn't make sense to abstract that logic out yet.
play2-PRs #773 SUCCESS |
Gotcha. Thanks again for putting this together. Looks good to me 👍 |
LGTM Final review with @richdougherty |
.dependsOn(PlayProject, PlayTestProject % "test", PlayJavaProject % "test") | ||
.settings( | ||
binaryIssueFilters ++= Seq( | ||
// oops... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add a little more detail to this comment. :)
Other than a bit more commenting, lgtm. 👍 |
please fix that |
* Fixes playframework#1734, custom token generator feature reinstatement * Fixes playframework#1728, ensured CSRFFilter can be instantiated without a running application * Added a csrf.sign.tokens conifguration option to switch between default CSRF token providers, either signed or unsigned. * Abstracted tests so they can be run on many different permutations of configuration * Added documentation about all the different configuration options This commit breaks binary compatibility, the CSRFFilter constructor parameters are now not lazy, and CSRFFilter is no longer a case class, so many of the methods it used to provide are no longer there. This was deemed necessary because the intended use of CSRFFilter, ie: object Global extends WithFilters(CSRFFilter()) with GlobalSettings was not possible with the old constructor. The constructor is however still source compatible for most use cases. Since that constructor is intentionally breaking binary compatibility, new parameters that were added for custom token generation and configuration signing were added without consideration for binary compatibility, only source compatibility.
play2-PRs #794 SUCCESS |
Master branch also updated. |
This commit breaks binary compatibility, the CSRFFilter constructor parameters are now not lazy, and CSRFFilter is no longer a case class, so many of the methods it used to provide are no longer there. This was deemed necessary because the intended use of CSRFFilter, ie:
was not possible with the old constructor. The constructor is however still source compatible for most use cases.
Since that constructor is intentionally breaking binary compatibility, new parameters that were added for custom token generation and configuration signing were added without consideration for binary compatibility, only source compatibility.