Solved thread

This post is marked as solved. If you think the information contained on this thread must be part of the official documentation, please contribute submitting a pull request to its repository.

How to force HTTPS?

I need to force all requests as HTTPS in my multimodule application. I've found a topic on Phalcon forum about this but it doesn't give the answer.

My problems:

(1) How to build a new, valid URL/request based on the current?

My solution:

if(!$di->get('request')->isSecureRequest()){
    $url = "https://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"];
    $di->get('response')->redirect($url);
    return false;
}

Do you know any other better solutions? Is there a solution to produce a new, little changed URL based on the matched route?

(2) Where to put this?

First (check post in the linked topic) I have put the code in the base controller -> in the beforeExecuteRoute method. I have a multimodule application so I decided to change it. At the end I've put the code in the index.php bootstrap -> dispatcher -> event. Check the full code below!

$di->set('dispatcher', function() {
        $dispatcher = new Dispatcher();

        //Create an event manager
        $eventsManager = new EventsManager();

        //Attach a listener for type "dispatch"
        $eventsManager->attach("dispatch:beforeDispatchLoop", function($event, $dispatcher) {
            $di = $dispatcher->getDI();
            if(!$di->get('request')->isSecureRequest()){
                $url = "https://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"];
                $di->get('response')->redirect($url);
                return false;
            }
            return true;
        });

        //Bind the eventsManager to the view component
        $dispatcher->setEventsManager($eventsManager);

        return $dispatcher;
},true);

What do you think? Is there a better place to put this than in dispatcher event?

(3) How to handle requests other than GET e.g. POST?

At the moment I don't need it but probably I will. I am thinking how to handle full request, I mean POST data, ports etc.? Is there a "sexy" soluton for these?

(4) Other ways?

I have heard that other solution is to change some settings in apache. Did you heard about it? Any other solutions? What are pros and cons?

Every input is highly appreciated!. TIA

edited Nov '14

Hey Conradaek,

The codes related with "$di" which is for dependency injection, are used in services. So you can write all your codes containg $di in config/services.php file at the end of file. You can keep adding your DI services one by one after the last function in services.php file. Try it. ;) Enjoy your codes. :D



16.7k

I don't understand what you are about. Could you explain another way? Is what you are proposing about how should I organise my files?

Second code in my post is part of my bootstrap (public/index.php) file.



18.5k

I used SSL in apache2, but I cannot tell you pros and cons, because I'm a totally noob in that. What I can tell is that is very easy to set up an SSL server there.



1.9k
Accepted
answer

Can You do 301 redirect in .htaccess from http to https, or in apache.conf for virtual host ? I think it will be good way for to force HTTPS.

edited Nov '14

Paste these codes in config/services.php file

    $di->set('dispatcher', function() {
            $dispatcher = new Dispatcher();

            //Create an event manager
            $eventsManager = new EventsManager();

            //Attach a listener for type "dispatch"
            $eventsManager->attach("dispatch:beforeDispatchLoop", function($event, $dispatcher) {
                $di = $dispatcher->getDI();
                if(!$di->get('request')->isSecureRequest()){
                    $url = "https://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"];
                    $di->get('response')->redirect($url);
                    return false;
                }
                return true;
            });

            //Bind the eventsManager to the view component
            $dispatcher->setEventsManager($eventsManager);

            return $dispatcher;
    },true);

Try this and if it doesn't work, let me know.

I don't understand what you are about. Could you explain another way? Is what you are proposing about how should I organise my files?

Second code in my post is part of my bootstrap (public/index.php) file.

By far the best way to do this is put a redirect rule in your .htaccess file. It's a couple lines vs. a whole bunch of lines. Plus, the .htaccess file gets parsed before PHP fires up, so using .htaccess is much more efficient.



44.6k
    public function beforeDispatchLoop(Event $event, Dispatcher $dispatcher)
    {
        $https = $this->config->security->https;
        $hsts = $this->config->security->hsts;

        // If HTTPS or HSTS are required.
        if ($https || ($hsts > 0)) {
            // is HTTPS currently active.
            // HTTP_X_FORWARDED_PROTO checks for reverse proxies that that communicate with the server using HTTP
            $isCurrentlyHttps = (isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == 'on'))
              || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'));

            // At this point HTTPS is required and it redirects to HTTPS if the current connection is not secure
            if (! ($isCurrentlyHttps)) {
                // Create a new URL. The URL service will be set to generate HTTPS by these same configuration options
                $secureUrl = $this->url->get($_SERVER["REQUEST_URI"], true);
                // Redirect the client to the HTTPS protocol version of this page
                $this->response->redirect($secureUrl, true, 301);
                // Stop entire dispatch operation for redirect
                return false;
            }
            // At this point the client is already connected with the HTTPS protocol.
            // Send HSTS header if set in the configuration
            else if ($hsts > 0) {
                // Note: This feature is currently not supported on any IE as of version 11 (and is quitely ignored).
                $this->response->setHeader('Strict-Transport-Security', 'max-age='.(string)$hsts);
            }
        }

        // Prevents the webpage from being contained within an iframe of a foreign domain
        if ($this->config->security->preventClickjack) {
            $this->response->setHeader('X-Frame-Options', 'SAMEORIGIN');
        }
    }
