Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

[WIP][RFC] Signed internal uris #6463

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

Closed
wants to merge 4 commits into from

Conversation

asm89
Copy link
Contributor

@asm89 asm89 commented Dec 22, 2012

Recently a security issue with the _internal uris of the FrameworkBundle led to the removal of the ability to directly render partials with controller actions, e.g. {% render 'BlogBundle:Post:list' with { 'limit': 2} %}. For me, people around me and probably other developers this mechanism was a big plus of Symfony2, because it was very easy to enable rendering these partials as standalone and get all the nice features of Varnish/esi.

With this pull request I propose to revert to the "old" render behavior, but only remove the /_internal_public route and secure the /_internal route by signing the url. The implementation in this PR is far from finished, but I'm looking for comments.

The complete removal of the feature should not have happened in my opinion, because not everyone relies on solely the routing firewall for security (annotations/aop, access checks in controllers, etc). Furthermore, if you do not use ESI, _internal uris will never be generated! Finally there are also other ways to make sure that _internal urls are only requested by your reverse proxy (e.g. Varnish) and are not accessible for the outside world.

There is also a POC by @fabpot that will allow for different rendering strategies if merged (#6459). The signed urls could also be a separate rendering strategy, but then it would still be useful to be able to do things like {% render 'BlogBundle:...%}.

@vicb
Copy link
Contributor

vicb commented Dec 22, 2012

@asm89 looks like a good concept. You should improve you PR comment and code.

What about HInclude, it seems the code has been removed ? (I think I understand but the reason why butit should be mentionned in your post)

Furthermore, if you do not use ESI, _internal uris will never be generated!

Wrong, HInclude. And we don't really care if they are generated or not. The important thing is whether they are routed or not.

Finally there are also other ways to make sure that _internal urls are only requested by your reverse proxy (e.g. Varnish) and are not accessible for the outside world.

Not everybody use a RP & HInclude must be accessible to the outside world.

And one last but important q, why would using a controller be better than using a path ?

@lsmith77
Copy link
Contributor

@vicb the main point is ease of use. that being said, i doubt that @asm89 would be working on this feature if he wouldn't be concerned about legacy code.

@vicb
Copy link
Contributor

vicb commented Dec 23, 2012

@lsmith77 I don't really get your point here. @asm89 asks for feedback and I give some.
ease of use ? Using a named route should be as easy as using a controller name.

@lsmith77
Copy link
Contributor

@vicb: i was replying to the question "And one last but important q, why would using a controller be better than using a path ?" not having to define a route is easier than having to define one, at least initially because is one required step less, since often render calls are to controllers that are otherwise not supposed to be accessible .. there are of course plenty of cases where using a route is better and more flexible.

@vicb
Copy link
Contributor

vicb commented Dec 23, 2012

Ok, thanks for clarification. In fact I'd like to know if asm89 as any other reason in mind (ie something we would have missed)

@weaverryan
Copy link
Member

Hiya guys!

I'm also interested in this, for the same as @lsmith77 mentioned - usability, i.e. not needing to create+secure a route that's only used for a non-standalone render. That's especially important for developers that don't use ESI or HInclude, but just come across features that require them to need to render another controller.

I don't care as much about the implementation - I would be ok with or without needing to create routes to use ESI/HInclude, as long as you didn't need to create (and secure) a route to use a non-standalone render.

The internal URL stuff is convenient for people using ESI/HInclude, but it's also a bit magical, requires some extra "teaching" for people to understand how it works. In that way, I don't mind the route for those cases.

Thanks!

list($service, $method) = explode(':', $controller, 2);
$class = get_class($this->container->get($service));

if (!preg_match('/Controller$/', $class)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I know this is the convention, but why must it be a hard requirement? (Maybe it already is in full stack, not sure.)

Copy link
Member

Choose a reason for hiding this comment

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

Using direct controllers is not supported at all in 2.2. This change allows to limit the security issue by allowing to execute code only in controllers (as this feature cannot be removed in maintenance release)

@Crell
Copy link
Contributor

Crell commented Dec 27, 2012

From a Drupal perspective, the most important usability factor is not having to manually create additional routes for each thing that you could non-subrequest-access (ESI, etc.). We're still working toward making the entire page mostly partial-based, and not having to replicate every partial we could possibly have as a unique route would make life a lot easier.

I'm unclear how the signing would work for hInclude, though. Since that's always coming from the browser, what exactly is the benefit?

@stof
Copy link
Member

stof commented Dec 27, 2012

@Crell avoiding links forged by the client by modifying the url. If the client modifies the target code, he won't be able to provide the update hash

@asm89
Copy link
Contributor Author

asm89 commented Dec 30, 2012

@vicb

What about HInclude, it seems the code has been removed ? (I think I understand but the reason why butit should be > mentionned in your post)

With signed uris HInclude could in theory stay, but it's probably still a bad idea. There could be another way of rendering hinclude tags with routes imo.

Not everybody use a RP & HInclude must be accessible to the outside world.

Yes, so adding HInclude was one of the things that fully opened up a security hole it seems. It would be nice however to attempt to fix it. :)

And one last but important q, why would using a controller be better than using a path ?

Not having to create a route for every single controller action? Why should a controller action be tied to the routing system? If you rely on rendering partials, having to add a route for all of them is a real dealbreaker imo (not to mention each partial now has to generate a url, go through the url matcher etc).


The point is that the creation of _internal urls and the interpretation of them was broken, but that doesn't mean that rendering partials "{% render 'BlogBundle:Post:list' with { 'limit': 2} %}" is suddenly a bad idea. Is it really worth the BC break in a 2.2 version?

@fabpot Any thoughts?

@vicb
Copy link
Contributor

vicb commented Dec 30, 2012

@asm89 thanks for adding details I think were missing from your original PR.

I wish the severity of the original issue would have been understood sooner & faster by the core team (I include myself here) so that we might have found a better solution.

@asm89
Copy link
Contributor Author

asm89 commented Dec 30, 2012

@vicb Yes, but since 2.2 is not out yet the complete removal of the feature could still be reverted?

@vicb
Copy link
Contributor

vicb commented Dec 30, 2012

"reverted" is probably not a word I would use here.

2.2 is supposed to be feature complete sometime next week & entering a 2 month "stabilization" phase. Strictly speaking the modification you request is beyond the scope of the stabilization phase... So I think only @fabpot could answer your question.

@fabpot
Copy link
Member

fabpot commented Dec 30, 2012

I spoke to several people about the removal of the _internal routes (some from Symfony and others from the eZpublish and Drupal projects). It is clear that people liked the old way, especially those who rely on this feature heavily for internal sub-requests only (no ESI, no hinclude).

I decided to remove these internal routes because of the big security issue they allow when not used properly.

However, the proposal in this PR sounds good, but instead of reverting and applying this patch, I'd like to first finish and merge PR #6459 because it will then be much easier to implement what you propose selectively (depending on the rendering strategy). For instance, for the default and ESI rendering strategies, we can automatically reject any request not coming from localhost or trusted proxies; and use a signed URI for Hinclude.

@asm89
Copy link
Contributor Author

asm89 commented Dec 31, 2012

@fabpot @vicb #6459 would make it easier to add different rendering strategies indeed, this is very nice. Will it however also re-introduce the {% render 'BlogBundle:Post:list' with { 'limit': 2} %} syntax?

@fabpot
Copy link
Member

fabpot commented Dec 31, 2012

As the signature for the tag/function should be the same for everything, I was thinking about adding a new controller function to support controller names:

{% render url('path') %}
{% render path('path') %}
{% render controller('BlogBundle:Post:list', { 'limit': 2}) %}

@Crell
Copy link
Contributor

Crell commented Jan 1, 2013

@fabpot I don't understand how url() and path() would differ there. Having controller() be a separate op makes sense to me, but how would that work outside of Twig? (Drupal's unlikely to be calling HttpKernel::render() from in a Twig file, more likely from its own PHP code.)

