HTTP live streaming with encryption - ios

I am trying to understand how the HTTP Live Streaming protocol that Apple supports on their iOS devices as well as on Safari protects the key that unlocks the content.
The way I understand it, the .m3u8 file holds the whole thing together and references the content (in MPEG2 TS container, AES 128 encrypted) and the key to the TS file.
Like in this example:
#EXTM3U
#EXT-X-MEDIA-SEQUENCE:7794
#EXT-X-TARGETDURATION:15
#EXT-X-KEY:METHOD=AES-128,URI="https://priv.example.com/key.php?r=52"
#EXTINF:15,
http://media.example.com/fileSequence52-1.ts
#EXTINF:15,
http://media.example.com/fileSequence52-2.ts
#EXTINF:15,
http://media.example.com/fileSequence52-3.ts
#EXT-X-KEY:METHOD=AES-128,URI="https://priv.example.com/key.php?r=53"
#EXTINF:15,
http://media.example.com/fileSequence53-1.ts
Assuming a browser based playback where the <video> element is fed a m3u8 file in the "src" attribute. In this case, even if the key is delivered via https, how can I make sure that the user does not simply enter the https URL in his browser and saves the key to his hard drive? The way I understand the mechanism, the key download is done by the <video> tag as it plays the m3u8 source using the browser's https stack -- how is the legitimate client inside the browser distinguished from the user just typing it into the address bar? This must be really obvious, but I just don't see it...
All the best,
dansch

how can I make sure that the user does not simply enter the https URL in his
browser and saves the key to his hard drive?
You can have an SSL client key/certificate in the app, and thereby authenticate "the app" for playing the content. Then you'd avoid leaking your content to other devices than your app.
But that would mean you'd need to somehow hide your ssl-key/passphrase inside the app. And there are unfortunately also problems getting the video player on iOS to use the ssl key authentication...

Some interesting pointers can be found here: https://developer.apple.com/library/content/documentation/AudioVideo/Conceptual/AirPlayGuide/EncryptionandAuthentication/EncryptionandAuthentication.html
This will require custom work in iOS, but also in Android and web players.
Serve keys from a protected HTTPS realm. Before playback begins, your app can use NSURLConnection to authenticate itself, providing credentials that are kept hidden.
Use cookies over HTTPS. Your app can make a connection to an HTTPS server and authenticate the app in an app-defined way. Your server can then issue a cookie that applies to the key URLs. You should set the cookie to expire long after playback is complete. The server must then require the presence of a valid session cookie in future GET requests for the keys.
For maximum reliability, if the expiration date is in the near future, the server should update the cookie’s expiration date in its response to future GET requests.
Specify the keys in the .m3u8 files using an app-defined URL scheme. The app should register a custom NSURLProtocol to handle requests for those URLs. The player then calls back into your app when it needs to load a key URL; your app can then obtain the key using a secure side channel and can provide it to the player.
If you're only targeting iOS, then you should use Apple Fairplay DRM which handles the authentication of the keys.

The answer is not obvious at all. You're essentially required to invent your own key delivery if you want it to be secure. One option is to set a cookie for authorized users, and to verify the cookie in the key server. This will keep someone from being able to just use the key url to bypass your security.
Keep in mind that it still only takes one legitimate client to leak the key for your security to be invalidated.

The best way is to use Apple HLS supported encryption.HLS support 128 bit AES encryption and the client player need to decode the stream.

how is the legitimate client inside the browser distinguished from the user just typing it into the address bar?
Interesting distinction, the suggestion is the browser the user is using is legitimate when playing the video embedded in the web page, and illegitimate when accessed via the address bar.
But there is no actual distinction there, I don't think you are missing anything.
How would you give rights to a browser and not a user? Cannot a user just write their own browser?
I know, it seems unlikely a user would write a browser, but these types of discussions are always about unlikely scenarios anyway. An unlikely user might find a way to view the m3u8 as plain text, they might download the keys directly, they may use those keys to unencrypt and eventual piece together the video segments.
Or, something that is far more likely - use screen recording software to copy any video that they can play in the browser.
In my opinion, if a user is authorized to play the video, they can, unfortunately also copy the video - because there's no way to prevent the display of the video being redirected into something that is no longer encrypted - at least in the environment of a desktop computer that is playing a video in a browser.
Anyway, my understanding is that you can protect the keys by requiring authorization to get the keys, but if the user has that authorization, then - well they can get the keys.

Have a look here
https://datatracker.ietf.org/doc/html/draft-pantos-http-live-streaming-13#section-6.3.6
the playlist will have to specify a key tag for each segment. so a player will be able to identify a key required to decrypt a segment.
Browsers do not support DRM out of the box. HTML5 specify that it can be done via EME (Encrypted media extensions) whoever not implemented atm.
so your options are:
use flash and fetch the keys via your own algorithm
write your own plugins(extension)
be big like Netflix and agree with browser
vendors to support your DRM aka content protection and key
distribution.

Apple's implementation of HTTP live streaming does not support DRM.
See FAQ number 16 on https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/StreamingMediaGuide/FrequentlyAskedQuestions/FrequentlyAskedQuestions.html

Related

Service to host streaming videos for mobile access where urls are not trackable

I'm building an iOS app and Android app that will display a series of private videos. Someone will purchase the app for x amount and then have access to the videos through that app only.
I already know a couple of ways to do that part. But the real trick is hiding the video urls to traffic sniffers/etc. I don't want anyone to be able to detect the video urls, or at least the endpoint will reject a request without an auth token.
So I could build my own Node/Express server, incorporate wowza maybe with Amazon to store the files - but that is a lot of work.
So what is the simplest solution to stream my videos to mobile without people being able to load up the videos outside of the app?
It looks like you'll need to implement some sort of authentication system, so that even if they get the video url somehow, they will be unable to view it without the authentication key.
Your videos should be hosted in a directory on your server that is inaccessible from the web. Then use some sort of index page which takes a parameter for the video ID and does the authentication before serving up the video file contents.

iOS broadcasting live to Azure Media Services

