-
Notifications
You must be signed in to change notification settings - Fork 368
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Treat posted data as multipart #285
Conversation
I don't think multipart is allowed per spec, or am I mistaken? |
The rfc6749 doesn't forbid it it just gives all examples in The 2^24 aka 16M limit is a bit high. Hm tests. Why the hell are they failing now. |
My guess is that tests are failing because the valid |
By the way, just do |
I changed this now to ignore the specific error (NotMultiart, just like request.FormValue does) will do. |
All tests except one now pass. And I have no Idea why the last one reports different error |
access_request_handler.go
Outdated
@@ -62,7 +62,7 @@ func (f *Fosite) NewAccessRequest(ctx context.Context, r *http.Request, session | |||
|
|||
if r.Method != "POST" { | |||
return accessRequest, errors.WithStack(ErrInvalidRequest.WithDebug("HTTP method is not POST")) | |||
} else if err := r.ParseForm(); err != nil { | |||
} else if err := r.ParseMultipartForm(2 ^ 24); err != nil && err != http.ErrNotMultipart { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ParseMultipartForm
does not parse anything except the content type multipart
, so the proper encoding has been replaced with multipart
as ParseForm
has been replaced and if the form is not multipart
, then the flow fails (so every oauth2 library out there will not be able to make any requests to this library any more :D ).
Parsing multipart should be a fallback, not the default!
Also, do we really need 16MB of data here? Smells like a possible DoS vulnerability!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've just seen this review. I've changed this to be 2^20 aka 1M. The other thing being
I don't know which version of go you are running but in 1.10 ParseMultipartForm first calls ParseForm and then it continues to do a multipart parse
Also in case you missed it. If you use the FormValue or PostFormValue of the request both of them call ParseMultipartForm with the default value of 32M!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've just seen this review. I've changed this to be 2^20 aka 1M.
Nice!
I don't know which version of go you are running but in 1.10 ParseMultipartForm first calls ParseForm and then it continues to do a multipart parse
I think the tests run Go 1.8. We should definitely make this bc compatible with older versions of Go!
Also in case you missed it. If you use the FormValue or PostFormValue of the request both of them call ParseMultipartForm with the default value of 32M!
I didn't know that. We are however only calling PostForm
which requires a prior ParseForm
(or it's nil). This led me to investigate though and it seems that ParseForm
reads up to 10MB, so also quite a lot (not 32M but still). So 1MB is definitely fine here, and 16MB was probably too! Parsing explicitly only 1MB is even better though!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've checked the source of request.go in 1.8 and it seems that the ParseMultipartForm code is the same and it also calls ParseForm
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ohh, I see, I didn't know that. I was looking at another line where multipart is ignored but apparently it's handled in the outer functions of that call. Thank you for clarifying that! Learned a ton about form parsing in this PR :)
Hm, I don't think we should allow this, see: https://tools.ietf.org/html/rfc6750#section-2.2 That explicitly enforces |
I don't agree as the last thing I want to do is maintain my own fork of the library. We have numerous copies of our software out and removing support for old versions is out of the question. |
Sorry, I linked to a spec that doesn't concern this PR, I'll check again to see if this may be allowed |
I'm still looking for hints in the specs as the are very vague. However, the big ones (like Google OAuth 2.0) are not forgiving when it comes to this parameter, see the docs. Usually, the issue you describe comes from using either outdated OAuth2 clients or self-written code that handles OAuth2. Both should (must) be changed in order to (a) have an OAuth2 compliant flow and (b) remove any potential security issues. Keep in mind that this is probably at the core of your authorization flow, so why rely on potentially insecure code? Second, you won't have to maintain your own fork. It's very easy to either write a middleware that encodes from I know that we're strict and that's the point this library is making. We don't want to compromise integrity, reliability, or security for 1% use cases. Having said that, I haven't explicitly decided if this should make it or not in the library. I'll see what other big OAuth2 Providers are doing and will try to find information on this in the specs. |
I checked the code and the failing test case is because |
So, I don't think there's actually anything speaking against adding this feature and I was not able to find a resource that would say otherwise. There's however still a failing test :| |
Yeah. But for that we would need to re-read the body. if body, _ := ioutil.ReadAll(r.Body); len(body) == 0 {
return accessRequest, errors.WithStack(ErrInvalidRequest.WithDebug("missing form body"))
}
// or
if body, _ :=ioutil.ReadAll(io.LimitReader(r.Body, 1)); len(body) == 0 {
return accessRequest, errors.WithStack(ErrInvalidRequest.WithDebug("missing form body"))
} |
Ugh, that sucks, especially because we actually can't re-read the body afaik, as the body is treated as a stream, unless |
…it to send form data
I've added this check only into the revoke and introspect handlers. |
Perfect, I'll take another look at this today and will merge if nothing else emerges. Thank you for your persistence and work! :) |
Use Multipart form parse function as some client implementations use it to send form data.
e.g All of our native clients which use CURL