@vicb
Copy link
Contributor

vicb commented Jan 2, 2013

@asm89 I have been thinking a little more about this PR.

I think that having 2 different paths (secure vs HSI) is a must have.

However I am not really comfortable with URL signing. Your app will still be exposed to brute force attacks. There could be an other simple solution that was exposed to @fabpot and @schmittjoh in my initial threat report. Hopefuly I can get feedback soon. The final solution might be a conjuction of both signing & this - I am sorry to be vague here but I think not giving too many details is preferable.

@asm89
Copy link
Contributor Author

asm89 commented Jan 2, 2013

@fabpot In that case, maybe render could still behave as it did in 2.0 and 2.1 and render_uri could be added for the now options? Is it really worth breaking BC on this?

@vicb If you're comfortable with it you can e-mail me about this too (iam.asm89 [at] gma...). While I tend to agree with the general feeling that the app will be exposed to brute force attacks when using url signing, in the end this isn't different from your remember_me cookie being vulnerable for these kind of attacks (see TokenBasedRememberMeServices). Apart from that it's still possible to secure the _internal route with for example varnish configuration.

@vicb
Copy link
Contributor

vicb commented Jan 2, 2013

@asm89 the difference being that remember_me is optional and you would probably not enable the default implementation if you need a strong security.

@vicb
Copy link
Contributor

