-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Validates response processed by exception handler #1776
Validates response processed by exception handler #1776
Conversation
52e9dea
to
f38213e
Compare
If block of return nil, the response would be nil. That causes system information leak. Add a validation to prevent it.
f38213e
to
9e945a6
Compare
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.
Looks legit, see my questions/requests below. Thanks.
CHANGELOG.md
Outdated
@@ -21,6 +21,7 @@ | |||
* [#1758](https://github.com/ruby-grape/grape/pull/1758): Fix expanding load_path in gemspec - [@2maz](https://github.com/2maz). | |||
* [#1765](https://github.com/ruby-grape/grape/pull/1765): Use 415 when request body is of an unsupported media type - [@jdmurphy](https://github.com/jdmurphy). | |||
* [#1771](https://github.com/ruby-grape/grape/pull/1771): Fix param aliases with 'given' blocks - [@jereynolds](https://github.com/jereynolds). | |||
* [#1776](https://github.com/ruby-grape/grape/pull/1776): Validates response processed by exception handler - [@darren987469](https://github.com/darren987469). |
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.
We released 1.1.0, so this belongs in the next release above.
lib/grape/middleware/error.rb
Outdated
valid_response?(response) ? response : error!('Internal Server Error(Invalid Response)') | ||
end | ||
|
||
def valid_response?(response) |
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.
Do we do anything similar elsewhere? Seems a bit fishy, possibly belongs in Rack (maybe there's a method somewhere to check that the response is valid)?
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.
After searching, I don't find anything similar.
I know this is a bad smell. The better solution is let exception handler return a Rack:: Response
object, rather than an array (currently returned by Rack::Response.new.finish
). Then we can check whether the handler return Rack:: Response
object. However, that break the existing behavior and needs a lot of corresponding changes not only for grape but also for users of grape.
What do you think? @dblock
lib/grape/middleware/error.rb
Outdated
@@ -127,7 +127,13 @@ def run_rescue_handler(handler, error) | |||
handler = public_method(handler) | |||
end | |||
|
|||
handler.arity.zero? ? instance_exec(&handler) : instance_exec(error, &handler) | |||
response = handler.arity.zero? ? instance_exec(&handler) : instance_exec(error, &handler) | |||
valid_response?(response) ? response : error!('Internal Server Error(Invalid Response)') |
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.
Should we re-raise the original error instead?
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.
Sounds good. I will change the code to use default_rescue_handler to handle the original error. That means, if custom handlers failed to do their job (return valid response), default_rescue_handler will handle it.
a1d7bee
to
bbb20ca
Compare
bbb20ca
to
429295f
Compare
Looking at this more carefully, do we really want this behavior? The problem I see is that with this change we allow any kind of response from The current documentation doesn't document what |
Would love some second opinion, maybe @namusyaka? |
The problem stated in #1757 is: if Indeed, add documentation to tell what should be returned in Another way I have come up is: if In summary, I think we should do two things:
|
I totally agree that this is an important problem. Lets fix it. Does anyone actually expect to get a response from Are we breaking any existing specs if we start ignoring the response from |
@dblock I’m not sure if I get what you mean.
Do you mean if we start ignoring what returned from |
I think "yes". I am reading the spec and it says |
I add documentation to suggest developers call What do you think about this version? |
add9989
to
96d3138
Compare
This feels too complicated to me, I feel like your previous version may have been better. Re-reading README we say The I totally understand that we have been going back and forth on this. I can try the above as an alternate PR if you're tired of me ;) |
@dblock What is the behavior you image if the response from |
I think as is the code works well. If the response inside a rescue handler is garbage I expect unexpected things to happen :) What happens when you throw an exception from a rescue handler? That can always happen and I think we should explain the behavior and make it predictable in both README and specs. Try to write an UPGRADING to catch any changes users may beed to do to handle the changes? I'm worried (unnecessarily?) about those @namusyaka I could use some help with another pair of eyes here |
Changes:
@dblock I use version 1.1.1 as next version since this is a fix in a security issue. But this PR also break grape usage. What do you think? For your concern about the removal of |
Looks good. I'll edit the language in UPGRADING a bit, but for now lets just wait for another maintainer to take a look in case I missed something, hopefully soon. |
Sorry for the late response. @darren987469 You removed In many cases, the change won't be no matter. I'm not saying that this change is bad. |
@namusyaka Thanks for your response. Your are right, my referrenced block is not actually used for returning HTTP response. After digging more, I think it is ok to remove .finish method: response = Rack::Response.new('body', 200)
status, body, headers = response The code above announces a Since grape uses Current documentation says we should return |
@darren987469 That makes a lot of sense, lets try to |
@dblock There is no more require 'bundler/inline'
gemfile do
source 'https://rubygems.org'
gem 'rack'
gem 'rspec'
end
require 'rack'
require 'rspec/autorun'
RSpec.describe Rack::Response do
it 'calls to_ary when doing assignment' do
response = Rack::Response.new('body', 200)
expect(response).to receive(:to_ary)
status, headers, body = response
end
it 'call finish when doing assignment' do
# mock finish method
Rack::Response.class_eval do
def finish(&block)
[1, 2, 3]
end
alias to_ary finish
end
response = Rack::Response.new('body', 200)
status, headers, body = response
expect(status).to eq 1
expect(headers).to eq 2
expect(body).to eq 3
end
end
# Rack::Response
# calls to_ary when doing assignment
# call finish when doing assignment
# Finished in 0.00745 seconds (files took 0.10826 seconds to load)
# 2 examples, 0 failures |
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.
Looks good to me
Closed via c117bff. Thanks @darren987469! |
@dblock @namusyaka Thank you, too! |
Try to fix #1757.
Problem
The
rescue_from
block return nil, that cause response likeResponse exposes the system information.
After PR
Response would like
Not sure the message is proper or not.