bad request

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

bad request

otto
Hi,

Vulnerability tests that ran against our site showed that URL's with
percentage encoded UTF8 characters creates a 500 (internal server
error) response, where I think they should actually respond with 404
or 405.

Some examples:

GET /% breaks when WAUrl class #decodePercent: tries to read off the
end of the stream.
GET /%C0 breaks for the same reason, but in GRPharoUtf8CodecStream |
next: (more cases in there!)
GET /%C0%10 raises GRInvalidUtf8Error.
GET /%C0%AE returns 404 (not found).

I'd like to improve on this, if you agree.

I need some guidance on how to improve regarding the construction of
the request. This is the code in WAServerAdaptor | contextFor:

It creates a request (self requestFor: aNativeRequest) without
handling exceptions. This means that the outer exception handler
catches it and returns a 500.

I am not sure where to handle errors such as these and to elegantly
ensure that the response is "bad request" if the request could not be
parsed. I also see that there's a nice badRequest method on
WAResponse, without any senders in my image. Perhaps this is some
perform: magic that I can't trace.

Any help will be appreciated.

Thanks
Otto
_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: bad request

Philippe Marschall
On Mon, Dec 23, 2013 at 4:25 PM, Otto Behrens <[hidden email]> wrote:
> Hi,
>
> Vulnerability tests that ran against our site showed that URL's with
> percentage encoded UTF8 characters creates a 500 (internal server
> error) response, where I think they should actually respond with 404
> or 405.

I think in this very specific case 400 (bad request would be the way to go).

> Some examples:
>
> GET /% breaks when WAUrl class #decodePercent: tries to read off the
> end of the stream.
> GET /%C0 breaks for the same reason, but in GRPharoUtf8CodecStream |
> next: (more cases in there!)
> GET /%C0%10 raises GRInvalidUtf8Error.
> GET /%C0%AE returns 404 (not found).
>
> I'd like to improve on this, if you agree.
>
> I need some guidance on how to improve regarding the construction of
> the request. This is the code in WAServerAdaptor | contextFor:
>
> It creates a request (self requestFor: aNativeRequest) without
> handling exceptions. This means that the outer exception handler
> catches it and returns a 500.

So right now FastCGI already turns it into a 500?

> I am not sure where to handle errors such as these and to elegantly
> ensure that the response is "bad request" if the request could not be
> parsed. I also see that there's a nice badRequest method on
> WAResponse, without any senders in my image. Perhaps this is some
> perform: magic that I can't trace.

That's simply a convenience method for setting the status code.

> Any help will be appreciated.

There could be all sorts of things that could go wrong causing an
exception. The http version for example could be "A.B", cookie parsing
could fail and URL decoding could fail [1].
Should the response generated in the exception case be a WAResponse or
a "native" response? WAResponse response may be a bit tricky because
you don't have WARequestContext because you don't have WARequest. So
it's probably going to be "native" response, this also avoids the
other issue of what you're going to do if response conversion
(#responseFrom:) throws some kind of exception.
So in the end all what you do is use a 400 instead of a 500 for some
exception classes.

 [1] http://code.google.com/p/seaside/issues/detail?id=764

Cheers
Philippe
_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: bad request

otto
Thanks for the response.

>> Vulnerability tests that ran against our site showed that URL's with
>> percentage encoded UTF8 characters creates a 500 (internal server
>> error) response, where I think they should actually respond with 404
>> or 405.
>
> I think in this very specific case 400 (bad request would be the way to go).

Yes, agree. Not 405.

>> It creates a request (self requestFor: aNativeRequest) without
>> handling exceptions. This means that the outer exception handler
>> catches it and returns a 500.
>
> So right now FastCGI already turns it into a 500?

Yes, the GS one does

> There could be all sorts of things that could go wrong causing an
> exception. The http version for example could be "A.B", cookie parsing
> could fail and URL decoding could fail [1].

Yes, agree. Parsing the UTF-8 encoded characters in the URL is one.

Looking at rfc6265, I could not specifically pick up appropriate
responses if a cookie could not be parsed (or any other header field /
part of the header). One conclusion that I could find was that the
server should "degrade gracefully" when receiving invalid cookies. But
this is not necessarily the inability to parse the cookies in the
first place. And then a similar question arises for the parsing of
other header fields. Please let me know if you have better references
to read up on.

This is my best conclusion - please comment:
For someone providing a web application, the server implementer can either
1) be strict respond with 400 (bad request) if it finds something it
dislikes in the request (either the http method + URL, headers or
body),
or 2) ignore inappropriate parts of the request. Of course, some parts
of the request can't be ignored, so one will have to distinguish
carefully.

