Skip to content

Instantly share code, notes, and snippets.

@vortexau
Last active March 16, 2017 08:13
Show Gist options
  • Save vortexau/d69e2c8ec782b3b12aa7 to your computer and use it in GitHub Desktop.
Save vortexau/d69e2c8ec782b3b12aa7 to your computer and use it in GitHub Desktop.
Laravel 5.1 Handling SSL and NonSSL connections

Laravel 5.1 SSL/TLS & Non-TLS interface.

Problem:

A Laravel 5.1 Application behind a BigIP F5 load-balancer applicance, which performed the SSL termination. The traffic from F5 to Laravel is only over Port 80 (internal 'secure' network) and Laravel itself thinks it is insecure, and thus all URLs to internal resources were 'http'. We also wanted to maintain the ability to serve certain unauthenticated content over HTTP.

These F5 load-balancers can roll all connections up to HTTPS, however in this instance we did not wish to perform this as the Laravel application is designed to intercept connections for another decommissioned application which served SSL and Non-SSL connections.

Solution:

  1. An iRule was added to the Virtual Server on the F5 device to include a 'HTTPS' 'on' header when the request to the F5 device was HTTPS

  2. A ServiceProvider was added to Laravel to check for this and call the required 'forceSchema()' function call when required.

  3. Add the ServiceProvider to config/app.php in the providers array, sepecifically under the 'Custom Providers'

     /*
      * Custom providers...
      */
     App\Providers\SecureRoutingServiceProvider::class,
    

Your specific configuration may differ from the above. This code may work with other load balancer devices or services such as CloudFlare as they send a different header for HTTPS requests, and as such the SecureRoutingServiceProvider.php code may not need the call to setTrustedHeaderName() for example.

You may like to check the IP provided by getClientIp() against a whitelist before allowing it to be given Trusted Proxy status (infact I would insist on it!). In our environment nothing but the load balancers themselves can get to our web servers - but clearly your environment might be vastly different to this especially if you're using a service like CloudFlare.

<?php
namespace App\Providers;
use Illuminate\Routing\UrlGenerator;
use Illuminate\Routing\Router;
use App\Providers\RouteServiceProvider as ServiceProvider;
use Symfony\Component\HttpFoundation\Request;
class SecureRoutingServiceProvider extends ServiceProvider
{
public function boot(Router $router)
{
$request = request();
$request->setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, 'HTTPS');
$request->setTrustedProxies( [ $request->getClientIp() ] );
// Our environment has SSL all through Dev/Test/Prod. Yours may not,
// as such you can remove the environments below which do not make sense.
if ($request->secure() &&
(app()->environment('dev') ||
app()->environment('test') ||
app()->environment('production'))) {
app()->bind('url', function() {
$generator = new UrlGenerator(
app('router')->getRoutes(),
request()
);
$generator->forceSchema('https');
return $generator;
});
}
parent::boot($router);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment