Skip to content
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

Prevent OpenURI redirection & private hosts during API image upload #3593

Conversation

calebhaye
Copy link
Contributor

@calebhaye calebhaye commented Apr 22, 2020

Description
Paperclip’s CVE-2017–0889 Server Side Request Forgery (SSRF)
vulnerability (https://medium.com/in-the-weeds/all-about-paperclips-cve-2017-0889-server-side-request-forgery-ssrf-vulnerability-8cb2b1c96fe8) was likely introduced in our attempts to allow API image uploads via URL. This patch ensures that redirection does not take place in the context of
uploading an image via the api. It also does a check to make sure the IP/host aren't private. Lastly, it uses VCR to stub out the http requests for images.

Ref #3573

Checklist:

  • I have followed Pull Request guidelines
  • I have added a detailed description into each commit message
  • I have updated Guides and README accordingly to this change (if needed)
  • I have added tests to cover this change (if needed)
  • I have attached screenshots to this PR for visual changes (if needed)

@calebhaye calebhaye force-pushed the prevent-openuri-redirect-for-api-upload-by-url branch 2 times, most recently from 64228ac to 348f8c1 Compare April 22, 2020 18:27
Copy link
Member

@jarednorman jarednorman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took a quick look at the CVE and this seems like a good fix to me.

@aldesantis
Copy link
Member

aldesantis commented Apr 24, 2020

@calebhaye correct me if I'm wrong, but we still need to ensure the user cannot pass a private IP as the hostname, is that right?

Also, would it be possible to stub the HTTP requests with VCR? That way we're not calling live URLs in our tests, which may easily break/fail randomly.

Paperclip’s CVE-2017–0889 Server Side Request Forgery (SSRF)
vulnerability (https://medium.com/in-the-weeds/all-about-paperclips-cve-2017-0889-server-side-request-forgery-ssrf-vulnerability-8cb2b1c96fe8) was likely introduced in solidusio#3573.  This patch
ensures that redirection does not take place in the context of
uploading an image via the api, and ensures that a private address
is not used for the attachment parameter.
@calebhaye calebhaye force-pushed the prevent-openuri-redirect-for-api-upload-by-url branch from 348f8c1 to c4dfa2a Compare April 24, 2020 10:08
@calebhaye calebhaye changed the title Prevent OpenURI redirection during API image upload Prevent OpenURI redirection & private hosts during API image upload Apr 24, 2020
@calebhaye
Copy link
Contributor Author

@calebhaye correct me if I'm wrong, but we still need to ensure the user cannot pass a private IP as the hostname, is that right?

Thanks @aldesantis, I added a private IP/host check.

Also, would it be possible to stub the HTTP requests with VCR? That way we're not calling live URLs in our tests, which may easily break/fail randomly.

I also added VCR, but I left it as a separate commit, for now. Of course, if we're happy with the implementation I'll squash the commits and we can merge. But if we decide for some reason that VCR isn't the way we want to go, rebasing out the commit will be easy.

Thank you for your comment, I'm looking forward to hearing your feedback.

@calebhaye calebhaye force-pushed the prevent-openuri-redirect-for-api-upload-by-url branch from 62d3e39 to 66d53f9 Compare April 24, 2020 18:46
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require 'spec_helper'
require "private_address_check/tcpsocket_ext"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious why this is needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the code that contains the error that will be raised, and that the spec tests for.

The gem itself seems pretty simple, and we could just copy or fork it, but it has undergone some review, so I figured maybe it's worth keeping. I'm open to a better solution, if anyone has any ideas.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could require it only in the sole spec where it was needed

@@ -1,5 +1,7 @@
# frozen_string_literal: true

require 'private_address_check'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should either add this to the gemspec or only require it when the attachment is a URI, making the functionality and dependency optional.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I felt like I might be doing this wrong. Any advice on a proper implementation is welcomed. For now I'll do your latter suggestion.

@aldesantis
Copy link
Member

@calebhaye left a couple of comments, thanks!

@kennyadsl
Copy link
Member

I'm starting to think this shouldn't be handled by Solidus. What about keeping URL upload disabled and allow enabling it with a preference? As far as I got, it's just a matter of adding Paperclip::UriAdapter in a Rails initializer, as suggested here: https://github.com/thoughtbot/paperclip#io-adapters.

It may sound drastic but, what about reverting the code in the controller and just adding some documentation on how to enable this adapter in Paperclip?

Another thing that I prefer not to do is adding code specific for Paperclip which is deprecated and we are trying to slowly replace with ActiveStorage.

What are your thoughts about this?

@aldesantis
Copy link
Member

@kennyadsl my 2 cents: I like the feature and would like to keep it for the time being, and I think we could easily replicate it with ActiveStorage when the time comes.

With that said, it would probably be a good idea to make the behavior optional by adding a configuration option, so that the user is fully aware of the security implications and we are not potentially slipping a vulnerability into the codebase without them knowing.

@calebhaye
Copy link
Contributor Author

@kennyadsl @aldesantis

Honestly, I have mixed feelings about it. I'm obviously biased because a) I wrote the code, and b) it serves the needs of my business, but beyond my selfishness there may be a valid reason for keeping the feature in place.

I guess one relevant question would be can anyone show me an example of the image api working without the feature in place? I wasn't able to get it to work, there is no documentation on it, and when I asked the Slack channel no one was able to give me an example there either. My point is, proving that the alternative works and providing docs for that would be a good place to start.

Beyond that, I think we should consider non-ruby devs who want to use Solidus. Having this feature work out of the box without having to write a Rails initializer might be a good thing.

That being said, I think it is easy enough to write an initializer to get this sort of functionality, but honestly if I had, I probably would have exposed my app to vulnerabilities. Having the group-think we've had around these implementations and making a decision in the best interest of the end-user seems like the responsible thing to do.

@calebhaye calebhaye force-pushed the prevent-openuri-redirect-for-api-upload-by-url branch from af5c450 to 9a72d19 Compare April 28, 2020 16:35
@kennyadsl
Copy link
Member

We discussed this via DM on Slack and we considered closing this and reverting the other PR that introduces this security concern (#3573).

The API image upload is working, we tried with:

curl -v -H "Content-Type: multipart/form-data" -H "Authorization: Bearer your_token" -i -F image[attachment]=@test_image.png http://localhost:3000/api/products/1/images

and the image is uploaded correctly.

Anyway, we agreed that we should improve the documentation around this with the following:

  • Add a better description in our API documentation for the endpoints that require "Content-Type: multipart/form-data".
  • Explain how to configure your app to allow other types of upload, like uploading via URLs (for paperclip we can link https://github.com/thoughtbot/paperclip/#io-adapters).

@calebhaye
Copy link
Contributor Author

I personally still think we should keep it, but only enable it with a config flag. Just so that others don't introduce security vulnerabilities when they try to add the adapter as per the paperclip docs you referenced, and so we don't waste the thought we've put into this thus far. Showing how to do something safely seems like the best approach, plus we get a handy feature that many developers will use, and it doesn't require writing a custom adapter

@kennyadsl what do you think of doing that, rather than throwing away all the code and a feature that is arguably valuable?

@aldesantis
Copy link
Member

@calebhaye how about extracting this into an extension? It should be fairly easy to do and would solve a lot of problems: users would have to explicitly install the extension, so they'd know the security implications of the feature, but they'd still be able to benefit from all the work and thought that went into the feature.

@calebhaye
Copy link
Contributor Author

@calebhaye how about extracting this into an extension? It should be fairly easy to do and would solve a lot of problems: users would have to explicitly install the extension, so they'd know the security implications of the feature, but they'd still be able to benefit from all the work and thought that went into the feature.

Sounds good! I'll do that. Closing this now.

@calebhaye calebhaye closed this May 11, 2020
kennyadsl added a commit to nebulab/solidus that referenced this pull request May 13, 2020
This reverts commit 4a1824a.

This commit potentially introduces a security vulnerabilty,
(CVE-2017–0889) as described here:

https://medium.com/in-the-weeds/all-about-paperclips-cve-2017-0889-server-side-request-forgery-ssrf-vulnerability-8cb2b1c96fe8

as kindly reported and described by this PR author in solidusio#3593.

Also, this PR has been introduced because there wasn't a clear way to
upload images via API, but this can be done by setting the right
Content-Type header in the request, as follow:

curl -v -H "Content-Type: multipart/form-data" -H "Authorization: Bearer YOUR_TOKEN" http://your.host/api/products/1
kennyadsl added a commit to nebulab/solidus that referenced this pull request May 13, 2020
This reverts commit 4a1824a.

This commit potentially introduces a security vulnerabilty,
(CVE-2017–0889) as described here:

https://medium.com/in-the-weeds/all-about-paperclips-cve-2017-0889-server-side-request-forgery-ssrf-vulnerability-8cb2b1c96fe8

as kindly reported and described by this PR author in solidusio#3593.

Also, this PR has been introduced because there wasn't a clear way to
upload images via API, but this can be done by setting the right
Content-Type header in the request, as follow:

curl -v -H "Content-Type: multipart/form-data" -H "Authorization: Bearer YOUR_TOKEN" http://your.host/api/products/1
mamhoff pushed a commit to mamhoff/solidus that referenced this pull request Feb 1, 2021
This reverts commit 4a1824a.

This commit potentially introduces a security vulnerabilty,
(CVE-2017–0889) as described here:

https://medium.com/in-the-weeds/all-about-paperclips-cve-2017-0889-server-side-request-forgery-ssrf-vulnerability-8cb2b1c96fe8

as kindly reported and described by this PR author in solidusio#3593.

Also, this PR has been introduced because there wasn't a clear way to
upload images via API, but this can be done by setting the right
Content-Type header in the request, as follow:

curl -v -H "Content-Type: multipart/form-data" -H "Authorization: Bearer YOUR_TOKEN" http://your.host/api/products/1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants