Unable to play HLS m3u8 file with AWS CloudFront Signed Cookies - amazon-cloudfront

I am working on a project where I will need to play HLS encrypted video (.m3u8) file. I am using CloudFront and signed cookies to secure the content. I am able to play .m3u8 file without signed cookies but when I use signed cookies then cookies do not get send in requests.
I am using the alternate domain for CloudFront distribution and I confirm that apart from .m3u8 file I am able to access all other files using signed cookies.
After research, I found that if I set withCredentials to true like the following code then signed cookies will be send in request:
player.ready(function() {
player.src({
src: 'https://protected.example.com/output-plain/art.m3u8',
type: 'application/x-mpegURL',
withCredentials: true
});
});
This code works and signed cookies are getting send in request however I started getting a new error which is:
Access to XMLHttpRequest at 'https://protected.example.com/output-plain/art.m3u8undefined' from origin 'https://example.com' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
Then I found that I have to set Access-Control-Allow-Credentials to true. however, this does not work for me.
I am using video.js library, I have also tried hls.js and getting the same error and stuck at same place.
I am stuck on this issue for the last 7 days and I think AWS docs are really overwhelming, I have referred many questions on SO and issues on Github but still no luck. Hope someone will help me here.
Here is the screenshot of CloudFront distribution behavior:
And here is my php and js code; index.php:
<?php
header("Access-Control-Allow-Origin: https://protected.example.com");
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Max-Age: 1000");
header("Access-Control-Allow-Headers: X-Requested-With, Content-Type, Origin, Cache-Control, Pragma, Authorization, Accept, Accept-Encoding");
header("Access-Control-Allow-Methods: PUT, POST, GET, OPTIONS, DELETE");
?>
<!DOCTYPE html>
<html>
<head>
<link href="https://vjs.zencdn.net/7.10.2/video-js.css" rel="stylesheet" />
</head>
<body>
<video
id="video_player"
class="video-js"
controls
preload="auto"
poster="//vjs.zencdn.net/v/oceans.png"
data-setup='{}'
width=600 height=300>
</video>
<script src="https://vjs.zencdn.net/7.10.2/video.js"></script>
<script>
var player = videojs('video_player')
player.responsive(true);
player.ready(function() {
player.src({
src: 'https://protected.example.com/output-plain/art.m3u8',
type: 'application/x-mpegURL',
withCredentials: true
});
});
</script>
</body>
</html>
Here is S3 bucked CORS Policy:
[
{
"AllowedHeaders": [
""
],
"AllowedMethods": [
"POST",
"GET",
"PUT",
"HEAD"
],
"AllowedOrigins": [
"*"
],
"ExposeHeaders": []
}
]
Thank you in advance.

The answer is within the browser's error message, "The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'." Your S3 bucket's CORS policy cannot use a wildcard for the AllowedOrigins value.
Also your empty AllowedHeaders value may be removing the Host value from the preflight request check, so let's set it to a wildcard just to be safe.
If you update your S3 bucket's CORS policy to this, it should resolve the issue:
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"POST",
"GET",
"PUT",
"HEAD"
],
"AllowedOrigins": [
"https://example.com",
"https://protected.example.com"
],
"ExposeHeaders": []
}
]

Related

Single backend with multiple APIs

I have a single backend defined, for this example named myserver with a runtime url https://myserver.com. Also, I have "Authorization credentials" set for this backend:
The header x-custom-header is added with a secret value. Every request needs to provide this header.
My backend provides the following endpoints:
GET https://myserver.com/Devices
GET https://myserver.com/Devices/device-1
POST https://myserver.com/Devices
Get https://myserver.com/Weather?location=Vienna
...
Here comes the problem:
I want to provide multiple APIs specific for the data:
Devices Api with API URL suffix Devices:
https://mycompany-apim.azure-api.net/Devices
Weather Api with API URL suffix Weather:
https://mycompany-apim.azure-api.net/Weather
For some reason, I don't understand how I can achieve that with only a single backend without too much configuration hassle. I have configured <set-backend-service backend-id="myserver" /> but that obviously does not correctly resolve https://mycompany-apim.azure-api.net/Devices to GET https://myserver.com/Devices but only to GET https://myserver.com/.
Some solutions that might work:
Define a backend for each API. E.g. backend myserver-devices with the base url https://myserver.com/Devices
Problem: I don't want to have X backends configured the same way just with a different url ending.
Configure an rewrite-uri policy for each endpoint in each API.
Problem: Obviously, this would be even more configuration overhead.
Are there alternatives?
This can be achieved by creating one API e.g. 73219639 and the required operations:
It's important that each APIM operation has the same path e.g. /Devices:
https://rfqapiservicey27itmeb4cf7q.azure-api.net/Devices -> https://myserver.com/Devices
This is the simple working yaml:
openapi: 3.0.1
info:
title: '73219639'
description: ''
version: '1.0'
servers:
- url: 'https://rfqapiservicey27itmeb4cf7q.azure-api.net'
paths:
/Devices:
post:
summary: Devices
description: Devices
operationId: post-devices
responses:
'200':
description: OK
get:
summary: Devices
description: Devices
operationId: get-devices
responses:
'200':
description: OK
/Weather:
get:
summary: Weather
description: Weather
operationId: get-weather
responses:
'200':
description: OK
components:
securitySchemes:
apiKeyHeader:
type: apiKey
name: Ocp-Apim-Subscription-Key
in: header
apiKeyQuery:
type: apiKey
name: subscription-key
in: query
security:
- apiKeyHeader: []
- apiKeyQuery: []
Configure the Backend in the All operations policy with an existing backend:
<policies>
<inbound>
<base />
<set-backend-service backend-id="myserver-com" />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
Do not change/modify any other policy. It's working with the default ones.
GET Devices - Test:
HTTP request
GET https://rfqapiservicey27itmeb4cf7q.azure-api.net/Devices HTTP/1.1
Host: rfqapiservicey27itmeb4cf7q.azure-api.net
Ocp-Apim-Subscription-Key: ••••••••••••••••••••••••••••••••
Ocp-Apim-Trace: true
Trace: set-backend-service (18.701 ms)
{
"message": "Backend service URL was changed.",
"oldBackendServiceUrl": "https://rfqapiservicey27itmeb4cf7q.azure-api.net/",
"newBackendServiceUrl": "https://myserver.com/",
"request": {
"url": "https://myserver.com/Devices"
}
}
Trace: forward-request (0.127 ms)
{
"message": "Request is being forwarded to the backend service. Timeout set to 300 seconds",
"request": {
"method": "GET",
"url": "https://myserver.com/Devices",
"headers": [
{
"name": "Host",
"value": "myserver.com"
},
{

Express.js GET request failing when proved with longer request

I have a big deeply nested JS object that is send to the Express.js server after it gets JSON.strify() and turned it into an string. I tried the same thing with a smaller and shallowly nested object, then it worked fine.
Here's the big object:
{
channelName: 'PewDiePie',
channelTag: 'UC-lHJZR3Gqxm24_Vd_AJ5Yw',
channelLogoLink: 'https://yt3.ggpht.com/a/AATXAJzlZzr16izsGHBCHIkO3H7n-UiHyZPCJFEPiQ=s88-c-k-c0xffffffff-no-rj-mo',
unseenVideoTitles: [
[
'I Made The WORST Minecraft MISTAKE There Is. .. - Part 40',
'The MOST Dangerous Place In Minecraft!',
'I Found The New Biome in Minecraft! (Nether Update)',
'I\'m Back in Minecraft! - Part 39'
]
],
videoThumbnailLinks: [
[
'https://i.ytimg.com/vi/8HHZiNdrZGA/mqdefault.jpg',
'https://i.ytimg.com/vi/evcMQ7Lk8NU/mqdefault.jpg',
'https://i.ytimg.com/vi/aOXAtnb-grk/mqdefault.jpg',
'https://i.ytimg.com/vi/1B1f9PGLbIs/mqdefault.jpg'
]
],
videoLinks: [
[
'https://www.youtube.com/watch?v=8HHZiNdrZGA',
'https://www.youtube.com/watch?v=evcMQ7Lk8NU',
'https://www.youtube.com/watch?v=aOXAtnb-grk',
'https://www.youtube.com/watch?v=1B1f9PGLbIs'
]
],
videoUploadTime: [
[
'2020-03-13',
'2020-03-31',
'2020-03-25',
'2020-03-06'
]
]
}
Here's the code in Express.js:
router.get('/query/:stringifiedObj', (req, res) => {
const retrievedObj = JSON.parse(req.params.stringifiedObj);
const uid = retrievedObj.uid;
delete retrievedObj.uid;
console.log(uid, retrievedObj);
res.status(200).send(uid);
});
The error I get is:
HTTP/1.1 404 Not Found
X-Powered-By: Express
Content-Security-Policy: default-src 'none'
X-Content-Type-Options: nosniff
Content-Type: text/html; charset=utf-8
Content-Length: 955
Date: Sat, 04 Apr 2020 11:42:17 GMT
Connection: close
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot GET /api/query/%7B%22channelName%22:%22PewDiePie%22,%22channelTag%22:%22UC-lHJZR3Gqxm24_Vd_AJ5Yw%22,%22channelLogoLink%22:%22https://yt3.ggpht.com/a/AATXAJzlZzr16izsGHBCHIkO3H7n-UiHyZPCJFEPiQ=s88-c-k-c0xffffffff-no-rj-mo%22,%22unseenVideoTitles%22:[[%22I%20Made%20The%20WORST%20Minecraft%20MISTAKE%20There%20Is.%20..%20-%20Part%2040%22,%22The%20MOST%20Dangerous%20Place%20In%20Minecraft!%22,%22I%20Found%20The%20New%20Biome%20in%20Minecraft!%20(Nether%20Update)%22,%22I%27m%20Back%20in%20Minecraft!%20-%20Part%2039%22]],%22videoThumbnailLinks%22:[[%22https://i.ytimg.com/vi/8HHZiNdrZGA/mqdefault.jpg%22,%22https://i.ytimg.com/vi/evcMQ7Lk8NU/mqdefault.jpg%22,%22https://i.ytimg.com/vi/aOXAtnb-grk/mqdefault.jpg%22,%22https://i.ytimg.com/vi/1B1f9PGLbIs/mqdefault.jpg%22]],%22videoLinks%22:[[%22https://www.youtube.com/watch</pre>
</body>
</html>
Here's the string:
{"channelName":"PewDiePie","channelTag":"UC-lHJZR3Gqxm24_Vd_AJ5Yw","channelLogoLink":"https://yt3.ggpht.com/a/AATXAJzlZzr16izsGHBCHIkO3H7n-UiHyZPCJFEPiQ=s88-c-k-c0xffffffff-no-rj-mo","unseenVideoTitles":[["I Made The WORST Minecraft MISTAKE There Is. .. - Part 40","The MOST Dangerous Place In Minecraft!","I Found The New Biome in Minecraft! (Nether Update)","I'm Back in Minecraft! - Part 39"]],"videoThumbnailLinks":[["https://i.ytimg.com/vi/8HHZiNdrZGA/mqdefault.jpg","https://i.ytimg.com/vi/evcMQ7Lk8NU/mqdefault.jpg","https://i.ytimg.com/vi/aOXAtnb-grk/mqdefault.jpg","https://i.ytimg.com/vi/1B1f9PGLbIs/mqdefault.jpg"]],"videoLinks":[["https://www.youtube.com/watch?v=8HHZiNdrZGA","https://www.youtube.com/watch?v=evcMQ7Lk8NU","https://www.youtube.com/watch?v=aOXAtnb-grk","https://www.youtube.com/watch?v=1B1f9PGLbIs"]],"videoUploadTime":[["2020-03-13","2020-03-31","2020-03-25","2020-03-06"]]}

Cross origin error between angular cli and flask

first i post the user id and password from the UI(angular) to flask
public send_login(user){
console.log(user)
return
this.http.post(this.apiURL+'/login',JSON.stringify(user),this.httpOptions)
.pipe(retry(1),catchError(this.
handleError))
}
next i received it from backend
backend error
all the operations are working properly but at console the cross origin error is raising
Error at UI console
the http option in Ui side is mentioned below
constructor(private http: HttpClient) { }
// Http Options
httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': 'http://localhost:9000',
'Access-Control-Allow-Methods': "GET,POST,OPTIONS,DELETE,PUT",
'X-Requested-With': 'XMLHttpRequest',
'MyClientCert': '', // This is empty
'MyToken': ''
})
}
the cors declared at backend is metioned below
cors = CORS(app, resources={r"/login": {"origins": "*"}})
#app.route('/login', methods=['GET','POST'])
def loginForm():
json_data = ast.literal_eval(request.data.decode('utf-8'))
print('\n\n\n',json_data,'\n\n\n')
im not able to find were is the problem is raising
Note: cross origin arising in the time of login process other wise in the consecutive steps
add below code in your app.py
CORS(app, supports_credentials=True)
and from frontend use
{with-credentials :true}
it will enable the communication between the frontend and backend
To me it seems the call is not leaving the front end (at least in my experience it is like this), because the browsers are securing this.
Create a new file proxy.conf.json in src/ folder of your project.
{
"/backendApiUrl": { <--- This needs to reflect the server backend base path
"target": "http://localhost:9000", <-- this is the backend server name and port
"secure": false,
"logLevel": "debug" <--- optional, this will give some debug output
}
}
In the file angular.json (CLI configuration file), add the following proxyConfig option to the serve target:
"projectname": {
"serve": {
"builder": "#angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "your-application-name:build",
"proxyConfig": "src/proxy.conf.json" <--- this is the important addition
},
Simply call ng serve to run the dev server using this proxy configuration.
You can read the section Proxying to a backend server in https://angular.io/guide/build
Hope this helps.

Google safe browse API lookup Node.js

I am having trouble getting a google safe search lookup working. Here is the code I am trying and I am always getting {} in the response
var request = require("request-promise")
var body = {
"client": {
"clientId": "myclientid",
"clientVersion": "1.0"
},
"threatInfo": {
"threatTypes": ["MALWARE"],
"platformTypes": ["WINDOWS", "LINUX"],
"threatEntryTypes": ["URL"],
"threatEntries": [
{"url": "http://some-malicious-url"}
]
}
}
var options = {
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
},
method: "POST",
url: "https://safebrowsing.googleapis.com/v4/threatMatches:find?key=my-api-key",
form: body
}
request(options).then(function (data){
console.log(data)
})
Not sure if I understood the docs correctly or if I am missing any param from my request. I have tried with different urls. Tried searching for malicious urls form web which were identified by my browser as malicious but those also returned blank response. Here is the documentation I am following
I also tried their threatLists:list API and that always gives an error
curl -XGET https://safebrowsing.googleapis.com/v4/threatLists:list?key=my_api_key
Here is the output that I get:
<!DOCTYPE html>
<html lang=en>
<meta charset=utf-8>
<meta name=viewport content="initial-scale=1, minimum-scale=1, width=device-width">
<title>Error 404 (Not Found)!!1</title>
<style>
*{margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{background:#fff;color:#222;padding:15px}body{margin:7% auto 0;max-width:390px;min-height:180px;padding:30px 0 15px}* > body{background:url(//www.google.com/images/errors/robot.png) 100% 5px no-repeat;padding-right:205px}p{margin:11px 0 22px;overflow:hidden}ins{color:#777;text-decoration:none}a img{border:0}#media screen and (max-width:772px){body{background:none;margin-top:0;max-width:none;padding-right:0}}#logo{background:url(//www.google.com/images/branding/googlelogo/1x/googlelogo_color_150x54dp.png) no-repeat;margin-left:-5px}#media only screen and (min-resolution:192dpi){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat 0% 0%/100% 100%;-moz-border-image:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) 0}}#media only screen and (-webkit-min-device-pixel-ratio:2){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat;-webkit-background-size:100% 100%}}#logo{display:inline-block;height:54px;width:150px}
</style>
<a href=//www.google.com/><span id=logo aria-label=Google></span></a>
<p><b>404.</b> <ins>That’s an error.</ins>
<p>The requested URL <code>/v4/threatLists:list?key=my_api_key</code> was not found on this server. <ins>That’s all we know.</ins>
threatLists working example:
threatLists works without :list. e.g. curl https://safebrowsing.googleapis.com/v4/threatLists?key=YOUR_KEY
threatMatches working example:
Method: POST
Content-Type:application/json
https://safebrowsing.googleapis.com/v4/threatMatches:find?key=YOUR_KEY
Body:
{
"client": {
"clientId": "testing",
"clientVersion": "0.0.1"
},
"threatInfo": {
"threatTypes": ["MALWARE","SOCIAL_ENGINEERING","UNWANTED_SOFTWARE","MALICIOUS_BINARY"],
"platformTypes": ["ANY_PLATFORM"],
"threatEntryTypes": ["URL"],
"threatEntries": [
{"url": "http://goooogleadsence.biz/"}
]
}
}
The code is correct. I have the same...
It seems Chrome browser has an other (more accurate) source for safe browsing. Maybe they keep these fresh data exclusively for some specific clients.
The result is the same whatever lookup protocol version you can use.
And this is the same if you use the update API.
If someone knows, really, why... I am very interested in this information.
Please make sure that you are appending "/" in you URLs in the request. It is important to do that.
In this case, your URL would become http://some-malicious-url/.
Let me know if this works!

GET chrome-extension://< soundcloud's stream url > net : : ERR_FAILED

So I'm trying to stream soundcloud with soundmanager2, but i got this error from my background event page:
GET chrome-extension://api.soundcloud.com/tracks/155143944/stream?
client_id=d47c763873f2jan403dac26b62e3a820 net::ERR_FAILED chrome-
extension://api.soundcloud.com/tracks/155143944/stream?
client_id=d47c763873f2jan403dac26b62e3a820:1
T/tracks/155143944-0.7370116342790425: HTML5 error, code 4 soundmanager2.js:1191
T/tracks/155143944-0.7370116342790425: Failed to load / invalid sound? Zero-length
duration reported. (chrome-extension://api.soundcloud.com/tracks/155143944/stream?
client_id=d47c763873f2jan403dac26b62e3a820) soundmanager2.js:1189
Here is my code:
Manifest:
"permissions": [
"tabs",
"*://soundcloud.com/*"
],
"background": {
"scripts": ["soundmanager2/script/soundmanager2.js", "soundcloud_SDK.js",
"background.js"],
"persistent": false
},
Background.js:
SC.initialize({
client_id: "d47c763873f2jan403dac26b62e3a820"
});
soundManager.setup({
url: 'soundmanager2/swf',
onready: function() {
SC.stream("/tracks/155143944", function(sound){
sound.play();
});
}
});
This seems like an issue with protocol-relative URLs.
Look in the source files for strings like //api.soundcloud.com/ and put https: in front of it.
And maybe also location.protocol + '//api.soundcloud.com/' -> https://api.soundcloud.com/.

Resources