vicb commented Jan 2, 2013

@asm89 and brute-forcing an URL is much more powerull for an hacker: you can get access to the DB, file system, ...

@fabpot fabpot mentioned this pull request Jan 3, 2013
@fabpot
Copy link
Member

fabpot commented Jan 3, 2013

see #6459 for an implementation of the signing strategy.

@fabpot
Copy link
Member

fabpot commented Jan 3, 2013

Closing in favor of #6459

@fabpot fabpot closed this Jan 3, 2013
fabpot added a commit that referenced this pull request Jan 11, 2013
This PR was merged into the master branch.

Commits
-------

76fefe3 updated CHANGELOG and UPGRADE files
f7da1f0 added some unit tests (and fixed some bugs)
f17f586 moved the container aware HTTP kernel to the HttpKernel component
2eea768 moved the deprecation logic calls outside the new HttpContentRenderer class
bd102c5 made the content renderer work even when ESI is disabled or when no templating engine is available (the latter being mostly useful when testing)
a8ea4e4 [FrameworkBundle] deprecated HttpKernel::forward() (it is only used once now and not part of any interface anyway)
1240690 [HttpKernel] made the strategy a regular parameter in HttpContentRenderer::render()
adc067e [FrameworkBundle] made some services private
1f1392d [HttpKernel] simplified and enhanced code managing the hinclude strategy
403bb06 [HttpKernel] added missing phpdoc and tweaked existing ones
892f00f [HttpKernel] added a URL signer mechanism for hincludes
a0c49c3 [TwigBridge] added a render_* function to ease usage of custom rendering strategies
9aaceb1 moved the logic from HttpKernel in FrameworkBundle to the HttpKernel component

Discussion
----------

[WIP] Kernel refactor

Currently, the handling of sub-requests (including ESI and hinclude) is mostly done in FrameworkBundle. It makes these important features harder to implement for people using only HttpKernel (like Drupal and Silex for instance).

