Cross origin Server Push extra request issue on Safari v12+ (both MacOS and iOS) - safari

Problem: Safari is doing a request with the pushed path but to the site host, resulting in 404s.
Scenario: Cross origin asset that is server pushed. Asset's host and site's host are different domains.
Browser: Safari v12+ (also v13) in both MacOS and iOS.
It is worth noting that the server push feature it self works, but Safari makes this extra request to the host. Also this doesn't happen on Safary v10 or v11.

I ran into this too, and confirmed (by re-writing with Charles Proxy) that Safari does load resources in a link header from the cross-origin domain if the link header uses an absolute path that includes a domain.
This type of HTTP response will not work in Safari:
HTTP/2 200
content-type: application/javascript; charset=utf-8
... other headers
link: </script.js>; rel=preload; as=script; crossorigin
Instead, you need to include the full domain and protocol, like so:
HTTP/2 200
content-type: application/javascript; charset=utf-8
... other headers
link: <https://www.example.com/script.js>; rel=preload; as=script; crossorigin
This is different from most server push tutorials which have a path that's absolute from the root of the domain (e.g. /script.js), but I've confirmed that it works correctly in Safari even when the server-push response is for a JavaScript resource on a different domain than the one that the HTML page lives on.

Scenario: Cross origin asset that is server pushed. Asset's host and site's host are different domains.
You cannot push a resource for another domain except in for very limited circumstances. The server has to be authorative for this server. Basically that means it goes to same IP address and is covered by same certificate. So if you are on www.example.com and have a separate sharded domain on static.example.com on the same server you can in theory push from that. However browser support is really poor for this and I really wouldn't recommend it. You can use the preload resource hint for that instead which is much better understood and supported.
Problem: Safari is doing a request with the pushed path but to the site host
As per above link, Safari does not support cross domain pushing. And neither do lots of other browsers.
resulting in 404s.
That would make sense since the resource you are requesting to push does not exist on that domain
It is worth noting that the server push feature it self works, but Safari makes this extra request to the host.
Then why do you think it is working?
Also this doesn't happen on Safary v10 or v11.
What doesn’t happen? The push? The double download? Both?

Related

Referrer and origin preflight request headers in Safari are not changing when user navigates

I have two web pages hosted on a.example.com and b.example. Each web page is including a script with a <script> tag, hosted on another domain and served with correct CORS headers.
At a certain point, user navigates from a.example.com to b.example.com.
Safari has here a strange behavior: the referrer and origin headers in preflight request are filled with a.example.com, making the server sending a bad value in Access-Control-Allow-Origin (and so the script can't be executed).
Is there a way to force Safari browser to send correct origin header in that kind of scenario ?
Does the cache policy for the script include Vary: Origin?
Respectively is there actually a second request after navigating to b.example.com?
If not, there is a chance that Safari is actually serving the script from cache - despite the Access-Control-Allow-Origin policy forbidding it to access the resource. Which is a conforming behavior, if the cache policy isn't configured correctly.
It seemed to be indeed a Safari bug.
The issue is not reproductible on Safari 10.0. It repro only on Safari 9.1.1 / 9.1.3.

Browser-side suggested HTTP/2 server push

Are there any specific spec'd processes that a browser client can use to dynamically encourage a server to push additional requested items into the browser cache using HTTP/2 server push before the client needs to actually use them (not talking about server-side events or WebSockets, here, btw, but rather HTTP/2 server push)?
There is nothing (yet) specified formally for browsers to ask a server to push resources.
A browser could figure out what secondary resources needs to render a primary resource, and may send this information to the server opportunistically on a subsequent request with a HTTP header, but as I said, this is not specified yet.
[Disclaimer, I am the Jetty HTTP/2 maintainer]
Servers, on the other hand, may learn about resources that browsers ask, and may build a cache of correlated resources that they can push to clients.
Jetty provides a configurable PushCacheFilter that implements the strategy above, and implemented a HTTP/2 Push Demo.
The objective of server push is that the server send additional files (e.g. javascripts, css) along with the requested URL (e.g. an HTML page) to the browser before the browser knows what related files are required, thus saving a round-trip and improve webpage load speed. If the browser already know what resources are needed it can request with normal HTTP calls.

Why is same origin policy kicking in when making request from localhost to localhost?

I'm keeping the backend API as a separate project from the frontend HTML5 app consuming it. I'm using Yeoman for the frontend development. Yeoman runs on localhost:3501 and the backend on localhost:3000. When I make the API request from the browser (using AngularJS's $http), I hit the same origin policy:
XMLHttpRequest cannot load http://localhost:3000/venues. Origin http://localhost:3501 is not allowed by Access-Control-Allow-Origin.
AFAIK, same origin policy should kick in only when making request across different domains. Why is it whining when we do a request from localhost to localhost (albeit to different port)?
How can I make this work and will this cause problems in production?
The ports also count for cross domain requests, therefore http://localhost:3000 and http://localhost:3501 are 2 different domains (from browser's point of view).
If you need both applications (client and backend) to run on different ports, consider using http://enable-cors.org/
According to W3C, "An origin is defined by the scheme, host, and port of a URL", so the different port is causing your problems.
Two possible solutions:
CORS (Cross Origin Resource Sharing)
Using JSONP requests
Both would require changes to your backend (I'm not familiar enough wo. CORS would probably mean the least changes to your frontend (I think AngularJS supports it out-of-the-box).

BlazeDS data push over SSL

I have an application that uses the data push technology of blazeDS to send data to a Flex Client event 5 seconds. The application works fine when I run it via HTTP with or without a proxy. When I run it via https the data push doesn't work anymore. I get the following error
rootCause [IOErrorEvent type="ioError" bubbles=false cancelable=false eventPhase=2
text="Error #2032: Stream Error.
URL: https://localhost/admin/messagebroker/streamingamfsecure?command=open&version=1
Has anyone successfully got streaming to work over SSL?
Thanks,
Pratima
Questions to ask yourself (and post here)
Is the request showing up in your access logs?
Does Tomcat/whatever server up normal HTML pages via HTTPS?
What do the response headers look like? Does clearing your cache change anything?
What browser are you using?
Can you set explicate caching headers?
Try one of these:
Cache-Control: no-store
Cache-Control: no-store, must-revalidate
Cache-Control: no-store,max-age=0,must-revalidate
Cache-Control: max-age=0,must-revalidate
Cache-Control: must-revalidate
2032 is a bit of a vague error from the framework.
However, things to check (in addition to Stu's list)
Can you hit the https:// page in a browser directly?
I notice in your example that you haven't specified the port number for SSL. Unless you've gone to the trouble of setting up some Apache SSL redirects, chances are this is a mistake.
If you paste the URL into a browser, you should be able to hit it, and get an empty response. Anything else, and you've got a problem (often one that doesn't relate to BlazeDS.)
Is your certificate valid?
If you're using a Self signed cert (as is common in development), does your browser have a security exception defined? Various browsers will block attempts to hit invalid certs in different ways, but no self-resepcting browser would allow this call through until an exception has been set up.
Is your channel defined correctly?
When switching from http:// to https://, you need to update your Channel class on the flex client to SecureAMFChannel and the endpoint class in your services-config.xml to SecureAMFEndpoint.
Broadly speaking, https with BlazeDS (either push, or RPC) works just fine, assuming you configure it properly.

How do I figure out which parts of a web page are encrypted and which aren't?

I'm working on a webserver that I didn't totally set up and I'm trying to figure out which parts of a web page are being sent encrypted and which aren't. Firefox tells me that parts of the page are encrypted, but I want to know what, specifically, is encrypted.
The problem is not always bad links in your page.
If you link to iresources at an external site using https://, and then the external site does its own HTTP redirect to non-SSL pages, that will break the SSL lock on your page.
BUT, when you viewing the source or the information in the media tab, you will not see any http://, becuase your page is properly using only https:// links.
As suggested above, the firebug Net tab will show this and any other problems. Follow these steps:
Install Firebug add-on into firefox if you don't already have it, and restart FF when prompted.
Open Firebug (F12 or the little insect menu to the right of your search box).
In firebug, choose the "Net" tab. Hit "Enable" (text link) to turn it on
Refresh your problem page without using the cache by hitting Ctrl-Shift-R (or Command-shift-R in OSX). You will see the "Net" tab in firefox fill up with a list of each HTTP request made.
Once the page is done loading, hover your mouse over the left colum of each HTTP request shown in the net tab. A tooltip will appear showing you the actual link used. it will be easy to spot any that are http:// instead of https://.
If any of your links resulted in an HTTP redirect, you will see "301 Moved Permanently" in the HTTP status column, and another HTTP request will be just below for the new location. If the problem was due to an external redirect, that's where the evidence will be - the new location's request will be HTTP.
If your problem is due to redirections from an external site, you will see "301 Moved permanently" status codes for the requests that point them to their new location.
Exapnd any of those 301 relocations with the plus sign at the left, and review the response headers to see what is going on. the Location: header will tell you the new location the external server is requesting browsers use.
Make note of this info in the redirect, then send a friendly polite email to the external site in question and ask them to remove the https:// -> http:// redirects for you. Explain how it's breaking the SSL on your site, and ideally include a link to the page that is broken if possible, so that they can see the error for themselves. (this will spur faster action than if you just tell them about the error).
Here is sample output from Firebug for the the external redirect issue.. In my case I found a page calling https:// data feeds was getting the feeds rewritten by the external server to http://.
I've renamed my site to "mysite.example.com" and the external site to "external.example.com", but otherwise left the heders intact. The request headers are shown at the bottom, below the response headers. Note that I"m requesting an https:// link from my site, but getting redirected to an http:// link, which is what was breaking my SSL lock:
Response Headers
Server nginx/0.8.54
Date Fri, 07 Oct 2011 17:35:16 GMT
Content-Type text/html
Content-Length 185
Connection keep-alive
Location http://external.example.com/embed/?key=t6Qu2&width=940&height=300&interval=week&baseAtZero=false
Request Headers
Host external.example.com
User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1
Accept */*
Accept-Language en-gb,en;q=0.5
Accept-Encoding gzip, deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection keep-alive
Referer https://mysite.example.com/real-time-data
Cookie JSESSIONID=B33FF1C1F1B732E7F05A547A9CB76ED3
Pragma no-cache
Cache-Control no-cache
So, the important thing to note is that in the Response Headers (above), you are seeing a Location: that starts with http://, not https://. Your browser will take this into account when figuring out if the lock is valid or not, and report only partially encrypted content! (This is actually an important browser security feature to alert users to a potential XSRF and/or phishing attacks).
The solution in this case is not something you can fix on your site - you have to ask the external site to stop their redirect to http. Often this was done on their side for convenience, without realizing this consequence, and a well written, polite email can get it fixed.
For each element loaded in page, check their scheme:
it starts with HTTPS: it is encrypted.
it starts with HTTP: it's not encrypted.
(you can see a relatively complete list on firefox by right-clicking on the page and selecting "View Page Info" then the "medias"tab.
EDIT: FF only shows images and multimedia elements. They are also javascript files & CSS ones which have to be checked. And Firebug is a good tool to find what you need.
Some elements may not list http or https, in this case whichever was used for the page will be used for these items, i.e. if the page request is under SSL then these images will come encrypted while if the page request is not under SSL then these will come unencrypted. Fiddler in Internet Explorer may also be useful in tracking down some of this information.
Sniff the packets - that'll tell you really quick. WireShark is a good program for such a task.
Can firebug do this?
Edit: Looks like firebug will also do this using the "Net" panel, which also gives you some other interesting statistics.
The best tool I have found for detecting http links on a https connection is Fiddler. It's also great for many other troubleshooting efforts.
I use FF plugin HTTPFox for this.
https://addons.mozilla.org/en-us/firefox/addon/httpfox/