phphttps

How to find out if you're using HTTPS without $_SERVER['HTTPS']


I've seen many tutorials online that says you need to check $_SERVER['HTTPS'] if the server is connection is secured with HTTPS. My problem is that on some of the servers I use, $_SERVER['HTTPS'] is an undefined variable that results in an error. Is there another variable I can check that should always be defined?

Just to be clear, I am currently using this code to resolve if it is an HTTPS connection:

if(isset($_SERVER['HTTPS'])) {
    if ($_SERVER['HTTPS'] == "on") {
        $secure_connection = true;
    }
}

Solution

  • Basic Approach

    This should always work even when $_SERVER['HTTPS'] is undefined:

    function isSecure() {
        return
            (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
            || $_SERVER['SERVER_PORT'] == 443;
    }
    

    The code is compatible with IIS.

    From the PHP.net documentation and user comments :

    1. Set to a non-empty value if the script was queried through the HTTPS protocol.

    2. Note that when using ISAPI with IIS, the value will be "off" if the request was not made through the HTTPS protocol. (Same behaviour has been reported for IIS7 running PHP as a Fast-CGI application).

    Also, Apache 1.x servers (and broken installations) might not have $_SERVER['HTTPS'] defined even if connecting securely. Although not guaranteed, connections on port 443 are, by convention, likely using secure sockets, hence the additional port check.

    Consideration for Load Balancers

    If there is a load balancer between the client and your server, the above code doesn't test the connection between the client and the load balancer, but the connection between the load balancer and your server. To test the connection between the client and the load balancer, you would need to check the HTTP_X_FORWARDED_PROTO header. However, implementing this can be more complex; see latest comments below this answer.

    Alternative Approach: Using Symfony's Request Class

    Symfony provides a more robust way to determine whether the request is secure by using the Request class from its HttpFoundation component. This method accounts for headers set by proxies and load balancers, making it more reliable across different environments.

    Installation

    First, install the necessary package using Composer:

    composer require symfony/http-foundation
    

    Using $request->isSecure()

    Then, use the Request class:

    use Symfony\Component\HttpFoundation\Request;
    
    $request = Request::createFromGlobals();
    $isSecure = $request->isSecure();
    

    This method first checks if the request is from a recognized proxy. If it is, it considers X-Forwarded-Proto. If the request is not from a recognized proxy, it considers $_SERVER['HTTPS'].

    Handling Proxies and Load Balancers

    If your application is behind a proxy or load balancer, you must explicitly set trusted proxies to ensure Symfony correctly interprets forwarded headers:

    Request::setTrustedProxies(
        ['127.0.0.1', '192.168.1.1'], // Replace with actual proxy IPs
        Request::HEADER_X_FORWARDED_ALL
    );
    

    Request::HEADER_X_FORWARDED_ALL is a Symfony constant that includes all relevant forwarded headers, such as X-Forwarded-For (client IP), X-Forwarded-Proto (HTTPS detection), and others. This simplifies proxy handling by ensuring all forwarded headers are considered.

    Alternatively, in a Symfony project, you can configure this in config/packages/framework.yaml:

    framework:
        trusted_proxies: ['127.0.0.1', '192.168.1.1']
        trusted_headers: ['x-forwarded-for', 'x-forwarded-proto']
    

    In YAML configuration, trusted headers are explicitly listed. x-forwarded-for allows Symfony to correctly determine the client IP when behind a proxy, while x-forwarded-proto ensures proper HTTPS detection. This gives fine-grained control over which headers are trusted.

    Be aware that HTTP_X_FORWARDED_PROTO can be spoofed unless properly controlled. Always ensure that trusted proxy configurations are correctly set to avoid false HTTPS detections.