> Should the response generated in the exception case be a WAResponse or
> a "native" response? WAResponse response may be a bit tricky because
> you don't have WARequestContext because you don't have WARequest. So
> it's probably going to be "native" response, this also avoids the
> other issue of what you're going to do if response conversion
> (#responseFrom:) throws some kind of exception.
> So in the end all what you do is use a 400 instead of a 500 for some
> exception classes.

Ok, I understand some of the predicament. But I don't understand how I
would use 400 and not 500 in these cases.

A "native" request would be something that Comanche / Zinc / FastCGI
would create and pass to Seaside (i.e. WAServerAdaptor >> process:)

In the error case that the Seaside framework does not handle, the web
server / fast cgi server implements a fallback handler for server
errors (500 Internal Server Error). (e.g. HttpService >>
handleDispatchErrorsIn:). This is the error handler invoked in this
discussion where the URL contains percent-encoded parts that break the
UTF-8 decoding.

It seems if I want to handle any of these errors (consistently), I
have to modify Comanche, Zinc and FastCGI adaptors.

I think we should allow the Seaside framework to handle these errors
as well. I understand giving the WAResponse the responsibility to
handle it can be tricky, but it may just be the right place.
Currently, it does handle some of the 400 range of errors (eg. not
found).

This is my suggestion: Create the WARequestContext on the native
request without parsing it.

Parsing the URL effectively comes down to handleFiltered: on
WADispatcher that will try to get the url via the consumer on the
request. If parsing it breaks, the request is marked as a bad request.
The dispatcher could pass to the default handler. The parsing errors
of the other parts of the request would then go to the handler
dispatched to. And that could in turn be dispatched to an error
handler.

This gives the user of the Seaside framework the flexibility of
handling these errors elegantly as well. Only errors that break the
seaside framework itself, the ones that somehow fall through
WAExceptionHandler >> #handleExceptionsDuring: would then trigger the
Comanche / Zinc / FastCGI handler.
_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: bad request

otto
> This is my suggestion: Create the WARequestContext on the native
> request without parsing it.
>
> Parsing the URL effectively comes down to handleFiltered: on
> WADispatcher that will try to get the url via the consumer on the
> request. If parsing it breaks, the request is marked as a bad request.
> The dispatcher could pass to the default handler. The parsing errors
> of the other parts of the request would then go to the handler
> dispatched to. And that could in turn be dispatched to an error
> handler.

I got this to work in our application. I added adaptor and
nativeRequest to WARequest, and constructed it with these:

WAServerAdaptor >> requestFor: aNativeRequest
"Answer a request object for aNativeRequest."

^ WARequest basicNew
adaptor: self;
nativeRequest: aNativeRequest;
yourself

I then lazy initialized the variables on WARequest, using the messages
in the current version of requestFor:. For example:

WARequest >> uri
^ uri ifNil: [ uri := adaptor ifNotNil: [ (adaptor requestUrlFor:
nativeRequest) seasideUrl ] ]

This could be better, I suppose (I personally don't really like lazy
initializations). But a lot of tests construct the request with
specific URLs, methods and what not. So I would need to refactor these
to use a simple native request. I then changed WARequestContext to be
aware of a parsing error (must be better, should be on request
itself...)

The reason why this reports in our application is because the parsing
of the url is invoked again later on in the process, which throws an
exception.

The source modifications are here:
https://github.com/finworks/Seaside30/tree/handleRequestParsingError.
(A fork from https://github.com/glassdb/Seaside30)

1. Please let me know if you think this can generally work
2. Do you think I should continue and make the changes on Seaside "trunk"?
3. I suppose http://www.squeaksource.com/Seaside30LGPL is the place to do it?
4. Seaside 3.1 only?

Cheers
Otto
_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: bad request

otto
> to use a simple native request. I then changed WARequestContext to be
> aware of a parsing error (must be better, should be on request
> itself...)

Made another change - WADispatcher now reponds with bad request.

> The source modifications are here:
> https://github.com/finworks/Seaside30/tree/handleRequestParsingError.
> (A fork from https://github.com/glassdb/Seaside30)

If you attempted to see changes up to now, there were none. Sorry, I
pushed 2 minutes ago.
_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: bad request

Philippe Marschall
In reply to this post by otto
On Thu, Dec 26, 2013 at 12:05 PM, Otto Behrens <[hidden email]> wrote:

> Thanks for the response.
>
>>> Vulnerability tests that ran against our site showed that URL's with
>>> percentage encoded UTF8 characters creates a 500 (internal server
>>> error) response, where I think they should actually respond with 404
>>> or 405.
>>
>> I think in this very specific case 400 (bad request would be the way to go).
>
> Yes, agree. Not 405.
>
>>> It creates a request (self requestFor: aNativeRequest) without
>>> handling exceptions. This means that the outer exception handler
>>> catches it and returns a 500.
>>
>> So right now FastCGI already turns it into a 500?
>
> Yes, the GS one does
>
>> There could be all sorts of things that could go wrong causing an
>> exception. The http version for example could be "A.B", cookie parsing
>> could fail and URL decoding could fail [1].
>
> Yes, agree. Parsing the UTF-8 encoded characters in the URL is one.
>
> Looking at rfc6265, I could not specifically pick up appropriate
> responses if a cookie could not be parsed (or any other header field /
> part of the header). One conclusion that I could find was that the
> server should "degrade gracefully" when receiving invalid cookies. But
> this is not necessarily the inability to parse the cookies in the
> first place. And then a similar question arises for the parsing of
> other header fields. Please let me know if you have better references
> to read up on.
>
> This is my best conclusion - please comment:
> For someone providing a web application, the server implementer can either
> 1) be strict respond with 400 (bad request) if it finds something it
> dislikes in the request (either the http method + URL, headers or
> body),
> or 2) ignore inappropriate parts of the request. Of course, some parts
> of the request can't be ignored, so one will have to distinguish
> carefully.

I generally prefer option 1) because this way when something goes
wrong on the server the client gets notified. Otherwise client errors
can be really annoying to debug.

