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

Add static files server #9294

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open

Conversation

alecpl
Copy link
Member

@alecpl alecpl commented Dec 31, 2023

In an attempt to improve an overall security of Roundcube installation related to the fact that people aren't using our public_html folder, I prepared an initial implementation of a static files server.

The idea is that we do not allow direct access to static resources at all. I.e. you must use the public_html as your root
folder, and that folder will contain only two files: index.php and static.php (and maybe .htaccess).

It also solves problems people have with the links (skins and plugins) in public_html folder.

I'm interested in your opinion. Please, note it's not a complete solution. We'd have to:

  • make it working with use_secure_urls feature,
  • make it working with assets_path feature,
  • get rid of assets_dir, as it won't be needed anymore,
  • move .htaccess and index.php into the public_html folder.

Let me know what do you think.

Reference: #8851, #5738.

@Neustradamus
Copy link

Nice PR!

@alecpl
Copy link
Member Author

alecpl commented Jan 21, 2024

@johndoh @mvorisek @EdouardVanbelle @cmollekopf what do you think?

@mvorisek
Copy link
Contributor

a) .htaccess can solve any security issue as long as no dynamic ACL based on like the logger user is needed. .htaccess is supported more or less by Apache only.

b) On Windows, symlinks are very mildly supported and even on NTFS they are not usually extracted (by common archive utilities) from the release archvives.

c) It will add more load to the webserver as the static content requests will have to go thru PHP, but it seems like caching is implemented so this should not be an issue, actually it can improve performance on webservers with wrongly configured caching.

To sum this up:

Given a) this PR helpful for non-Apache based webservers like nginx (with non-ignoreable marker share).

Given a) and c) this PR should be not the default/only static files routing solution when .htaccess is supported.

Given b), this PR is needed (for restricting access to all files). All symlinks can/should be removed then.

People are lazy and how many of them configure public_html as output dir at all? If this PR should solve all file access issues, it would make sense to add a runtime check if .htaccess is supported (ie. if served thru Apache) or if accessed thru public_html/*.php. If satisfied, we are safe. If not, we should inform the user the installation can be insecure by default. User (administrator) should still be able to disable this check, as he might want to mimic the .htaccess by a custom webserver config.

@alecpl
Copy link
Member Author

alecpl commented Jan 21, 2024

The point is to remove current ./index.php file and have public_html/index.php file so admins are forced to use public_html as the entry point (it won't be optional as it is now). And after that there might be only one .htaccess file, in public_html, or none.

@mvorisek
Copy link
Contributor

Inexperienced users should not be forced to change their webserver route to public_html and experienced users should be allowed to host Roundcube in a subfolder.

So there needs to a be .htaccess in the root.

index.php in the root removed (or kept with some simple info) can effectively act as the "runtime check", as either .htaccess in the root will be honored or the request was made thru public_html.

The problem of serving static files and securing other files is not related to this repo only. I would prefer some solution using separate repo. Maybe there is some package which solves it well already.

@johndoh
Copy link
Contributor

johndoh commented Jan 21, 2024

I second @mvorisek's thoughts about Windows. If there are any contributors who run a Windows bassed setups may be they could comment?

If index.php is removed from the root then people have to setup public_html as the root, right? May be adding some security checks into the installer, to make sure thing like the logs are not readable by the client, would also help people secure their setups?

If file type is not on the list it will have to be served by custom code in your plugin.

I tried serving a non-supported file from a test plugin. Its a very rough test but if you have $this->include_script($this->local_skin_path() . '/foo.bar'); in your plugin that result still has static.php in it but then fails because static.php does not support .bar files and plugins can't interact with it.

Small thing but str_starts_with() is PHP8 only.

@alecpl
Copy link
Member Author

alecpl commented Jan 25, 2024

We could make use of https://github.com/Stadly/FileWaiter. I didn't find other library that isn't part of some big framework.

I really see no problem in forcing users to use public_html.

As for performance, I think it will be good enough. Users that require something really fast can setup a separate static assets server, I suppose.

Regarding Windows and links. The only problem (link) would be the installer. I suppose we could provide install.php instead of a link.

@melroy89
Copy link

melroy89 commented Feb 7, 2024

I do want to use public_html already, but the resources like the skins will no longer load. Example: https://mail.melroy.org/

Changing the document root back to the actual root (without public_html) will load all the static files correctly. What do I wrong today? I understand why people won't use public_html today even without this PR...

Ps. the guide told me to use the normal root first during the installation, and after the installation change the root. Which I did now.

EDIT: Yes, I use Nginx not Apache. I did already add the additional security steps to Nginx (I was hoping no more sections where needed to get public_html working with Nginx), snippet:

    location ~ ^/(README.md|INSTALL|LICENSE|CHANGELOG|UPGRADING)$ {
         deny all;
    }

    location ~ ^/(bin|SQL|config|temp|logs)/ {
         deny all;
    }

@melroy89
Copy link

melroy89 commented Feb 7, 2024

I do want to use public_html already, but the resources like the skins will no longer load. Example: https://mail.melroy.org/

Changing the document root back to the actual root (without public_html) will load all the static files correctly. What do I wrong today? I understand why people won't use public_html today even without this PR...

Ps. the guide told me to use the normal root first during the installation, and after the installation change the root. Which I did now.

EDIT: Yes, I use Nginx not Apache. I did already add the additional security steps to Nginx (I was hoping no more sections where needed to get public_html working with Nginx), snippet:

    location ~ ^/(README.md|INSTALL|LICENSE|CHANGELOG|UPGRADING)$ {
         deny all;
    }

    location ~ ^/(bin|SQL|config|temp|logs)/ {
         deny all;
    }

I found it.. The wiki guide told me to use FTP (eg. FileZilla) to copy the data to the server, but it seems like it's not copying the symlinks from public_html !

@melroy89
Copy link

melroy89 commented Nov 10, 2024

I found it.. The wiki guide told me to use FTP (eg. FileZilla) to copy the data to the server, but it seems like it's not copying the symlinks from public_html !

Please be sure to update the documention wiki page with some additional information that copying those files via sftp will not copy symlinks. Or either describe a better installation method instead..?

Comment on lines 440 to 444
if (!function_exists('str_starts_with')) {
function str_starts_with(string $haystack, string $needle) {
return strlen($needle) === 0 || strpos($haystack, $needle) === 0;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

https://github.com/atk4/core/blob/5.2.0/composer.json#L35-L38 would be better solution as installed dependencies are required in all cases

Copy link
Member Author

Choose a reason for hiding this comment

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

You're right. Anyway, we should consider bumping PHP version requirement to 8.1 for the next Roundcube version, especially if it will be a bump to 2.0.

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