Oct
25
SSL Redirect Filter for Symfony
Filed Under PHP, Security, Symfony - October 25th, 2006 5:05pm
Serving secure pages on a website is made a lot easier by having both your secure and insecure pages served by the same files - all you need to do is change the scheme from http:// to https:// and you’re done. But how do you manage which pages should redirect to the secure server? And how do you make sure you redirect users back when they’re finished submitting sensitive information?
The answer again is in Symfony’s filter framework, which can be used to automatically monitor whether your requests should change scheme, and redirect when needed.
Oh - one more thing. I don’t want redirection to take place in development mode.
Note: this technique won’t work if your secure and insecure URLs point to different directories. Sorry, but I haven’t taken that scenario into consideration because I haven’t had to deal with it yet :). If you’re really stuck email me and I’ll see what I can do.
First add the following settings to your app.yml file:
1 2 3 4 5 6 7 8 | all:
ssl:
insecure_host: blog.phpdeveloper.co.nz
secure_host: secure.phpdeveloper.co.nz
secure_actions:
- { module: shop, action: register }
- { module: shop, action: checkout }
- { module: register, action: updateCardDetails } |
The insecure_host and secure_host keys should be the hostnames of your HTTP server (port 80) and HTTPS server (port 443) respectively. Under secure_actions put the list of module/action combinations which should always be secure. Best practice is to make both the form editing page and the form submission page secure, to give your users peace of mind throughout the process.
Next we add our filter code to lib/sslFilter.class.php:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | /** * Filter for redirecting to SSL for the pages that need it * * @author James McGlinn <james@mcglinn.org> * @version 2 */ class sslFilter extends sfFilter { /** * Execute filter * * @param FilterChain $filterChain The symfony filter chain */ public function execute ($filterChain) { // Only execute this filter once if ($this->isFirstCall() && SF_ENVIRONMENT != 'dev') { // Array of modules/actions that require move to SSL $ssl_actions = sfConfig::get('app_ssl_secure_actions'); if (empty($_SERVER['HTTPS']) && count($_POST) < 1) { // We're not using SSL and not POSTing data - check if we should be using SSL foreach ($ssl_actions as $action) { if ($this->getContext()->getModuleName() == $action['module'] && $this->getContext()->getActionName() == $action['action']) { $new_url = sprintf('https://%s%s', sfConfig::get('app_ssl_secure_host'), $_SERVER['REQUEST_URI']); header('Location: ' . $new_url); exit; } } // Using secure host when not required - not good if ($_SERVER['HTTP_HOST'] == sfConfig::get('app_ssl_secure_host')) { $new_url = sprintf('http://%s%s', sfConfig::get('app_ssl_insecure_host'), $_SERVER['REQUEST_URI']); header('Location: ' . $new_url); exit; } } elseif (!empty($_SERVER['HTTPS']) && count($_POST) < 1) { // We're using SSL and not posting data $dont_redirect = false; foreach ($ssl_actions as $action) { if ($this->getContext()->getModuleName() == $action['module'] && $this->getContext()->getActionName() == $action['action']) { $dont_redirect = true; } } if ($dont_redirect == false) { // Redirect $new_url = sprintf('http://%s%s', sfConfig::get('app_ssl_insecure_host'), $_SERVER['REQUEST_URI']); header('Location: ' . $new_url); exit; } } } // Next filter $filterChain->execute(); } } |
Finally, enable your sslFilter in the application’s config/filters.yml configuration file:
1 2 | sslFilter: class: sslFilter |
Run symfony cc to clear your cache and the filter will be working. Your URLs can remain the same and any insecure requests for actions listed in app.yml will be redirected to the same URL on the secure server. The only exceptions are requests with POST data, which won’t be redirected as the data would be lost.
Conversely, any requests made through the secure server for pages not in the list will redirect the user back to the insecure version of the page. That reduces the work your server has to do and decreases load times for the user, keeping everyone happy.

I have modified a little bit the code to secure a whole module or a couple module/action.
In 1st bloc
In 2nd bloc :
Note that the following code leads to an infinite redirection if the secure and unsecure section have the same url excepting the “s”, i had to remove it for my server configuration.
great way to handle this. makes selective implementation a breeze. Far less invasive than other possible ways of handling this, and great that it redirects non secure pages back to non secure hosting.
on the downside, filters seem to slow down the overall performance–I guess what we gain in the abstraction we give up in the localization. less code, less intrusion, but a check on every page load for the site, every time.
well done.
Two years later, still helping =)
[...] url: http://james.mcglinn.org/2006/10/ssl-redirect-filter-for-symfony/ Comments [...]
[...] scripts that I found online, and created a very simple filter to handle this. This was inspired by this script, and the unacceptably poor example in the Symfony 1.2 [...]
Hi,
I’m getting this in the Apache log :
PHP Fatal error: Class ’sslFilter’ not found in ***\modules_home_config_filters.yml.php on line 6
What could be the problem ?
Thank you
Hi Dan, sounds like you need to run “./symfony cc” to clear your cache. After that the filter class file should be picked up by the autoloader.