I am trying to make a Periscope-like app (not practically, but technical requirements are alike) where users can start streaming quickly from their iPhone to an unknown amount of users, both mobile. I am trying to use Azure Media Services for live video streaming, but even after reading pages of documentation I'm stuck.
I'm using VideoCore (https://github.com/jgh-/VideoCore) to publish from iOS device to the RTMP server. On local (using Wowza) I can just connect to the local server with my set username and password as shown:
vcSession = [[VCSimpleSession alloc] initWithVideoSize:CGSizeMake(1280, 720) frameRate:30 bitrate:1000000 useInterfaceOrientation:NO];
[self.view addSubview:vcSession.previewView];
vcSession.previewView.frame = self.view.bounds;
vcSession.delegate = self;
[vcSession startRtmpSessionWithURL:#"rtmp://172.20.10.2:1935/live?rtmpauth=test:test" andStreamKey:#"test"];
Where the rtmpauth parameter has the username:password format, which I've set both to test on my local server. It works. In Azure, I've created a channel named test, and I've got the following Ingest URL:
rtmp://test-myappname.channel.mediaservices.windows.net:1935/live/some-long-hexadecimal-string
In Wirecast, I'm able to stream to URL (though EXTREMELY slow and connection frequently lost, don't know why) by selecting Azure Media Services in Output Settings and typing that Ingest URL. In iOS, I have no idea how to connect to Azure Media Services.
In startRtmpSessionWithURL:andStreamKey: method, I've tried all the possible combinations of URL and a stream key, but no luck. I have no idea what my username/password is (nothing is given at the Azure side), what the stream key is (I've tried test, live, empty string) and what that long hexadecimal string is (some sources say that it's called a locator, though).
What is the correct format of RTMP URL and stream key when connecting to Azure Media Services for streaming?
I'll find someone to help you. I think you are just missing a stream name after the long hex string in the URL.
rtmp://test-myappname.channel.mediaservices.windows.net:1935/live/some-long-hexadecimal-string/[YOUR-CUSTOM-STREAM-NAME-Anything Really!]
Also, do you have any control over the encoding settings? Its possible that some encoding settings are not right. We have not tested with that VideoCore library, so it may also be that there is a slight variation in the RTMP protocol (since it is very poorly documented and there is a lot of missing information out there).
I'm curious why your Wirecast setup is having trouble as well. That doesn't sound good to start with. Network issue? Are you setting it to the proper Encoder preset with H.264 and NOT x264 set?
Review your settings in Wirecast against Cenk's blog post here: http://azure.microsoft.com/blog/2014/09/18/azure-media-services-rtmp-support-and-live-encoders/

How QuickTime Player(or actually CoreMedia) works while playing HTTP stream?

I'm working in analyze the live tv streaming from TVB(HK)
Well known the url(s) to watch them are:
http://token.tvb.com/stream/live/hls/mobilehd_hdj.smil
http://token.tvb.com/stream/live/hls/mobilehd_j2.smil
http://token.tvb.com/stream/live/hls/mobilehd_inews.smil
We can directly watch by url(s) above in any apple native software(such as QuickTime, Safari) no matter in Mac or iOS. And also known they are using AppleCoreMedia framework. But it won't works in other platforms. You will get HTTP 200 but "access denied" in content.
I analyzed all the traffic about it. I found that the HTTP request(by CoreMedia) to the endpoint(the server really provide video) contain a header:
x-playback-session-id: xxxxx
The video arrived instead of "access denied" message after I add the header manually(I tried in Chrome or Firefox), no matter what the user-agent is. But the problem occur is, I can't find any other place contain this header in earlier request(since it redirected a few times) in the traffic I dumped. So I'm curious what AppleMediaCore did when it playing http stream? Did it calculated a session id(or hash) or it got the id from somewhere i missed?
p.s. I'm not sure TVB do a IP check or not. Since they had a copyright or legal concern so maybe blocked to access from somewhere. You maybe need a VPN.
Finally I found the answer. The x-playback-session-id is a UUID comes from the AVPlayer Framework. But in fact this won't affect I got token or not. The real token is HTTP cookie.
Authorization process I found:
token.tvb.com redirect to vod server with a couple of GET value
VOD Server check GET value and set cookie if valid. Also respond m3u8 file(contains several different quality stream url)
Player will request one or more url in m3u8 to retrieve streams. VOD server will then check cookie and user-agent as token.
In the coming time player will keep using the cookie and user-agent as token to request ts files.
p.s. HLS from TVB for android has different process I haven't figure out. But I found that if user-agent contains "Android" then authorization will fail.

How to stream video over secure connection on iOS

I can play a video from a local resource (on the device).
I can stream a video from the unprotected internet.
I can't stream from the company intranet (either from internal or externally)
Typical secure company network. Videos are stored in SharePoint 2007 lists (but I have url to the video file).
I've tried:
MPMoviePlayerController
MPMoviePlayerViewController
UIViewView (creating html on fly using the <video> tag and video url)
and I can't get anything to work. Heck, I can't even get it to work going directly to the link in Safari on the iPad. The only thing I haven't tried doing is downloading it as a file then playing locally. Due to a host of usability issue this would not be a preferred option.
There were 2 problems.
MPMoviePlayerController doesn't support all the challenge authentication which exists in NSURLConnection. The solution is to just do a "dummy" NSURLConnection somewhere inside your secure area, have it handle all the challenges and set it to store the information for the session. From here on out, MPMoviePlayerController or other connections which don't support the ins and outs of SSL requests will use the existing session.
A valid intermediate certificate had to be installed on the server. Something I never would have figured out myself. It exists as a small item in one of the guides under Secure connections.

How to get Airplay working with encrypted HTTPS streaming?

I´ve been struggling to get AirPlay to work with encrypted streams playing in AVPlayer.
Reading this page by Apple doesn´t do me much good.
Serve keys from a protected HTTPS realm. Before playback begins, your
app can use NSURLConnection to authenticate itself, providing
credentials that are kept hidden.
I could only get this to work in the simulator. Not on the device.
Use cookies over HTTPS. Your app can make a connection to an HTTPS
server and authenticate the application in an application-defined way.
Your server can then issue a cookie that applies to the key URLs. You
should set the cookie to expire long after playback is complete. The
server must then require the presence of a valid session cookie in
future GET requests for the keys.
For maximum reliability, if the expiration date is in the near future, the server should
update the cookie’s expiration date in its response to future GET requests.
Haven´t actually tried this since I don´t have direct access to the server setup, but I am going to if no other answers appear.
Specify the keys in the .m3u8 files using an application-defined URL
scheme. The app should register a custom NSURLProtocol to handle
requests for those URLs. The player then calls back into your app when
it needs to load a key URL; your app can then obtain the key using a
secure side channel and can provide it to the player.
This doesn´t seem to work because AVPlayer HTTP connections bypass the NSURLProtocol system completely. You just can´t intercept any of the HTTP requests made by the AVPlayer.
I would be eternally grateful if anyone has a way of solving the encryption key serving problem in a manner that works with AVPlayer and AirPlay.
Seems like the trouble I was wrestling with went away with the iOS 5.1.1 update and the following Apple TV update. The iOS 5.1.1 update was not enough to fix the issue on it´s own, but together with the subsequent Apple TV update all is fine and dandy once again.
It is now enough to implement your own loopback server as I have described in an earlier question.

Resources