>> Should the response generated in the exception case be a WAResponse or
>> a "native" response? WAResponse response may be a bit tricky because
>> you don't have WARequestContext because you don't have WARequest. So
>> it's probably going to be "native" response, this also avoids the
>> other issue of what you're going to do if response conversion
>> (#responseFrom:) throws some kind of exception.
>> So in the end all what you do is use a 400 instead of a 500 for some
>> exception classes.
>
> Ok, I understand some of the predicament. But I don't understand how I
> would use 400 and not 500 in these cases.

something like

process: aNativeRequest
    ^ [ self basicProcess ]
        on: self badRequestExceptionSet
        do: [ :e | self badRequestFor: e ]

badRequestExceptionSet
  ^ GRInvalidUtf8Error, WAInvalidUrlSyntaxError

badRequestFor: anError
  "default implementation, trigger the servers internal error handler
  sublcasses can answer a 'native' bad request (HTTP 400) respone"
  anError signal

> A "native" request would be something that Comanche / Zinc / FastCGI
> would create and pass to Seaside (i.e. WAServerAdaptor >> process:)

Yes.

> In the error case that the Seaside framework does not handle, the web
> server / fast cgi server implements a fallback handler for server
> errors (500 Internal Server Error). (e.g. HttpService >>
> handleDispatchErrorsIn:). This is the error handler invoked in this
> discussion where the URL contains percent-encoded parts that break the
> UTF-8 decoding.
>
> It seems if I want to handle any of these errors (consistently), I
> have to modify Comanche, Zinc and FastCGI adaptors.

Yes

> I think we should allow the Seaside framework to handle these errors
> as well. I understand giving the WAResponse the responsibility to
> handle it can be tricky, but it may just be the right place.
> Currently, it does handle some of the 400 range of errors (eg. not
> found).

WAResponse does not handle 400. Somebody somewhere creates a 400
response just like somebody somewhere creates a 200 response.

> This is my suggestion: Create the WARequestContext on the native
> request without parsing it.

I'm not liking it. The propose of WARequestContext is that it holds on
to (among other things) a WARequest and a WAResponse. We just got an
exeption when trying to create a WARequest. This smells like having a
partially initialized object that will just cause other exceptions
further down the road.

> Parsing the URL effectively comes down to handleFiltered: on
> WADispatcher that will try to get the url via the consumer on the
> request. If parsing it breaks, the request is marked as a bad request.
> The dispatcher could pass to the default handler. The parsing errors
> of the other parts of the request would then go to the handler
> dispatched to. And that could in turn be dispatched to an error
> handler.

No, the URL is parsed in WAServerAdaptor >> #requestUrlFor:

> This gives the user of the Seaside framework the flexibility of
> handling these errors elegantly as well. Only errors that break the
> seaside framework itself, the ones that somehow fall through
> WAExceptionHandler >> #handleExceptionsDuring: would then trigger the
> Comanche / Zinc / FastCGI handler.

Cheers
Philippe
_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: bad request

Philippe Marschall
In reply to this post by otto
On Thu, Dec 26, 2013 at 2:02 PM, Otto Behrens <[hidden email]> wrote:
>> to use a simple native request. I then changed WARequestContext to be
>> aware of a parsing error (must be better, should be on request
>> itself...)
>
> Made another change - WADispatcher now reponds with bad request.

IMHO dipsatcher is the wrong place to do this. WADispatcher is just a
request handler that delegates to other request handlers. There is no
requirement that you have a dispatcher in the handler chain (it is the
default though).

Sorry for being so negative. I understand you're trying to fix an
important issue for you and I'm just responding with "I don't like it"
and don't really have a better solution myself.

Cheers
Philippe
_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: bad request

otto
>> Made another change - WADispatcher now reponds with bad request.
>
> IMHO dipsatcher is the wrong place to do this. WADispatcher is just a
> request handler that delegates to other request handlers. There is no
> requirement that you have a dispatcher in the handler chain (it is the
> default though).

Ok, yes, you're right.

> Sorry for being so negative. I understand you're trying to fix an
> important issue for you and I'm just responding with "I don't like it"
> and don't really have a better solution myself.

No problem. I'm arguing for alternatives because I want to test if
they can work. So thanks for the responses and the patience.

I think that this should not only be an important issue for me, but
for other users if Seaside too. And that is because I believe that we
should work out ways for the framework to handle errors in a
consistent way. Well, it is not the end of the world when the user of
the application get a crude response for a bad request, or for a 'not
found', but could be better.

Thanks
Otto
_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: bad request

otto
In reply to this post by Philippe Marschall
>> This is my best conclusion - please comment:
>> For someone providing a web application, the server implementer can either
>> 1) be strict respond with 400 (bad request) if it finds something it
>> dislikes in the request (either the http method + URL, headers or
>> body),
>> or 2) ignore inappropriate parts of the request. Of course, some parts
>> of the request can't be ignored, so one will have to distinguish
>> carefully.
>
> I generally prefer option 1) because this way when something goes
> wrong on the server the client gets notified. Otherwise client errors
> can be really annoying to debug.

