Laza
Laza

Reputation: 101

Serving private content from CloudFront with Signed Cookies

Cloudfront supports signed cookies for serving up private content but I cant find any examples on how to do this.

I have found examples on how to sign URLs with the Java AWS API but not Cookies, can someone please share their experiences with doing this and is this the best way to secure multiple forms of media being served from CloudFront.

Our site has images and video that are uploaded by the user, which can then be viewed by searches on our site, I want to make sure that these images can only be served by our site and not copied for later use.

Upvotes: 6

Views: 3524

Answers (2)

Mohan Shanmugam
Mohan Shanmugam

Reputation: 690

In AWS JAVA SDK version 1.10.73 introduced class CloudFrontCookieSigner for Signed Cookies with custom policies. Using this class and methods we can generate cookies.

  1. CloudFront-Signature
  2. CloudFront-Policy
  3. CloudFront-Key-Pair-Id

    Note that Java only supports SSL certificates in DER format,so you will need to convert your PEM-formatted file to DER format.

    To do this, you can use openssl:

Command to Generate .der File from .pem

openssl pkcs8 -topk8 -nocrypt -in origin.pem -inform PEM -out new.der -outform DER 

Reference:- http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/CFPrivateDistJavaDevelopment.html

String privateKeyFilecdr = "/home/ec2-user/cookie.der";
String distributionDomain = "xxxxxxxx.cloudfront.net";
String s3ObjectKey = "signed-cookie.png";
String distributionid = "X4X4X4Y5Y5"; //Cloud Front Distribution id
String KeyFileId = "MPSIKFGHLMNSTOP" //AWS PEM KEY FILE ID
Date expiresOn = DateUtils.parseISO8601Date("2012-11-14T22:20:00.000Z");

String policyResourcePath = "https://" + distributionDomain + "/" + s3ObjectKey;
File privateKeyFile = new File(privateKeyFilecdr);

CookiesForCannedPolicy cookies = null;

try {

    cookies = CloudFrontCookieSigner.getCookiesForCannedPolicy(policyResourcePath, KeyFileId, privateKeyFile, expiresOn);
        //  @SuppressWarnings({ "resource", "deprecation" })
            HttpClient client = new DefaultHttpClient();
             HttpGet httpGet = new HttpGet(SignerUtils.generateResourcePath(Protocol.https, distributionDomain, 
                     s3ObjectKey));


            httpGet.addHeader("Cookie", cookies.getExpires().getKey() + "=" + 
              cookies.getExpires().getValue());
             httpGet.addHeader("Cookie", cookies.getSignature().getKey() + "=" + 
              cookies.getSignature().getValue());
             httpGet.addHeader("Cookie", cookies.getKeyPairId().getKey() + "=" + 
              cookies.getKeyPairId().getValue());
             HttpResponse responsevalues = client.execute(httpGet);
            // System.out.println(responsevalues);

        } catch (InvalidKeySpecException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

Upvotes: 2

fensterkreuz
fensterkreuz

Reputation: 71

We were able to introduce signed cookies with custom policies using this library

http://www.jets3t.org/

You need three cookies created by your app as described here http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-setting-signed-cookie-custom-policy.html

Please read that carefully. Especially the part on how to create a policy.

The three cookies are:

  1. CloudFront-Policy
  2. CloudFront-Signature
  3. CloudFront-Key-Pair-Id

First create a policy

Date expirationTime = (new LocalDate()).plusYears(1).toDate();
String customPolicy = CloudFrontService.buildPolicyForSignedUrl(basePath, expirationTime, null, null);

//and assign it to a cookie

Cookie signedCookiePolicy = new Cookie("CloudFront-Policy", ServiceUtils.toBase64(customPolicy.getBytes()));
signedCookiePolicy.setMaxAge(365 * 24 * 60 * 60);
signedCookiePolicy.setPath("/");
response.addCookie(signedCookiePolicy);

The signature is the tricky part but all tools are available once you use this jets3t thing

byte[] signatureBytes = EncryptionUtil.signWithRsaSha1(getDerPrivateKey(), customPolicy.getBytes("UTF-8"));
String signature = ServiceUtils.toBase64(signatureBytes).replace('+', '-').replace('=', '_').replace('/', '~');
Cookie signedCookieSignagture = new Cookie("CloudFront-Signature",cdnSignService.signBaseUrl(basePath, expirationTime));
signedCookieSignagture.setMaxAge(365 * 24 * 60 * 60);
signedCookieSignagture.setPath("/");
response.addCookie(signedCookieSignagture);

The third cookie only holds the key-id of your AWS account.

Cookie signedCookieKeyPairId = new Cookie("CloudFront-Key-Pair-Id","YOUR_AWS_CF_KEY_ID");
signedCookieKeyPairId.setMaxAge(365 * 24 * 60 * 60);
signedCookieKeyPairId.setPath("/");
response.addCookie(signedCookieKeyPairId);

The above only introduces you to concepts of using the correct libs to create the signed cookies. Its not executable or runnable on its own.

Be nice, its my first overflow contribution..

Upvotes: 7

Related Questions