-
-
Notifications
You must be signed in to change notification settings - Fork 4.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
matcher: Add split_path
option to file matcher; used in php_fastcgi
#3302
Conversation
@mholt I'll let you pick the milestone, not sure when you think this should go in. |
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.
This looks good! Nice work, thanks.
Do you think we need the case-insensitivity? Are there cases where case-sensitive split is useful?
I kept that mostly to match the reverse_proxy behaviour. I figure if a request to |
I'd be willing to merge this in before 2.0 if the original reporters of the bug confirm that it works for them. |
We had some issues in 1 around split_path for php files and incorrect matches. do you think there is any possibility this will suffer from similar issues. eg. Would it be possible to upload a file myhackfile.php.txt and have it executed as myhackfile.php? This would obviously be a security issue. |
No, because But, this does mean this change would break requests to files that have Hmm. Should we only return the split path if the next character after the split is |
Okay I tried adding this bit just before the return in the loop: // skip the split if it's not the final part of the filename
if pos != len(path) && ! strings.HasPrefix(path[pos:], "/") {
continue
} Caddyfile:
Tree:
Tests:
With that change, as you can see, it allows direct requests to Edit: regarding "or if the file is followed by |
In other news, we got word from the user on the forums that this change fixed the problem for them with NextCloud: https://caddy.community/t/help-to-migrate-caddyfile-v1-to-v2-for-nextcloud/7647/25?u=francislavoie |
5af33db
to
8ad1c6a
Compare
Are untrusted users ever able to upload directories?
^ that test, if a user uploads a file in a directory like |
At that point it's not Caddy's problem, it's the app's. If they allow things like that, then it's an insecure app. I don't think we need to worry about it. |
Not that I disagree with you, but, allow me to play devil's advocate here, since I know we will get complainers if we don't drill down ahead of them: is there a reason that is the app's fault but not allowing file uploads with filename like |
I added a file as described on disk:
And tried requesting it (same Caddyfile as above):
It does serve the file as-is. This is because after stripping (i.e. Also to note, here is the matcher in the Caddyfile above vs what is now generated by the
Then tried with this Caddyfile (PHP 7.4), each file just has their own filename in it:
Tests
You'll note that You'll also note that Debug logs for
I think we're safe here, I don't see any issues. I still want @whitestrake's input though! |
Okay sorry about that - I edited the comment above, I made a booboo and I ran all of that under the wrong code 🤦♂️ |
Hey @sarge I wouldn't mind your help on this one to add matcher tests similarly to those |
Don't mind the change to |
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.
^ that test, if a user uploads a file in a directory like myhackfile.php.txt/index.php, would a request to /myhackfile.php.txt invoke the index.php file within it?
I believe this is already a problem and beyond Caddy's scope.
The name of the directory beneath it doesn't matter. If someone can upload index.php
to any webdir, and call that directory to get its index, whoever allowed that upload has failed to secure their server and application. It has nothing to do on whether we split on .php
or not.
Re: where is the line between app and Caddy's responsibility? I propose that line should be drawn exactly where the function is that allows uploads in the first place, and Caddy's PHP/FastCGI functionality is not strictly providing the upload capability. In almost all cases, I expect that upload to be conceptually out of band, processed by completely different code beyond Caddy's control or concern.
It's not Caddy's responsibility to decide, once a file is already on disk, which files should be allowed to be executed as PHP. That responsibility comes down to the person who arranged/allowed for the files to be there; usually either the app maintainer or the server administrator.
Trying to use that line gets blurry, I suppose, if we talk about introducing functionality like WebDAV etc. built into Caddy. But I think there's an expectation that those kinds of things should be authenticated first... Combining free upload with PHP execution is something that must be voluntarily done by the server administrator. Those are powerful tools and a possible footgun, but without getting potentially crazy heuristics involved, I don't think we can or should check or aim to prevent this - that's the point I think you gotta say it's on the guy configuring things.
My only concern at a glance here is that a legitimate request to a file with .php
somewhere in the middle of the file name will be returned to index inappropriately. But in your firstSplit
function you already check that the .php
must be at the end of the path element / file name. So I'm happy with that.
After looking over this, it seems I can't think of any other way to exploit it, hence the approval. As a disclaimer, though - my lack of imagination shouldn't be taken as authority on what is possible, heh.
Perfect! Thanks @whitestrake that's essentially what I expected to hear 😄 Just wanted someone to check my sanity here ❤️ |
6e0232a
to
54e02bb
Compare
Bah, I hate that Github dismisses reviews after rebasing... but I rebased. This is ready to go @mholt. |
I think I can turn the auto-dismissal off, but I specifically want it on for PRs to the master branch to make sure something doesn't slip in too easily. No worries. |
Discussion: https://caddy.community/t/help-to-migrate-caddyfile-v1-to-v2-for-nextcloud/7647/18
A common pattern in PHP apps is to have a PHP file that acts as a router entrypoint to the application. This is typically the
index.php
file at the webroot or some other subpath of the application. These entrypoints typically accept requests that have a path appended to the filename, for example/index.php/blog/123
.Some PHP apps happen to have more than one router entrypoint, for example,
/router.php/some/path
, in addition to theindex.php
file. NextCloud is one of those applications; it hasremote.php
,public.php
and more that act as entrypoints.With the default
php_fastcgi
Caddyfile directive, many of those pages didn't work correctly in NextCloud. The problem has to do with thetry_files
matcher and rewrite that is included as part of thephp_fastcgi
shortcut:The issue is that on a request to the path
/remote.php/dav/files
, Caddy would check if that exact path exists as a file on disk (i.e. the first argument,{path}
), but this doesn't work because there's extra stuff after the actual filename.We already have an option in the reverse_proxy's fastcgi transport to allow splitting the path into two parts, with the left-hand side being the filename (including the split value), and the right-hand side being the path, i.e.
split .php
.The fix we landed on for this issue is to add a new
split
option to the file matcher (split_path
in JSON) that allows for splitting the path the same way, before testing if the file exists on disk. It looks like this:So now for a request to
/remote.php/dav/files
, Caddy will instead look for/remote.php
on disk while matching.The
php_fastcgi
shortcut is also updated to internally add this new split option for itstry_files
matcher. This should not be a breaking change, because we assume that any path that involved.php
in the middle of it was assumed to be the filename boundary, but this wasn't working as expected.