Using bearer token authentication with HTTP Live Streaming? - http-live-streaming

My scenario with expected outcome:
User logs into a web portal.
The web portal presents content which is allowed to be accessed by the user.
The user selects a piece of content, which directs their browser to the m3u8 file for that content.
Each piece of content has an encryption key. The m3u8 file includes a URL for the key for that video, which is a REST endpoint with a query string (e.g. https://www.mymediaserver.com/api/key/100
The REST API will deliver the key in raw form to the requester if and only if a bearer token is provided along with the request. The key used to process the token is the same as the key used for the frontend API (e.g. that lists video content available). In other words, the same Authorization header that the user agent provides with API requests to populate the frontend can also be used for key retrieval. (This is not ideal, but it's a start and this project is more proof-of-concept at this stage.)
The video player would include the Authorization header with the request, and thus receive the key and be able to play the content.
Here are my questions:
The intended use case is simply to play the video within the browser. I could use a <video> tag, or even just redirect the browser to the file to begin playing the content full-screen on its own, and the user would use the Back button after playback.
I haven't yet started building all of this out because I'm not sure how the video playback engine actually requests the key. Is there a way to modify the HTTP request used to get the key, such that I can add the Authorization header?
Or, perhaps, does the video player automatically add the appropriate existing Authorization header?
Theories I've had:
I could dynamically generate the m3u8 file, adding the bearer token as a query string parameter. But, I'd then have to figure out how to get my REST endpoint to read the bearer token from the query string instead of from the headers. This would be an extra step.
I could generate my own one-time-use key retrieval strings and combine it with the above idea, but I then have to add the extra infrastructure to store the keys, expire them upon use, etc.
The summary question:
How do I implement bearer tokens when setting up a REST-style endpoint which will provide decryption keys for HLS video packages?
Notes:
The backend API is a C# ASP.NET Web API project.
The frontend for video selection is Angular.
I only plan to support iOS for now for this project.
I am aware that particularly crafty users may be able to figure out how to retrieve the keys. I'm trying to prevent casual downloading of video content from the server. (I fully realize you can't prevent copying, but you can prevent casual, easy copying.)
This is currently just a proof-of-concept idea for an internal video hosting platform that would make it at least challenging to retrieve video content for playback outside of the web site and without authentication.

Related

How do I manage and protect my Streaming Locators from Azure Media Services?

Background:
I have an Azure Media Service setup with a video uploaded and encoded. To access this video I've created a Streaming Locator in Azure Portal. With this Locator I can stream the video.
Problem:
How do I make it so that only my website can stream that video? I don't want other website to take my Locator and use it in their players because that would mean I'm paying for their streaming traffic.
Is DRM the solution to this problem or do I need to create Locators on-demand when a user firsts clicks on a video and then delete it afterwards?
I've looked into API authentication but that requires a Client Secret which might be problematic on an Angular website. Orr user authentication which is odd to require just for browsing videos.
Thye typical workflow for this would be to use just Clear Key AES content protection and not try to use DRM which has a lot of issues in setting up and getting players to work correctly. Clear Key still has its player support issues on iOS for example, but it is the easiest way to pull off what you are trying to do.
The workflow would be to set up content protection for the asset and use AES Clear Key on the Streaming Locators. Your audience would have to login and authenticate on your web site, which would provide them with a JWT token to play back and decrypt the media.
I dont have a complete example, but this sample in the Javscript SDK shows how to enable clear key encryption and use a JWT token.
https://github.com/Azure-Samples/media-services-v3-node-tutorials/blob/main/Streaming/StreamFileWithAESClearKey/index.ts
Note that it does not cover where you get the JWT token from exactly - it is using a sample token really. You would have to set up a service (Azure function) that does the authentication of the user and provides them with a valid JWT token for playback. That's left up to you, as there are lots of security layers that have to be considered which would be too complicated for sample code.
To use AES Clear Key you follow these steps:
Create a ContentKeyPolicy with the claims you want to use in the token. That can be issuer, audience, etc. You set the primary verification key on this policy and the restriction type is set to token type of JWT
When you want to publish a video, you create a new Streaming Locator for it and set the "DefaultContentKeyPolicy" on the streaming locator to point the the name of the ContentKeyPolicy you created in step 1.
Then on the client side, when a customer logs into your site or selects a video - you can create the JWT token for that user and pass it into the player. This is demonstrated in the sample above.
There is also a .NET C# version of that same sample flow up here if you prefer:
https://github.com/Azure-Samples/media-services-v3-dotnet/tree/main/ContentProtection/BasicAESClearKey

How to fetch api key when it is a part of the request headers [javascript nodeJS]?

I have endpoints to a site, e.g 'click here', I have also sniffed the api token needed and the auth value to view it.
As shown, I want to find out the api token without having to manually enter it in using a request. How would I got about doing this? P.S There is literally no other response headers that give this API, yet all requests need it to be successfully executed.
The API tokens are part of the site's security mechanism. How to use those vary based on what kind of technique is being used on the server side. Some sites that want others to use their APIs disclose the documentation.
Thats the only legal/moral way to find those. For sites like facebook, you just have to register your app with them and they give you API key. Some sites ask for OAuth, some just ask for you to include the key as URL parameter.
So the legal/moral way would be to ask them how you can access their APIs.

Retrieving public data using YouTube Analytics API

I would like to create a website which will allow users to input a YouTube URL, and will then generate statistics on the video or channel.
I have researched on the YouTube Analytics API, however I am encountering errors after following the https://developers.google.com/youtube/analytics/v1/sample-application. I am being given a "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup." Error.
What I am after is an easy way to GET HTTP url requests, which will provide me with basic analytics (details which are public, such as likes, views etc.) So I could just execute this GET Request on the YouTube URL which is entered.
Any help would be greatly appreciated.
sounds like you need to follow the instructions and register your app
from https://developers.google.com/youtube/v3/
Register your application with Google so that it can submit API requests.
this page has the details
https://developers.google.com/youtube/registering_an_application
Obtaining authorization credentials
Your application must have authorization credentials to be able to use the YouTube Data API. This document describes the different types
of authorization credentials that the Google Developers Console
supports. It also explains how to find or create authorization
credentials for your project.
Create your project and select API services
Go to the Google Developers Console.
Select a project.
In the sidebar on the left, select APIs & auth. In the list of APIs, make sure the status is ON for the YouTube Data API v3.
In the sidebar on the left, select Credentials.
The API supports two types of credentials. Create whichever credentials are appropriate for your project:
OAuth 2.0: Your application must send an OAuth 2.0 token with any request that accesses private user data. Your application sends a
client ID and, possibly, a client secret to obtain a token. You can
generate OAuth 2.0 credentials for web applications, service accounts,
or installed applications.
Learn more
API keys: A request that does not provide an OAuth 2.0 token must send an API key. The key identifies your project and provides API
access, quota, and reports.
If the key type you need does not already exist, create an API key by selecting Create New Key and then selecting the appropriate key
type. Then enter the additional data required for that key type.

How to secure my REST-API?

I have an api build with node.js & express.js. For now I have a unsecured api where anyone can GET,POST,PUT,DELETE records.
I am facing following problem. My rest api should not authenticate users but applications. E.g. my mobile application should have a valid token to access the api. Same for web application.
Another user case: my api will be used by another application that only uses one single rest call. So somewhere in the code I don't know in an application I don't know (for most part) a rest call on my api will be triggered. How can I secure such access, since no cookies or sessions are involved?
My first thought was, create a user and a password. Each api call (via https) must contain the credentials. Password may be hashed. However I read this
Usernames and passwords, session tokens and API keys should not appear
in the URL, as this can be captured in web server logs and makes them
intrinsically valuable.
from https://www.owasp.org/index.php/REST_Security_Cheat_Sheet
Any suggestions on this? I read about oauth but this involves redirections and I cannot imagine how this would work with a mobile app e.g. on android.
You can use RSA encryption for this, have a look at ursa module for node.
A simplified process of using this is... Arrange you client applications to encrypt a secret password with a public key and on the server side decrypt it with a private one, check if the secret is what you expect and act accordingly...
There are plenty of articles about using rsa in applications, I am sure you will be able to pick up a more definite explanation of how to work it if you just google.
EDIT
I have just bumped into this post which has a more detailed write-up on this question.
There is a question of how applications get to know a username/password in the first place, but if you are OK with the general idea (which is safe, as long as you consider the environment in which the application runs to be safe), then you don't need to worry about username/passwords in URLs: simply use https instead of https.
https is encrypted so that only the 2 endpoints (the client and your API) can read even the URL. Any router/proxy/server in between sees only encrypted data and has no means of accessing your username/passwords.
Instead of a username/password, btw, just use an "Access Token", which is a long (read: hard to guess) string, and assign one access token per application. In your end, you keep the list of valid tokens in a DB, and authenticate against that. You can even attach expiry dates to those strings, if you wish so.
Adding access token as part of an https:// url is common practice.

How do I secure REST API calls?

I'm developing the restful web app that using some popular web framework on the backend, say (rails, sinatra, flask, express.js). Ideally, I want to develop client side with Backbone.js. How do I let only my javascript client side interact with those API calls? I don't want those API calls to be public and be called by curl or simply by entering the link on browser.
As a first principle, if your API is consumed by your JS client, you have to assume, that it is public: A simple JS debugger puts an attacker into a position, where he can send a byte-for-byte identical request from a tool of his choice.
That said, if I read your question correctly, this is not, what you want to avoid: What you really don't want to happen is, that your API is consumed (on a regular basis) without your JS client being involved. Here are some ideas on how to if not enforce, then at least encourage using your client:
I am sure, your API has some sort of authentication field (e.g. Hash computed on the client). If not, take a look at This SO question. Make sure you use a salt (or even API key) that is given to your JS client on a session basis (a.o.t. hardcoded). This way, an unauthorized consumer of your API is forced into much more work.
On loading the JS client, remember some HTTP headers (user agent comes to mind) and the IP address and ask for reauthentication if they change, employing blacklists for the usual suspects. This forces an attacker to do his homework more thoroughly again.
On the server side, remember the last few API calls, and before allowing another one, check if business logic allows for the new one right now: This denies an attacker the ability to concentrate many of his sessions into one session with your server: In combination with the other measures, this will make an abuser easy detectable.
I might not have said that with the necessary clarity: I consider it impossible to make it completely impossible for an abuser to consume your service, but you can make it so hard, it might not be worth the hassle.
You should implement some sort of authentication system. One good way to handle this is to define some expected header variables. For example, you can have an auth/login API call that returns a session token. Subsequent calls to your API will expect a session token to be set in an HTTP header variable with a specific name like 'your-api-token'.
Alternatively many systems create access tokens or keys that are expected (like youtube, facebook or twitter) using some sort of api account system. In those cases, your client would have to store these in some manner in the client.
Then it's simply a matter of adding a check for the session into your REST framework and throwing an exception. If at all possible the status code (to be restful) would be a 401 error.
There's an open standard now called "JSON Web Token",
see https://jwt.io/ & https://en.wikipedia.org/wiki/JSON_Web_Token
JSON Web Token (JWT) is a JSON-based open standard (RFC 7519) for
creating tokens that assert some number of claims. For example, a
server could generate a token that has the claim "logged in as admin"
and provide that to a client. The client could then use that token to
prove that they are logged in as admin. The tokens are signed by the
server's key, so the server is able to verify that the token is
legitimate. The tokens are designed to be compact, URL-safe and usable
especially in web browser single sign-on (SSO) context. JWT claims can
be typically used to pass identity of authenticated users between an
identity provider and a service provider, or any other type of claims
as required by business processes.[1][2] The tokens can also be
authenticated and encrypted.[3][4]
Set a SESSION var on the server when the client first loads your index.html (or backbone.js etc.)
Check this var on the server-side on every API call.
P.S. this is not a "security" solution!!! This is just to ease the load on your server so people don't abuse it or "hotlink" your API from other websites and apps.
Excuse me #MarkAmery and Eugene, but that is incorrect.
Your js+html (client) app running in the browser CAN be set up to exclude unauthorized direct calls to the API as follows:
First step: Set up the API to require authentication. The client must first authenticate itself via the server (or some other security server) for example asking the human user to provide the correct password.
Before authentication the calls to the API are not accepted.
During authentication a "token" is returned.
After authentication only API calls with the authentication "token" will be accepted.
Of course at this stage only authorized users who have the password can access the API, although if they are programmers debugging the app, they can access it directly for testing purposes.
Second step: Now set up an extra security API, that is to be called within a short limit of time after the client js+html app was initially requested from the server. This "callback" will tell the server that the client was downloaded successfully. Restrict your REST API calls to work only if the client was requested recently and successfully.
Now in order to use your API they must first download the client and actually run it in a browser. Only after successfully receiving the callback, and then user entry within a short frame of time, will the API accept calls.
So you do not have to worry that this may be an unauthorized user without credentials.
(The title of the question, 'How do I secure REST API calls', and from most of what you say, that is your major concern, and not the literal question of HOW your API is called, but rather BY WHOM, correct?)
Here's what I do:
Secure the API with an HTTP Header with calls such as X-APITOKEN:
Use session variables in PHP. Have a login system in place and save the user token in session variables.
Call JS code with Ajax to PHP and use the session variable with curl to call the API. That way, if the session variable is not set, it won't call and the PHP code contains the Access Token to the API.

Resources