$di->setShared('url', function() use ($di) {
    $config = $di->get('config');

    $isCurrentlyHttps = $config->server->https;
    $shouldHttps = $config->security->https;
    $usingHsts = ($config->security->hsts > 0);

    $proto = ($isCurrentlyHttps || $shouldHttps || $usingHsts) ? 'https' : 'http';

    if ($config->server->domain == '') {
        $domain = $config->site->domains[0];
    } else {
        $domain = $config->server->domain;
    }

    $uri = $config->app->baseUri;

    $url = new Url();
    $url->setBaseUri("{$proto}://{$domain}{$uri}");
    return $url;
});


16.7k

Developing the PHP code for redirection was waste of time... Is there anyone who disagree?

Finally, I have decided to make an apache redirection it .htaccess file. As some of you suggested. There are two arguments:

(1) It is done before PHP script is started so it is more efficient (and we are Phalconees, we belive in performence! ) :) @quasipickle

(2) We already do apache redirections with mod_rewrite to rewrite URIs

@viralj Thanks for your input but it was only for organizing code (I mean which directory to put the files). I was asking "where" but in terms of application code (e.g. dispatcher event or controller etc).

My .htaccess file:

<IfModule mod_rewrite.c>
    # force HTTPS
    RewriteCond %{HTTPS} !=on
    RewriteRule .* https://%{SERVER_NAME}%{REQUEST_URI} [R,L]   

    # phalcon rewrite to publix/index.php file
    RewriteEngine on
    RewriteRule  ^$ public/    [L]
    RewriteRule  (.*) public/$1 [L]
</IfModule>

Is there sth to improve? Thanks!

I've done it based on http://www.askapache.com/htaccess/ssl-example-usage-in-htaccess.html.



16.7k

I have marked vitaliykoziy user as "accepted answer" first and then realized that I cannot mark two users. But it was you who have convinced me. THanks!

By far the best way to do this is put a redirect rule in your .htaccess file. It's a couple lines vs. a whole bunch of lines. Plus, the .htaccess file gets parsed before PHP fires up, so using .htaccess is much more efficient.



44.6k

Developing the PHP code for redirection was waste of time... Is there anyone who disagree?

It might be a waste of time but I consider it important enough to do in both. You might was to set Strict-Transport-Security as that will prevent the browser from ever attempting to reach out on an insecure line once everything gets going. It doesn't work on IE currently though.



16.7k

@dschissler I don't know if I understand you. Do you mean that if a user will be browsing by Internet Explorer and my redirection will be set only in apache's .htaccess file, without any code in PHP, then it will not work? The user will not be redirected?



44.6k

The .htaccess file is perfect in all scenarios.

If you set HSTS from PHP code then that header will currently be ignored until IE12. It doesn't hurt to add it and it will only improve the security.

I have marked vitaliykoziy user as "accepted answer" first and then realized that I cannot mark two users. But it was you who have convinced me. THanks!

I think the correct action was to mark vitaliykoziy's answer as accepted - like you've done. The point of marking an answer correct is so that future people looking for answers can quickly see what the right answer was. I see my answer has a +1 - so thanks for that.

edited Jul '16

in phalcon .htaccess default setting there is other .htaccess in directory project/public/.htaccess

could you give me a snapshot of that file and how you config it ?

i have tried with your solution but my browser tells error to many redirect.

these are my .htaccess

[ root project ]
 <IfModule mod_rewrite.c>
     # force HTTPS
     RewriteCond %{HTTPS} !=on
     RewriteRule .* https://%{SERVER_NAME}%{REQUEST_URI} [R,L]   

    RewriteEngine on
     RewriteRule  ^$ public/    [L]
     RewriteRule  ((?s).*) public/$1 [L]
 </IfModule>

 [ public directory]
 AddDefaultCharset UTF-8

 <IfModule mod_rewrite.c>
    RewriteEngine On 
    RewriteCond %{REQUEST_FILENAME} !-d 
     RewriteCond %{REQUEST_FILENAME} !-f 
     RewriteRule ^(.*)$ index.php?_url=/$1 [QSA,L]
 </IfModule>

Developing the PHP code for redirection was waste of time... Is there anyone who disagree?

Finally, I have decided to make an apache redirection it .htaccess file. As some of you suggested. There are two arguments:

(1) It is done before PHP script is started so it is more efficient (and we are Phalconees, we belive in performence! ) :) @quasipickle

(2) We already do apache redirections with mod_rewrite to rewrite URIs

@viralj Thanks for your input but it was only for organizing code (I mean which directory to put the files). I was asking "where" but in terms of application code (e.g. dispatcher event or controller etc).

My .htaccess file:

```php

<IfModule mod_rewrite.c> # force HTTPS RewriteCond %{HTTPS} !=on RewriteRule .* https://%{SERVER%5NAME}%{REQUEST%5URI} [R,L]

# phalcon rewrite to publix/index.php file RewriteEngine on RewriteRule ^$ public/ [L] RewriteRule (.*) public/$1 [L] </IfModule>

```

Is there sth to improve? Thanks!

I've done it based on http://www.askapache.com/htaccess/ssl-example-usage-in-htaccess.html.