This is an automated email from the ASF dual-hosted git repository. papegaaij pushed a commit to branch crypt-unification in repository https://gitbox.apache.org/repos/asf/wicket.git
commit e1c2f265082461f629daee38ec8806c9139ceeca Author: Emond Papegaaij <[email protected]> AuthorDate: Tue Aug 4 13:14:36 2026 +0200 WICKET-7190 Verify the upload token by decrypting it The signed upload settings introduced in 483b83ca62 were validated by re-encrypting the expected settings and comparing the resulting ciphertext to the token supplied by the client. That only worked because the default crypt at the time was deterministic PBE: the same plaintext always produced the same ciphertext. SchemeCrypt encrypts with a fresh random nonce per message, as an AEAD mode must, so no two encryptions of the same settings agree and the comparison never succeeds - every upload through FileUploadToResourceField was rejected. Validate the token by decrypting it and comparing the settings it carries instead. The authentication tag is what makes the token unforgeable, and decryption returns null for anything tampered with, so the check keeps rejecting a client that alters the limits. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> --- .../upload/resource/AbstractFileUploadResource.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/AbstractFileUploadResource.java b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/AbstractFileUploadResource.java index dea29a3494..c20e7a5ce8 100644 --- a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/AbstractFileUploadResource.java +++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/AbstractFileUploadResource.java @@ -227,9 +227,21 @@ public abstract class AbstractFileUploadResource extends AbstractResource return false; } - String expectedToken = createUploadToken(uploadId, maxSize, fileMaxSize, fileCountMax); - return MessageDigest.isEqual(expectedToken.getBytes(StandardCharsets.UTF_8), - actualToken.getBytes(StandardCharsets.UTF_8)); + // the token is authenticated but not deterministic - encryption uses a fresh nonce per + // message - so it cannot be validated by re-encrypting and comparing ciphertext. Decrypt + // it instead and compare the settings it carries; the authentication tag is what makes it + // unforgeable, and decryption fails on anything that was tampered with. + String decryptedToken = Application.get().getSecuritySettings().getCryptFactory().newCrypt() + .decryptUrlSafe(actualToken); + if (decryptedToken == null) + { + return false; + } + + String expectedSettings = serializeUploadSettings(uploadId, maxSize, fileMaxSize, + fileCountMax); + return MessageDigest.isEqual(expectedSettings.getBytes(StandardCharsets.UTF_8), + decryptedToken.getBytes(StandardCharsets.UTF_8)); } private ResourceResponse createErrorResponse(ResourceResponse resourceResponse, String errorMessage)
