Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

setting up signed cookies for aws cloudfront https with php SDK

I am setting up a HLS streaming service through cloudfront and implementing several security measures for content protection. I have successfully made it work under http, I can stream video and watch it in my website with a lot of content protection security measures. For more details on how I managed to make it work for http you can consult it in a post I made in drupal.org about secure hls streaming.

But now I need to add https to the formula because some encryption keys for hls encrypted segments are being transmitted, but I am having problems. Now I am working to add https to the formula. I have added a certificate to my site and I have added a different certificate in cludfront because my certificate is not a wildcard one.

My site certificate works for subdomain.mydomain.com

My cloudfront certificate is for *.mydomain.com

My cloudfront distribution has a cname of cdn.mydomain.com

When I create the cookie I set the secure parameter to true in the call (6th parameter after domain):

setcookie($name, $value, strtotime('+1 hour'), "/", ".mydomain.com", true, true);

But when I try to access some test data in my site

if (readfile('https://cdn.mydomain.com/privacy_test.txt')==0)
    print "Error in cdn access";

I don't see the contents of the file in my website, but the error message.

So it seems I need more things to do to make cloudfront aws signed cookies work under https. Any help?

like image 518
vasdfg Avatar asked Mar 19 '16 08:03

vasdfg


People also ask

How do I enable cookies in CloudFront?

If you want to receive cookies at your origin but you don't want CloudFront to cache the Set-Cookie headers in your origin's responses, configure your origin to add a Cache-Control header with a no-cache directive that specifies Set-Cookie as a field name. For example: Cache-Control: no-cache="Set-Cookie" .

What is the difference between CloudFront signed URL and S3 signed URL?

In CloudFront, a signed URL allow access to a path. Therefore, if the user has a valid signature, he can access it, no matter the origin. In S3, a signed URL issue a request as the signer user.


1 Answers

Simply setting the $secure parameter of setcookie() does not create a signed cookie. The process to create a signed cookie is a bit complicated. First, review Using Signed Cookies, specifically the Canned and Custom policy sections. You will need to familiarize yourself with creating a Policy, base64encoding that Policy and creating a Signature from the encoded policy.

Leveraging the code examples outlined in here, I then use the following code in a few of my applications to set the cookies:

public static function getCustomSignedCookies()
{
    $domain = '.' . explode('.', apache_request_headers()['Host'], 2)[1];
    $dt = new DateTime();
    $dt->add(new DateInterval('P1Y')); // 1 year
    $expires = $dt->getTimestamp();
    $url = Config::get('cloudfront_url') . '/*';
    $policy = self::getCustomPolicy($url, $expires);
    $encodedPolicy = self::url_safe_base64_encode($policy);
    $signature = self::getSignature($policy);

    $cookies = [
        [
            'name' => 'CloudFront-Policy'
            , 'value' => $encodedPolicy
            , 'expires' => $expires
            , 'path' => '/'
            , 'domain' => $domain
            , 'secure' => true
            , 'httpOnly' => true
        ],
        [
            'name' => 'CloudFront-Signature'
            , 'value' => $signature
            , 'expires' => $expires
            , 'path' => '/'
            , 'domain' => $domain
            , 'secure' => true
            , 'httpOnly' => true
        ],
        [
            'name' => 'CloudFront-Key-Pair-Id'
            , 'value' => self::$keyPair
            , 'expires' => $expires
            , 'path' => '/'
            , 'domain' => $domain
            , 'secure' => true
            , 'httpOnly' => true
        ]
    ];

    return $cookies;
}

public static function setCloudFrontCookies()
{
    ob_start();

    foreach (self::getCustomSignedCookies() as $cookie)
    {
        setcookie
        (
            $cookie['name']
            , $cookie['value']
            , $cookie['expires']
            , $cookie['path']
            , $cookie['domain']
            , $cookie['secure']
            , $cookie['httpOnly']
        );
    }

    ob_end_flush();
}
like image 87
Aaron St. Clair Avatar answered Sep 22 '22 02:09

Aaron St. Clair