Slim-Http icon indicating copy to clipboard operation
Slim-Http copied to clipboard

A way to disable some automatic body parsing

Open cypherbits opened this issue 5 years ago • 7 comments

Hello, Is it possible to disable automatic request parsing?

At least in version 3 it parses like this:

JSON requests are converted into associative arrays with json_decode($input, true). XML requests are converted into a SimpleXMLElement with simplexml_load_string($input). URL-encoded requests are converted into a PHP array with parse_str($input).

But I don't have installed the xml extension or have the functions disabled for security reasons. When an attacker sends a xml requests it wants to parse and I get an error like:

Call to undefined function Slim\Http\simplexml_load_string() on /var/www/website/vendor/slim/slim/Slim/Http/Request.php at 230

I would like to choose what parsing is done from these 3 options.

cypherbits avatar Dec 14 '19 14:12 cypherbits

You can try this code :

$request->registerMediaTypeParser('application/xml', function ($input) {
    return null;
});
$request->registerMediaTypeParser('text/xml', function ($input) {
    return null;
});

We could also create a function unregisterMediaTypeParser(string $mediaType). We would only have to call this function twice. Or call a function only once, named unregisterMultipleMediaTypeParser(array $mediaType) (I'm not attached to these names).

t0mmy742 avatar Jan 15 '20 22:01 t0mmy742

Another simple way to solve this is to add a middleware layer that checks a whitelist of supported content types, e.g.:

// Limit requests to application/json
$app->add(function (Request $request, Response $response, $next) {
    $whitelistContentTypes = ['application/json'];
    if (!in_array($request->getMediaType(), $whitelistContentTypes)) {
        return $response->withJson(['message' => 'Unsupported Media Type'], 415);
    }

    return $next($request, $response);
});

[edit] You may also need to consider the case where $request->getMediaType() === null

pdscopes avatar Feb 26 '20 14:02 pdscopes

Hi @pdscopes thanks for the reply, but if I want to just allow plain/normal HTTP messages, how would the code look like? (I mean blacklist XML and/or JSON and/or any other. What is the MediaType set for normal requests? Or maybe a whitelist: just allow URLencoded type.)

cypherbits avatar Feb 26 '20 18:02 cypherbits

To answer the original question, replace the XML media parser callback with your own.

Something like this will probably work:

$request->registerMediaTypeParser('application/xml', function () { return []; });
$request->registerMediaTypeParser('text/xml', function () { return []; });

(untested!)

akrabat avatar Feb 26 '20 19:02 akrabat

Hi @pdscopes thanks for the reply, but if I want to just allow plain/normal HTTP messages, how would the code look like? (I mean blacklist XML and/or JSON and/or any other. What is the MediaType set for normal requests? Or maybe a whitelist: just allow URLencoded type.)

For normal POSTed form data, the Content-Type should be: application/x-www-form-urlencoded or multipart/form-data.

akrabat avatar Feb 26 '20 19:02 akrabat

For normal POSTed form data, the Content-Type should be: application/x-www-form-urlencoded or multipart/form-data.

To follow on from this GET requests are unlikely not to send a Content-Type header so the media type will be null.

pdscopes avatar Feb 26 '20 19:02 pdscopes

The problem is that the request object is immutable, so if you call withWhatever on it, it is re-constructed and the same baked in parsers are re-added to the top-of-the chain request object in the constructor.

So you might disable it, and then someone else does something like withAttribute in a middleware, and you are back to them being enabled. This is a design issue. The parsers should be chainable, so that once set up, they are preserved.

lauri-elevant avatar Feb 03 '22 12:02 lauri-elevant