From: Tim Düsterhus Date: Fri, 4 Nov 2022 09:00:12 +0000 (+0100) Subject: Improve content-type check in JsonBody middleware X-Git-Tag: 6.0.0_Alpha_1~723^2 X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=52b40b21ff60dc5edd24301268c24ed7b21ca073;p=GitHub%2FWoltLab%2FWCF.git Improve content-type check in JsonBody middleware --- diff --git a/wcfsetup/install/files/lib/http/middleware/JsonBody.class.php b/wcfsetup/install/files/lib/http/middleware/JsonBody.class.php index da29018d6d..61a2a31ec6 100644 --- a/wcfsetup/install/files/lib/http/middleware/JsonBody.class.php +++ b/wcfsetup/install/files/lib/http/middleware/JsonBody.class.php @@ -2,6 +2,7 @@ namespace wcf\http\middleware; +use GuzzleHttp\Psr7\Header; use Laminas\Diactoros\Response\JsonResponse; use Laminas\Diactoros\Response\TextResponse; use Psr\Http\Message\ResponseInterface; @@ -24,18 +25,13 @@ final class JsonBody implements MiddlewareInterface { public const HAS_VALID_JSON_ATTRIBUTE = self::class . "\0hasValidJson"; - private const EXPECTED_CONTENT_TYPE = 'application/json'; - /** * @inheritDoc */ public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { $hasValidJson = false; - if ( - $request->getHeaderLine('content-type') === self::EXPECTED_CONTENT_TYPE - || \str_starts_with($request->getHeaderLine('content-type'), self::EXPECTED_CONTENT_TYPE) - ) { + if ($this->contentTypeIsJson($request)) { try { $data = JSON::decode($request->getBody()); } catch (SystemException $e) { @@ -54,4 +50,40 @@ final class JsonBody implements MiddlewareInterface return $handler->handle($request); } + + private function contentTypeIsJson(ServerRequestInterface $request): bool + { + $headers = Header::parse($request->getHeaderLine('content-type')); + + // If multiple content-type headers are given, we refuse to process any. + if (\count($headers) !== 1) { + return false; + } + + $header = $headers[0]; + + // The content-type itself is not part of a key-value pair and thus is numerically + // indexed. + if (!isset($header[0])) { + return false; + } + + // If the content-type is not application/json, we don't understand it. + if ($header[0] !== 'application/json') { + return false; + } + + foreach ($header as $key => $value) { + // If a charset pararameter exists ... + if (\strtolower($key) === 'charset') { + // ... and the charset is not UTF-8, we don't understand it. + if (\strtolower($value) !== 'utf-8') { + return false; + } + } + } + + // If no charset is given or the charset is UTF-8, we understand it. + return true; + } }