Yes, agree. I could not find "invalid cookie" kind of responses when
searching for how others solve this kind of problem though. Having
said this, I'd also rather respond with 'bad request' if I find
anything I don't like in the request.

I suppose we also have to distinguish between unable to parse the
cookie header and an unexpected key or value in the cookie header. If
the server receives a key that it does not recognise, should it
respond with bad request?

> process: aNativeRequest
>     ^ [ self basicProcess ]
>         on: self badRequestExceptionSet
>         do: [ :e | self badRequestFor: e ]
>
> badRequestExceptionSet
>   ^ GRInvalidUtf8Error, WAInvalidUrlSyntaxError
>
> badRequestFor: anError
>   "default implementation, trigger the servers internal error handler
>   sublcasses can answer a 'native' bad request (HTTP 400) respone"
>   anError signal

This means that every subclass of WAServerAdaptor have to implement a
native bad request response. Is there an elegant (i.e. non monkey
patched) way for me to customize this response? That's why I thought
the seaside framework must handle it, because I can customise there.

>> It seems if I want to handle any of these errors (consistently), I
>> have to modify Comanche, Zinc and FastCGI adaptors.
>
> Yes

Ok, would be soo nice if I can do it once in my application though
(because I do it there already).

>> I think we should allow the Seaside framework to handle these errors
>> as well. I understand giving the WAResponse the responsibility to
>> handle it can be tricky, but it may just be the right place.
>> Currently, it does handle some of the 400 range of errors (eg. not
>> found).
>
> WAResponse does not handle 400. Somebody somewhere creates a 400
> response just like somebody somewhere creates a 200 response.

Sorry, the request handler may create a WAResponse with code 400.

>> This is my suggestion: Create the WARequestContext on the native
>> request without parsing it.
>
> I'm not liking it. The propose of WARequestContext is that it holds on
> to (among other things) a WARequest and a WAResponse. We just got an
> exeption when trying to create a WARequest. This smells like having a
> partially initialized object that will just cause other exceptions
> further down the road.

Yes, I share your discomfort. But, the same problem applies to the
response. When creating the context, the response is empty. Exceptions
raised during the construction of the response may leave it in a bad
state if it is not properly handled, not true?

It would be better then to parse it in one shot then. And set the
WARequest to be bad could be another option. The request handler can
then take care of a bad request.

