Bug #105201
openPOST request with empty object generates a Bad multipart parameters parsing on F5 (RFC1341)
0%
Description
Our hosting is behind an F5 instance (WAF / Web Application Firewall) and with Typo3 v12 I get errors when the backend makes POST requests with an empty object as value. This happens for example for "Flush frontend caches", "Flush all caches", "Exit switch user mode", ...
The error report says that it's a "Bad multipart parameters parsing" because of "Closing multipart boundary is not found".
We also got a copy of the request payload:
POST /typo3/ajax/switch/user/exit?token=971033045db311905f14c9e91265dbb3ff2613ee HTTP/1.1 Host: test.domain.tdl Connection: keep-alive Content-Length: 44 Cache-Control: max-age=0 sec-ch-ua-platform: "macOS" User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 sec-ch-ua: "Google Chrome";v="129", "Not=A?Brand";v="8", "Chromium";v="129" Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryFdQi1AC0iZClXe8T sec-ch-ua-mobile: ?0 Accept: */* Origin: https://test.domain.tdl Sec-Fetch-Site: same-origin Sec-Fetch-Mode: cors Sec-Fetch-Dest: empty Referer: https://test.domain.tdl/typo3/module/dashboard Accept-Encoding: gzip, deflate, br, zstd Accept-Language: en,en-US;q=0.9,fr;q=0.8,de;q=0.7 Cookie: dtCookie=[...] X-Forwarded-For: xxx.xxx.xxx.xxx X-Forwarded-Proto: https ------WebKitFormBoundaryFdQi1AC0iZClXe8T--
Reading the RFC 1341 it seems that we are missing the start boundary and we only have the end boundary.
Typo3 does not produce the final payload it-self and "just" passes everything to fetch(), but before passing those values it processes some of the data and specially if the main data is an empty javascript object, this error is produced.
I found a possible solution by changing AjaxRequest::post() (vendor/typo3/cms-core/Resources/Public/JavaScript/ajax/ajax-response.js) to return an empty string as body if we have an empty javascript object, instead of running InputTransformer.byHeader() on it and create an empty FormData that produces those boundaries.
async post(e, t = {}) {
const r = {
body: "string" == typeof e || e instanceof FormData ? e : ( Object.keys(e).length ? InputTransformer.byHeader(e, t?.headers) : ""),
cache: "no-cache",
method: "POST"
}, n = await this.send({...r, ...t});
return new AjaxResponse(n)
}
For now I've copied the file to my extension and I'm overriding it via JavaScriptModules.php.
Updated by Garvin Hicking about 2 months ago
- Status changed from New to Needs Feedback
Thanks for your report and the good idea on how to solve it. Would you like to submit this as a parch?
Updated by Filipe DA COSTA about 2 months ago
Garvin Hicking wrote in #note-1:
Thanks for your report and the good idea on how to solve it. Would you like to submit this as a parch?
Yes, will do
Updated by Gerrit Code Review about 2 months ago
- Status changed from Needs Feedback to Under Review
Patch set 1 for branch main of project Packages/TYPO3.CMS has been pushed to the review server.
It is available at https://review.typo3.org/c/Packages/TYPO3.CMS/+/86441
Updated by Gerrit Code Review about 2 months ago
Patch set 2 for branch main of project Packages/TYPO3.CMS has been pushed to the review server.
It is available at https://review.typo3.org/c/Packages/TYPO3.CMS/+/86441