-
-
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
Issue with realpath() and open_basedir() altogether #2707
Comments
FYI I also thought of just passing null to the |
Please read twigphp/Twig#2707 a.k.a. "C'est moche, mais ça marche." (TM)
Please read twigphp/Twig#2707 a.k.a. "C'est moche, mais ça marche." (TM)
If the root of your project is |
@stof I think you do not clearly understand open_basedir. The goal of open_basedir is to restrict PHP access. Say you have a project, with documentation directories, and other sensitive stuff, like the composer.json that could be considered sensitive stuff in an information disclosure issue. In case of any include security issue, or a php:filter issue, any attack where the application goal is hijacked to try to extract informations, the open_basedir is the last security. It prevents PHP access on stuff that should not be readable by PHP (the only other security on that is php user read access on OS level). So clearly the way of fixing issue related to open_basedir issues is not to allow all files to be read by PHP. That's the goal of open_basedir, you do not want PHP to be able to read these directories. If we take @pounard example you have the composer file, a subdirectory |
@regilero if the doc is sensible, the best solution would be to not deploy it at all IMO. This way, nothing can access it in case of an attack. And btw, restricting access to The |
@stof I don't want to be rude, but it's been many times that realpath() over-use in both Twig and Symfony caused us such trouble. Problem is that you force symbolic links resolution, which in certain (sometime many) conditions breaks the PHP open_basedir behavior (even when the looked-up folder being in open_basedir). In the last 2 or 3 years, got the exact same problem tens of times.
If you end up with ".." in your paths, there's probably another problem behind, the app using Twig should probably not use ".." but use correctly dirname() instead when necessary. That said, we cannot fix all applications in the world, but at least the realpath() usage could be changed to either:
In all cases, using realpath() so lightly is dangerous: it's not only about fixing the path, but has many many other implications:
I think in this issue case, using realpath() is a misuse of it. |
Let's calm down :) We are all trying to do our best trying to understands problems and finding the best appropriate solutions. Thank to @pounard for the great explanations and the thorough investigation. I really appreciate it as it makes my life much easier :) I think you are right when you say that In any case, I will try to work on this topic in the next few weeks to see what we can do to be more "compatible" with projects using |
@fabpot I'd be glad to help, since it's recurrent problem for us, I can easily test patches in affected projects, but I can also help patching, since I start to have quite some experience with realpath'ing and it's problems. |
…ts with open_basedir, strong path normalisation
I created a PR #2709 that illustrate a way to solve this, by avoiding all calls to realpath() replacing it by a normalizePath() method that does not check for file existence. This method carries also the benefit of having a stronger path normalisation and matching for schemed URI such as phar://... Please be nice, I didn't attempt to make the code fast, rather illustrate that it's easily possible to work around and prevent realpath() usage. Python os.path package carries two methods: abspath() and realpath() - the method I propose here would be like replacing realpath() by abspath(): does the path normalization, but does not enforce symlink resolution or file existence checks. EDIT: I made the PR for the 1.x branch, since at this time, I experience the problem with 1.x version, but it should be rather easy to port in 2.x. |
…ts with open_basedir, strong path normalisation
Please PR #2709 is ready for review. My |
Still no reviews or discussion about this ? |
Some quick comments (I still haven't had time to work on this a lot):
Reading some material, and from my own experience, we should keep in mind the following:
|
Reading the code, I'm wondering if we cannot "just" remove the |
Of course, I agree and understand this.
Having a realpath()'ed branch would keep backward compatiblity (and should probably be used by default until next major).
Indeed.
Actually the OS does the real resolution, so normalizing the path as I do should not break anything. Calling realpath() on the normalized path should give the exact same result than on the non-normalized one, that's the beauty of it: normalization canonicalises the aliased path without resolving symlinks, but once you will really load the file, later during rendering or compiling, the OS will transparently resolve the symlinks without having us to care about. In two words: if it succeeds in realpath'ing the file, it will also resolve it transparently on file load the exact same way.
That needs testing, I should add Windows paths in the unit tests.
Actual implementation should be fast, I think. Good thing is the time it looses for normalization, in theory, should be compensated by the fact it does less I/O's, and does not ask the OS and FS to do a symlink resolution. Once everything is in place and cached properly, it will not resolve anything anymore (at least it should not). |
That would be a very nice first step! It still can possibly have side effects if I recall from when I was working on this subject. Need help to do a PR? |
A PR for this very first step would be really nice. Bonus if you can add some tests proving that it works well with open_basedir. |
I always love to place a good quote. Joke aside, I'll try to manage some spare time next week to do this. Thanks again for answering. |
wouldn't that break things in places computing the path relative to the root (to create cache keys) if the root was involving a symlink ? |
…ts with open_basedir, strong path normalisation
…ts with open_basedir, strong path normalisation
This issue is a reddit of #2387 which is probably experiencing a side effect of the same bug.
Context is, I am developping against Symfony 3.4 with some application. Our admins, which are sometime (maybe too much) paranoid always do set
open_basedir
PHP directive, on a per-project basis, in order to avoid PHP breaking out its rightful scope.Ou application uses Symfony's 3 style (not Symfony 4-flex style) so we have the following folders in our directory structure:
/srv/http/someproject/app/Resources/views
/srv/http/someproject/composer.json
/srv/http/someproject/var/cache
Problem here lies in the
\Twig_Loader_Filesystem::__construct()
, which does the following:Since we have
open_basedir
restriction over the project, which basically is set to this (and a few more folders that show no interest in being here):/srv/http/someproject/app:/srv/http/someproject/var/cache
, this means that when\Twig_Loader_Filesystem::__construct()
is called with the$rootPath
parameter set to/srv/http/someproject/
, it tries arealpath()
call outside of the allowedopen_basedir
folders.So I have here a major problem, because it's hardcoded, hence our sysadmins can't enforce a proper security sandbox for the projets.
I also a real question, the
\Twig_Loader_Filesystem::$rootPath
property behing private, and having no public accessor, this means that it has never been meant to be used outside of a few very specific use cases I spotted:in
addPath()
andprependPath()
it serves the purpose of ensuring that all paths are absolute (heck, why not) - but in real life, in Symfony's use case, we do always end up with path already being absolute (so there is no purpose in that),in
getCacheKey()
having an absolute path seems to make the cache key even more unique, so okay, why not, it makes sense,in
findTemplate()
it serves the purpose of absoluting each registered template path, which seems a duplicate of doing it withinaddPäth()
and therefore is always a no-op (I think it could be removed, also it would potentially be a minor BC break under very peculiar conditions, but not in Symfony as I recall).Are those
realpath()
really necessary ?In my situation, I can see two solutions to fix this:
a quick fix is to simple remove the
realpath()
call in the constructor, and from this, I can a see a single an only one potential side effect: if your CLI and your HTTPd don't see the same path (for example, if the HTTPd context is chrooted and the CLI context is not) it will create different cache keys for both. This by extension would mean that warming template caches from CLI would not be possible anymore.or a better one, add an optional
$noRealpath
constructor argument, which would turn to be a micro optimization for Symfony's framework, that in our case seems to feed the loader with only absolute paths from the begining (making thoserealpath()
calls always being obsolete).In all cases, in the current state of things, twig prevents sysadmins from correctly securing/sandboxing their PHP applications, and that's bad.
The text was updated successfully, but these errors were encountered: