views:

218

answers:

5

Hi,

I've developed an application that is currently in the app store weighing in at just over 400MB. The main reason for this is that the app features lots of video which at the moment is baked into the binary.

For our next release we'd like to externalise this video, allowing the user to download the videos they'd like to keep on-demand, and delete the videos they've already watched. We're currently sourcing a CDN etc. and are now trying to work out how we secure this video.

The problem is, people who don't have the App will be able to download our videos meant for paying customers over the web if we just use standard urls to the mp4s. Is there any way we can secure these videos so that they can't be easily stolen? (I say "easily" as I'm sure once the videos have been downloaded people can always find ways of tearing them out of the app and putting them on bit torrent, but if they ARE stealing, it would be good if we didn't have to pay for the bandwidth...)

I was thinking that maybe we could somehow generate one-time urls which are requested using some kind of hash of the UDID of the device and then verified on a server, and then allowing the user to download through that. Or is that just nonsense?

What's the sensible solution to this problem?

Thanks in advance,

UPDATE: Unfortunately I can't use the in app purchase mechanisms as this app is well and truly out there, so need to find my own way of securing our content.

Would this work as a solution: (forgive my vernacular, usually a client-side coder)

1) Server-side, a random token is generated every 5-10 mins which can be requested by the app.

2) Once the app has this token, it uses this, the device UDID, and a secret-key baked within the app to generate another token via md5 or something

3) The device makes a request to the server with the NEW token and the device UDID

4) The server attempts to verify by repeating the same process server-side (with same magic key) and seeing if the token it generates using the udid provided matches the one the app made the request with. if so, it delivers the file.

Would this work?

+1  A: 

You could offer the app for free and provide the videos as In-App Purchase. There is an API that your server can use to verify the IAP receipts, to make sure the customer actually legitimately purchased the item through Apple.

Kevin Ballard
A: 

You could always have the iPhone app send a request in to the server that includes its IP address; then, on your server, return a URL for the download that only permits access to that IP.

Jeff Kelley
A: 

Read the Server Product Model and Verifying Store Receipts sections of the In App Purchase Programming Guide. It explains how to do this in a fairly secure way.

Ben S
A: 

I find that encrypting data works well. Have the iPhone send a random key, encrypt with that key on the server, decrypt on the iPhone. Use AES, 128bit in CBC mode. If you want better performance you might consider encrypting only part of the file, say 10% with blocks spread evenly over the file, it's a tradeoff that the resultant video will not be worth watching vs saved crypto time.

zaph
This sounds interesting... although it sounds quite heavy on performance. We've 1000s upon 1000s of installs and it sounds like we'd be doing a lot of server side encryption.
Tricky
+2  A: 

I think your suggestion is consistent with what I would suggest.

Take a look at the Amazon S3 approach to link expiration for an example. I wrote the following helper in PHP to generate these links (works along with Zend Framework's Zend____Crypt____Hmac, please see http://framework.zend.com/wiki/pages/viewpage.action?pageId=35309 for more information):

    public function getExpiredQueryString($objectName, $expireTime, $bucketName){
       $stringToSign = "GET\n\n\n$expireTime\n/$bucketName/tracks/$objectName";
       $hashedSignature = Zend_Crypt_Hmac::compute(self::AMAZON_AWS_SECRET_KEY, 'sha1', utf8_encode($stringToSign));
       $signature = urlencode($this->_hex2b64($hashedSignature));

       $url = 'http://' . $bucketName . '.s3.amazonaws.com/tracks/' . $objectName . '?AWSAccessKeyId=' . self::AMAZON_AWS_KEY . '&Expires=' . $expireTime . '&Signature=' . $signature; 
       return $url;
    }

The following is the contents of _hex2b64 (not original, but helpful to see):

    private function _hex2b64($str){
          $raw = '';
          for ($i=0; $i < strlen($str); $i += 2)
          {
              $raw .= chr(hexdec(substr($str, $i, 2)));
          }
          return base64_encode($raw); 
     }

The long and short of it is that you can create a tokenized link structure that may have a ttl in a database table (for example) that is used to authenticate your user and authorize the download / stream of your asset.

As far as scalability is concerned, you will need to explore all of your options including choice of database, web server, operating system, overall efficiency of your server side code base, etc. This is a larger conversation.

Hope this helps!

Paul Shoemaker