This PR moves the code to HttpKernel instead. The code has also been refactored to allow easier integration of other rendering strategies (refs #6108).

The internal route has been re-introduced but it can only be used for trusted IPs (so for the internal rendering which is managed by Symfony itself, or by a trusted reverse proxy like Varnish for ESI handling). For the hinclude strategy, when using a controller, the URL is automatically signed (see #6463).

The usage of a listener instead of a controller to handle internal sub-requests speeds up things quite a lot as it saves one sub-request handling. In Symfony 2.0 and 2.1, the handling of a sub-request actually creates two sub-requests.

Rendering a sub-request from a controller can be done with the following code:

```jinja
{# default strategy #}
{{ render(path("partial")) }}
{{ render(controller("SomeBundle:Controller:partial")) }}

{# ESI strategy #}
{{ render(path("partial"), { strategy: 'esi' }) }}
{{ render(controller("SomeBundle:Controller:partial"), { strategy: 'esi' }) }}

{# hinclude strategy #}
{{ render(path("default1"), { strategy: 'hinclude' }) }}
```

The second commit allows to simplify the calls a little bit thanks to some nice syntactic sugar:

```jinja
{# default strategy #}
{{ render(path("partial")) }}
{{ render(controller("SomeBundle:Controller:partial")) }}

{# ESI strategy #}
{{ render_esi(path("partial")) }}
{{ render_esi(controller("SomeBundle:Controller:partial")) }}

{# hinclude strategy #}
{{ render_hinclude(path("default1")) }}
```

---------------------------------------------------------------------------

by fabpot at 2013-01-03T17:58:49Z

I've just pushed a new version of the code that actually works in my browser (but I've not yet written any unit tests). I've updated the PR description accordingly.

All comments welcome!

---------------------------------------------------------------------------

by Koc at 2013-01-03T20:11:43Z

what about `render(controller="SomeBundle:Controller:partial", strategy="esi")`?

---------------------------------------------------------------------------

by stof at 2013-01-04T09:01:01Z

shouldn't we have interfaces for the UriSigner and the HttpContentRenderer ?

---------------------------------------------------------------------------

by lsmith77 at 2013-01-04T19:28:09Z

btw .. as mentioned in #6213 i think it would make sense to refactor the HttpCache to use a cache layer to allow more flexibility in where to cache the data (including clustering) and better invalidation. as such if you are refactoring HttpKernel .. it might also make sense to explore splitting off HttpCache.

---------------------------------------------------------------------------

by fabpot at 2013-01-04T19:30:07Z

@lsmith77 This is a totally different topic. This PR is just about moving things from FrameworkBundle to HttpKernel to make them more reusable outside of the full-stack framework.

---------------------------------------------------------------------------

by fabpot at 2013-01-05T09:39:52Z

I think this PR is almost ready now. I still need to update the docs and add some unit tests. Any other comments on the whole approach? The class names? The `controller` function thingy? The URI signer mechanism? The proxy protection for the internal controller? The proxy to handle internal routes?

---------------------------------------------------------------------------

by sstok at 2013-01-05T10:08:25Z

Looks good to me :+1:

---------------------------------------------------------------------------

by sdboyer at 2013-01-07T18:17:08Z

@Crell asked me to weigh in, since i'm one of the Drupal folks who's likely to work most with this.

i think i've grokked about 60% of the big picture here, and i'm generally happy with what i see. the assumption that the HInclude strategy makes about working with templates probably isn't one that we'll be able to use (and so, would need to write our own), but that's not a big deal since the whole goal here is to make strategies pluggable.

so, yeah. +1.

---------------------------------------------------------------------------

by winzou at 2013-01-09T20:21:44Z

Just for my information: will this PR be merged for 2.2 version? Thanks.

---------------------------------------------------------------------------

by stof at 2013-01-09T20:41:04Z

@winzou according to the blog post announcing the beta 1 release, yes. It is explicitly listed as being one of the reason to make it a beta instead of the first RC.

---------------------------------------------------------------------------

by winzou at 2013-01-09T20:49:36Z

OK thanks, I've totally skipped this blog post.

---------------------------------------------------------------------------

by fabpot at 2013-01-10T15:26:15Z

I've just added a bunch of unit tests and fix some bugs I found while writing the tests.
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.

7 participants
Morty Proxy This is a proxified and sanitized view of the page, visit original site.