>> Parsing the URL effectively comes down to handleFiltered: on
>> WADispatcher that will try to get the url via the consumer on the
>> request. If parsing it breaks, the request is marked as a bad request.
>> The dispatcher could pass to the default handler. The parsing errors
>> of the other parts of the request would then go to the handler
>> dispatched to. And that could in turn be dispatched to an error
>> handler.
>
> No, the URL is parsed in WAServerAdaptor >> #requestUrlFor:

I meant that if we delay the parsing, #requestUrlFor: would be sent at
a later stage.
_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: bad request

Philippe Marschall
On Sun, Dec 29, 2013 at 8:26 AM, Otto Behrens <[hidden email]> wrote:

>>> This is my best conclusion - please comment:
>>> For someone providing a web application, the server implementer can either
>>> 1) be strict respond with 400 (bad request) if it finds something it
>>> dislikes in the request (either the http method + URL, headers or
>>> body),
>>> or 2) ignore inappropriate parts of the request. Of course, some parts
>>> of the request can't be ignored, so one will have to distinguish
>>> carefully.
>>
>> I generally prefer option 1) because this way when something goes
>> wrong on the server the client gets notified. Otherwise client errors
>> can be really annoying to debug.
>
> Yes, agree. I could not find "invalid cookie" kind of responses when
> searching for how others solve this kind of problem though. Having
> said this, I'd also rather respond with 'bad request' if I find
> anything I don't like in the request.
>
> I suppose we also have to distinguish between unable to parse the
> cookie header and an unexpected key or value in the cookie header. If
> the server receives a key that it does not recognise, should it
> respond with bad request?

No. Among other things it's hard to know in the adapter which cookies
the code later will accept.

>> process: aNativeRequest
>>     ^ [ self basicProcess ]
>>         on: self badRequestExceptionSet
>>         do: [ :e | self badRequestFor: e ]
>>
>> badRequestExceptionSet
>>   ^ GRInvalidUtf8Error, WAInvalidUrlSyntaxError
>>
>> badRequestFor: anError
>>   "default implementation, trigger the servers internal error handler
>>   sublcasses can answer a 'native' bad request (HTTP 400) respone"
>>   anError signal
>
> This means that every subclass of WAServerAdaptor have to implement a
> native bad request response. Is there an elegant (i.e. non monkey
> patched) way for me to customize this response?

Yes

> That's why I thought
> the seaside framework must handle it, because I can customise there.
>
>>> It seems if I want to handle any of these errors (consistently), I
>>> have to modify Comanche, Zinc and FastCGI adaptors.
>>
>> Yes
>
> Ok, would be soo nice if I can do it once in my application though
> (because I do it there already).
>
>>> I think we should allow the Seaside framework to handle these errors
>>> as well. I understand giving the WAResponse the responsibility to
>>> handle it can be tricky, but it may just be the right place.
>>> Currently, it does handle some of the 400 range of errors (eg. not
>>> found).
>>
>> WAResponse does not handle 400. Somebody somewhere creates a 400
>> response just like somebody somewhere creates a 200 response.
>
> Sorry, the request handler may create a WAResponse with code 400.
>
>>> This is my suggestion: Create the WARequestContext on the native
>>> request without parsing it.
>>
>> I'm not liking it. The propose of WARequestContext is that it holds on
>> to (among other things) a WARequest and a WAResponse. We just got an
>> exeption when trying to create a WARequest. This smells like having a
>> partially initialized object that will just cause other exceptions
>> further down the road.
>
> Yes, I share your discomfort. But, the same problem applies to the
> response. When creating the context, the response is empty. Exceptions
> raised during the construction of the response may leave it in a bad
> state if it is not properly handled, not true?

"it" meaning context or response

> It would be better then to parse it in one shot then. And set the
> WARequest to be bad could be another option. The request handler can
> then take care of a bad request.

That sounds better. It also addresses the issue of what happens when
the exception handler access the same header that signals an exception
or a different header that signals an exception as well. I guess you
could do the check in WARequestHandler >> #handle:. Would you extend
WAErrorHandler to have a #handleBadRequest: method or where would you
eventually handle it? Would be argument be the original exception, the
native request or the bad WARequest?

>>> Parsing the URL effectively comes down to handleFiltered: on
>>> WADispatcher that will try to get the url via the consumer on the
>>> request. If parsing it breaks, the request is marked as a bad request.
>>> The dispatcher could pass to the default handler. The parsing errors
>>> of the other parts of the request would then go to the handler
>>> dispatched to. And that could in turn be dispatched to an error
>>> handler.
>>
>> No, the URL is parsed in WAServerAdaptor >> #requestUrlFor:
>
> I meant that if we delay the parsing, #requestUrlFor: would be sent at
> a later stage.

Cheers
Philippe
_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside