

# PHP를 사용하여 서명된 쿠키 생성
<a name="signed-cookies-PHP"></a>

다음 코드 예제는 동영상에 대한 링크를 만드는 [PHP를 사용한 URL 서명 생성](CreateURL_PHP.md)의 예제와 유사합니다. 그러나 이 예제에서는 코드의 URL에 서명하는 대신 `create_signed_cookies()` 함수를 사용하여 쿠키에 서명합니다. 클라이언트 측 플레이어는 쿠키를 사용하여 CloudFront 배포에 대한 각 요청을 인증합니다.

이 접근 방식은 클라이언트가 매니페스트, 세그먼트 및 관련 재생 자산을 검색하기 위해 여러 요청을 해야 하는 HLS(HTTP Live Streaming) 또는 DASH(Dynamic Adaptive Streaming over HTTP)와 같은 콘텐츠를 스트리밍하는 데 유용합니다. 클라이언트는 서명된 쿠키를 사용하여 각 세그먼트에 대해 서명된 새 URL을 만들 필요 없이 각 요청을 인증할 수 있습니다.

**참고**  
URL 서명을 만드는 것은 서명된 쿠키를 사용해 프라이빗 콘텐츠를 제공하는 프로세스의 한 부분에 불과합니다. 자세한 내용은 [서명된 쿠키 사용](private-content-signed-cookies.md) 섹션을 참조하세요.



**Topics**
+ [RSA SHA-1 또는 SHA-256 서명 생성](#create-rsa-sha-1signature-cookies)
+ [서명된 쿠키 생성](#create-the-signed-cookie)
+ [전체 코드](#full-code-signed-cookies)

다음 섹션에서는 코드 예제를 각 부분으로 나눕니다. 아래에서 전체 [코드 샘플](#full-code-signed-cookies)을 확인할 수 있습니다.

## RSA SHA-1 또는 SHA-256 서명 생성
<a name="create-rsa-sha-1signature-cookies"></a>

이 코드 예제에서는 다음을 수행합니다.

1. `rsa_sha1_sign` 함수는 SHA-1을 사용하여 정책 문을 해시하고 서명합니다. 대신 SHA-256을 사용하려면 아래 표시된 rsa\$1sha256\$1sign 함수를 사용합니다. 필요한 인수는 배포의 신뢰할 수 있는 키 그룹에 있는 퍼블릭 키에 해당하는 프라이빗 키와 정책 설명입니다.

1. 다음으로 `url_safe_base64_encode` 함수는 서명의 안전한 URL 버전을 만듭니다.

   ```
   function rsa_sha1_sign($policy, $private_key_filename) {
       $signature = "";
       $fp = fopen($private_key_filename, "r");
       $priv_key = fread($fp, 8192);
       fclose($fp);
       $pkeyid = openssl_get_privatekey($priv_key);
       openssl_sign($policy, $signature, $pkeyid);
       openssl_free_key($pkeyid);
       return $signature;
   }
   
   function url_safe_base64_encode($value) {
       $encoded = base64_encode($value);
       return str_replace(
           array('+', '=', '/'),
           array('-', '_', '~'),
           $encoded);
   }
   ```

   다음 함수는 SHA-1 대신 SHA-256을 사용합니다.

   ```
   function rsa_sha256_sign($policy, $private_key_filename) {
       $signature = "";
       $fp = fopen($private_key_filename, "r");
       $priv_key = fread($fp, 8192);
       fclose($fp);
       $pkeyid = openssl_get_privatekey($priv_key);
       openssl_sign($policy, $signature, $pkeyid, OPENSSL_ALGO_SHA256);
       openssl_free_key($pkeyid);
       return $signature;
   }
   ```

   `rsa_sha256_sign` 함수는 `OPENSSL_ALGO_SHA256`을 `openssl_sign`에 전달한다는 점을 제외하면 `rsa_sha1_sign`과 동일합니다. SHA-256을 사용하는 경우 값이 `SHA256`인 `CloudFront-Hash-Algorithm` 쿠키를 포함합니다.

## 서명된 쿠키 생성
<a name="create-the-signed-cookie"></a>

다음 코드는 다음 쿠키 속성(예: `CloudFront-Expires`, `CloudFront-Signature`, `CloudFront-Key-Pair-Id` 및 `CloudFront-Hash-Algorithm`)을 사용하여 서명된 쿠키를 만듭니다. 코드는 사용자 지정 정책을 사용합니다.

```
function create_signed_cookies($resource, $private_key_filename, $key_pair_id, $expires, $client_ip = null, $hash_algorithm = 'SHA1') {
    $policy = array(
        'Statement' => array(
            array(
                'Resource' => $resource,
                'Condition' => array(
                    'DateLessThan' => array('AWS:EpochTime' => $expires)
                )
            )
        )
    );

    if ($client_ip) {
        $policy['Statement'][0]['Condition']['IpAddress'] = array('AWS:SourceIp' => $client_ip . '/32');
    }

    $policy = json_encode($policy);
    $encoded_policy = url_safe_base64_encode($policy);
    if ($hash_algorithm === 'SHA256') {
        $signature = rsa_sha256_sign($policy, $private_key_filename);
    } else {
        $signature = rsa_sha1_sign($policy, $private_key_filename);
    }
    $encoded_signature = url_safe_base64_encode($signature);

    $cookies = array(
        'CloudFront-Policy' => $encoded_policy,
        'CloudFront-Signature' => $encoded_signature,
        'CloudFront-Key-Pair-Id' => $key_pair_id
    );

    if ($hash_algorithm === 'SHA256') {
        $cookies['CloudFront-Hash-Algorithm'] = 'SHA256';
    }

    return $cookies;
}
```

자세한 내용은 [사용자 지정 정책을 사용하여 서명된 쿠키 설정](private-content-setting-signed-cookie-custom-policy.md) 섹션을 참조하세요.

## 전체 코드
<a name="full-code-signed-cookies"></a>

다음 예제 코드는 PHP로 CloudFront 서명 쿠키를 만드는 전체 데모를 제공합니다. [demo-php.zip](samples/demo-php.zip) 파일에서 전체 예제를 다운로드할 수 있습니다.

다음 예제에서는 IPv4 및 IPv6 주소 범위를 모두 허용하도록 `$policy Condition` 요소를 수정할 수 있습니다. 예제는 Amazon Simple Storage Service 사용 설명서의 [IAM 정책에서 IPv6 주소 사용](https://docs.aws.amazon.com/AmazonS3/latest/userguide/ipv6-access.html#ipv6-access-iam)을 참조합니다.**

```
<?php

function rsa_sha1_sign($policy, $private_key_filename) {
    $signature = "";
    $fp = fopen($private_key_filename, "r");
    $priv_key = fread($fp, 8192);
    fclose($fp);
    $pkeyid = openssl_get_privatekey($priv_key);
    openssl_sign($policy, $signature, $pkeyid);
    openssl_free_key($pkeyid);
    return $signature;
}

function url_safe_base64_encode($value) {
    $encoded = base64_encode($value);
    return str_replace(
        array('+', '=', '/'),
        array('-', '_', '~'),
        $encoded);
}

function rsa_sha256_sign($policy, $private_key_filename) {
    $signature = "";
    $fp = fopen($private_key_filename, "r");
    $priv_key = fread($fp, 8192);
    fclose($fp);
    $pkeyid = openssl_get_privatekey($priv_key);
    openssl_sign($policy, $signature, $pkeyid, OPENSSL_ALGO_SHA256);
    openssl_free_key($pkeyid);
    return $signature;
}

function create_signed_cookies($resource, $private_key_filename, $key_pair_id, $expires, $client_ip = null, $hash_algorithm = 'SHA1') {
    $policy = array(
        'Statement' => array(
            array(
                'Resource' => $resource,
                'Condition' => array(
                    'DateLessThan' => array('AWS:EpochTime' => $expires)
                )
            )
        )
    );

    if ($client_ip) {
        $policy['Statement'][0]['Condition']['IpAddress'] = array('AWS:SourceIp' => $client_ip . '/32');
    }

    $policy = json_encode($policy);
    $encoded_policy = url_safe_base64_encode($policy);
    if ($hash_algorithm === 'SHA256') {
        $signature = rsa_sha256_sign($policy, $private_key_filename);
    } else {
        $signature = rsa_sha1_sign($policy, $private_key_filename);
    }
    $encoded_signature = url_safe_base64_encode($signature);

    $cookies = array(
        'CloudFront-Policy' => $encoded_policy,
        'CloudFront-Signature' => $encoded_signature,
        'CloudFront-Key-Pair-Id' => $key_pair_id
    );

    if ($hash_algorithm === 'SHA256') {
        $cookies['CloudFront-Hash-Algorithm'] = 'SHA256';
    }

    return $cookies;
}



$private_key_filename = '/home/test/secure/example-priv-key.pem';
$key_pair_id = 'K2JCJMDEHXQW5F';
$base_url = 'https://d1234.cloudfront.net';

$expires = time() + 3600; // 1 hour from now

// Get the viewer real IP from the x-forward-for header as $_SERVER['REMOTE_ADDR'] will return viewer facing IP. An alternative option is to use CloudFront-Viewer-Address header. Note that this header is a trusted CloudFront immutable header. Example format: IP:PORT ("CloudFront-Viewer-Address": "1.2.3.4:12345")
$client_ip = $_SERVER['HTTP_X_FORWARDED_FOR'];


// For HLS manifest and segments (using wildcard)
$hls_resource = $base_url . '/sign/*';
$signed_cookies = create_signed_cookies($hls_resource, $private_key_filename, $key_pair_id, $expires, $client_ip, 'SHA256');

// Set the cookies
$cookie_domain = parse_url($base_url, PHP_URL_HOST);
foreach ($signed_cookies as $name => $value) {
    setcookie($name, $value, $expires, '/', $cookie_domain, true, true);
}

?>

<!DOCTYPE html>
<html>
<head>
    <title>CloudFront Signed HLS Stream with Cookies</title>
</head>
<body>
    <h1>Amazon CloudFront Signed HLS Stream with Cookies</h1>
    <h2>Expires at <?php echo gmdate('Y-m-d H:i:s T', $expires); ?> only viewable by IP <?php echo $client_ip; ?></h2>
    
    <div id='hls-video'>
        <video id="video" width="640" height="360" controls></video>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
    <script>
        var video = document.getElementById('video');
        var manifestUrl = '<?php echo $base_url; ?>/sign/manifest.m3u8';
        
        if (Hls.isSupported()) {
            var hls = new Hls();
            hls.loadSource(manifestUrl);
            hls.attachMedia(video);
        }
        else if (video.canPlayType('application/vnd.apple.mpegurl')) {
            video.src = manifestUrl;
        }
    </script>
</body>
</html>
```

서명된 쿠키를 사용하는 대신 서명된 URL을 사용할 수 있습니다. 자세한 내용은 [PHP를 사용한 URL 서명 생성](CreateURL_PHP.md) 섹션을 참조하세요.