Why are HTTP images not appearing in HTTPS application? - javascript

I have secured (HTTPS) ASP.Net MVC 4 application that uses unsecured (HTTP) ArcGIS map services. These services are called using JavaScript to get relevant map images.
If I use HTTP for my app, everything works as expected. But if I use HTTPS, IE10 and Chrome do not display the requested map images (IE prompts to display unsecured content) but Safari shows the image, no questions asked.
As an example, say my application is https://app.mydomain.com and my map services are at http://gis.mydomain.com
I run fiddler and see the response as something like (removed some parameters to simplify): http://gis.mydomain.com/arcgis/rest/services/Energy/BaseService/MapServer/export?....&f=image
but the image is not shown. If I enter this URL directly into my address bar, the expected image is shown.
There are no errors reported anywhere, including IIS 7.5 logs. I realize that mixed content is not ideal but I have no option at the moment. I have found lots of references to SilverLight with regard to this type of problem, but I am only using javascript and ASP.Net. I also compared the page source for both https and http - there is no difference.

While browsing a secure site, the browser will not load "nonsecure items" unless you (the visitor) authorize it.
The only way to solve this from server-side is by making the "nonsecure" content secure, by placing it under a https domain aswell.
Update:
By the way, if you don't specify the protocol in the content URLs, for exemple //gis.mydomain.com without specifying if it is http:// or https://, the browser will automatically assume the same protocol that was used to access the website to load this content too.
So if you access with http:// it will load the dependencies using http:// as well, and if you use https:// it will do the same.

Another way of getting around this is to proxy the insecure content via your (https) host. ESRI have some slightly out-of-date docco on this process (including an example ASP.Net proxy page) here, but most/all of it should still hold in the latest versions of the API. From memory, they recently (3.5?) made the proxy configurable on a per-service basis, which is very handy.
You can ignore the token-based authentication stuff in your case, all you're really looking for is to have the insecure content come through a secure host.

Related

How to allow only whitelisted resources (scripts, pixels etc.) to run within a sandboxed iframe?

I am looking for an approach to allow only whitelisted scripts to run within a sandboxed iframe. I was thinking of an iframe-sandbox directive that allows only whitelisted scripts to run within an iframe. The analogy is the script-src directive in the Content Security Policy.
The problem:
<iframe sandbox="allow-same-origin allow-scripts" src="https://app.thirdparty.com" width="100%" height="800" frameBorder="0"></iframe>
The app in the iframe provides valuable functionality for my website. However, it pulls in external resources that I would like to control (i.e., block), e.g., AnalyticsJavaScript.com and TrackingPixel.com. I would like to allow scripts from app.thirdparty.com but block AnalyticsJavaScript.com and TrackingPixel.com.
Any help appreciated.
The answer to this is unfortunately complicated. With the advent of iframe sandboxing the question seems simple enough, but the spec that you're looking for is very much a work in progress. Thus, if you want decent browser support, the issue devolves into how to modify an iframe's content, which usually involves some sort of proxy.
Content Security Policy
The spec you really need is the CSP. At its simplest, you would allow specific scripts with the iframe atribute csp="...".
<iframe ...
src=""
csp="script-src https://app.thirdparty.com/"
...></iframe>
Any scripts from domains not specified (i.e. tracking scripts as in the question) would not be allowed in the response. Note that limiting scripts to those from a specified source does rely on cooperation with the third party app's server. If the server does not inform the user agent that it will adhere to the CSP restrictions then the response will be blocked.
The CSP is still a working draft and may change in the future. As stated in the comments, Chrome 61 and Opera 48 have implemented the CSP spec, but at this stage there is no sign from Firefox, Edge or Safari that they will also implement it. Unless you can guarantee that your users will only be using a browser that supports the spec, the tracking scripts will still be present for a very large percentage of users.
The remaining suggestions all involve modifying the iframe's content to remove the offending scripts.
Reverse proxy
Creating a reverse proxy to block a couple of tracking scripts in an iframe is probably equivalent to using a nuclear warhead to light a camp fire as far as overkill goes. But, if you are able to configure your server to this extent, it is the most reliable and seamless method for iframe content injection/modification/blocking that I've found.
The Wikipedia page states:
A reverse proxy is a type of proxy server that retrieves resources on behalf of a client from one or more servers. These resources are then returned to the client, appearing as if they originated from the proxy server itself.
Because the reverse proxy is an intermediary between the third party app and your site, it can transparently modify the responses to remove the undesired scripts. I'll use Apache in this example, but your implementation really depends on what server you're already using.
You need a subdomain for the proxy that points to your server IP, e.g. proxywebapp.yourdomain.com. On your server you would then create a virtual host in httpd.conf that uses the Apache mod_proxy module. Within your virtual host configuration you would then substitute the script calls to AnalyticsJavaScript.com and TrackingPixel.com with blanks. If the third party app must use HTTPS then reverse proxying gets trickier as you need an SSL virtual host and a SSL certificate for the proxy's FQDN.
<VirtualHost *:*>
ServerName proxywebapp.yourdomain.com
ProxyPreserveHost On
ProxyPass "/" "http://app.thirdparty.com/"
ProxyPassReverse "/" "http://app.thirdparty.com"
# in case any URLs have the original domain hard coded
Substitute "s|app.thirdparty.com/|proxywebapp.yourdomain.com/|i"
# replace the undesired scripts with blanks
Substitute "s|AnalyticsJavaScript/| /|i"
Substitute "s|TrackingPixel/| /|i"
</VirtualHost>
Your iframe would then point to proxywebapp.yourdomain.com.
<iframe ... src="proxywebapp.yourdomain.com" ...></iframe>
Again: total overkill but should work transparently.
Proxy scripts
A third option to consider is implementing a proxy script on your server between the iframe and third party app. You would add functionality into the proxy script that searches for and removes the undesired scripts before they reach the iframe. Additionally the proxy means the iframe's content will validate the same-origin policy, thus you could instead remove the undesired content with JavaScript in the frontend, although this may not guarantee that the scripts won't run before they are removed. There are many proxy scripts available online for all manner of backends (PHP, Node.js etc. ad nauseum). You would likely install the script and add it as the iframe's src, something like <iframe ... src="proxy.php?https://app.thirdparty.com/" ...>.
Unless properly configured for all cases, the proxy may not correctly transfer data between the third party app and its parent server. Testing will be required.
Writing your own server side proxy to remove a couple of scripts from an iframe is probably a bit excessive.
If you can't access the backend, it is possible to scrape the web app's content using JavaScript and a CORS or JSONP web app, and modify it to remove the scripts. Essentially making your own proxy in JavaScript. Such web apps (Any Origin, All Origins, etc) allow you to bypass cross-domain policy restrictions, but because they are third party you can no longer assume any of the web app's data is private. The issue with correctly communicating any data transfer between the app and its parent server will still be present.
Summary
A widely supported pure frontend solution is not feasible at the moment. But there are many ways to skin a cat and perhaps even more ways to modify an iframe's content, regardless of cross-domain restrictions.
Content Security Policy does look promising and is exactly what you're asking for, but currently its lack of widespread support means it can only be used in very niche situations. A reverse proxy that modifies content may take a lot of configuring and in this situation is like driving a full size semi-trailer over a Hot Wheels track, but will likely operate seamlessly. Content modification from a forward proxy is somewhat simpler to implement, but may break communications with the third party app's parent server.
You can't do this the way you want (for now). As mentioned in comments CSP:EE is a thing yet to come.
However you can try proxying the request and removing the unnecessary scripts from the body on the server side or on the client side, e.g.:
1) Get the needed page via XMLHTTPRequest
2) Remove unwanted
3) Inject into iframe on the page
"Workability" of this method depends purely on external app functionality. I.e. it will not work if the aforementioned app needs registration/authorisation of the end user to work, however this can still be suitable for some simple cases.
P.S.: you can implement a workaround to make such thing work via browser extension, however I'm sure this is not what you want.

HTTP and HTTPS version of a same page render differently

Here are the links to the page in question:
http version
https version
The https version of the page doesn't render the video embedded on the top of the article. I inspected the source code and found that HTTPs is missing an entire block of code, as you can see in the images below:
I wonder how this happens? Isn't http(s) just the protocol to communicate with the server? Why do I get different code by using different protocols?
From Chrome Developer Toolkit:
The page at 'https://www.eyeviewdigital.com/blog/eyeview-launches-addressable-tv-ads-with-cablevision-dish-programmatic-tv-w-clypd-and-wideorbit/' was loaded over HTTPS, but requested an insecure script 'http://pshared.5min.com/Scripts/PlayerSeed.js?sid=281&width=480&height=401&playList=519141523'. This request has been blocked; the content must be served over HTTPS.
You typically need to load your content in either http or https. Mixing them together results in the error above.
On line 252 replace
http://pshared.5min.com/Scripts/PlayerSeed.js?sid=281&width=480&height=401&playList=519141523
with
https://delivery.vidible.tv/aol?sid=281&width=480&height=401&playList=519141523.js
Long story short the content was never loaded so the page looked different.
You're right that there should be no difference based on http/https as it is just the transport layer. There must be something in the server's code that is producing the html, that behaves differently based on the url used to make the request. I suggest you provide information on the web server code to help analyse the issue.
This is most likely caused because you're loading elements from insecure sources. Google Chrome for example, loading an image over http when your page is loaded over https can result in the image not loading at all. This is all for security purposes, of course. Just go through all of your code and make sure all sources are accessed through secure https so that they load in properly.

Cross Domain AJAX (Philips Hue Lights)

I am building a web application that uses voice recognition & text-to-speech that performs actions/displays a wide variety of data through an HTML page (built with JS (jQuery for AJAX)/HTML/CSS.) This web application is being hosted on HTTPS server that is not on my local network.
I have set up and configured some smart lights called "Philips HUE Lights" that are equipped with a RESTful API that can only be controlled through the local network (not visible outside of the local network.)
I am able to send commands to the device by visiting the CLIP debugger/API tool (local ip) "http:////debug/clip.html" that is included with their product. I am able to send HTTP commands to the "Philip HUE Bridge" which is the device that issues the commands to the lights. All of the commands work when I use their API tool (GET, "PUT, POST, DELETE) visiting the locally hosted url shown above.
However when I try using a jQuery AJAX request "GET"/"PUT" from my web application that is hosted on my HTTPS server, the command fails. I have tried setting the AJAX function header property with "Access-Control-Allow-Origin: *". I have also tried setting the "crossDomain" property to true in the AJAX function. I also have tried setting the "dataType" property to both "json" and "jsonp" and it still won't work.
I am visiting my HTTPS web application through a computer that is connected to the local network that the "HUE Bridge" is connected to. Given that I am using a computer on the same network, I thought this might work...
I have read a lot of other posts/information on the internet but can't seem to find a definitive answer. I wanted to ask some of you more seasoned people:
Is what I am trying accomplish even possible given the scenario I described above? Or will I have to achieve this in a different manner?
Any help/suggestions are much appreciated. Thanks.
You are running into "Mixed Content" security issues.
Basically when you are hosting a page on a secure URL (https) you cannot access unsecure (http) resources without getting a mixed content error.
This error is visible in the console of your browser (usually accessed by F12), when something is not working during webdevelopment always check the console for errors.
To hack around this you can temporarily disable the security and allow the unsecure request. For example Chrome shows a shield in the addressbar which you can click to temporarily disable the warning. Firefox shows a clickable warning overlay on the lock icon in the addressbar.
This might be a temporary workaround for development, but you cannot expect your users to disable security.
A solution should be to send a Content-Security-Policy header. Based on documentation from http://content-security-policy.com/ the following header should allow XMLHttpRequests to any resource:
Content-Security-Policy: connect-src *
However since I do not have enough control to modify the headers on the webserver where my files are hosted I could not test this.
Before using this method make sure you understand the security implications when you send this header.

Are custom URI's allowed by browser security?

Background Info
I want to integrate a javascript single-page web application with a 3rd party desktop windows application. I'm working with the 3rd party vendor to try to figure out the best way to set up the integration. The plan is to call URIs from the web application, and have the desktop application handle them to perform various actions. Right now, the URI's use the localhost scheme (i.e. they look like "http://localhost:8888/..."
The Questions
1) Attempting to make a get request to the URI from javascript results in the desktop app taking the desired action, but an error is returned to the browser due to cross-origin policy. I assume this is something that can be handled with CORS like any other cross origin request. Is this true? Or are URI requests to the OS "special" in some way?
2) We might instead want to use a custom URI scheme so that our URL can look like "myapp:..." instead of localhost. Will this suffer from the same cross-origin issues as the above? Will it run into any additional restrictions in major browsers? Would users need to manually muck with their browser settings to get it to work correctly, or is it even possible at all? Is there anything different from a browser security/permission standpoint between a "standard" URI using localhost and a custom URI scheme?

Mixed Content Warning IE: What matters; css, images, everything?

I have just moved my site from http to https and IE-9 started showing non-secure content warning at home page. This warning is understandable because i have one http call to googleapi for getting jquery script. But when I login and enter the inner pages there is no warning from IE despite the fact that most of the images are coming from other servers through http protocol.
So the question: Is getting image over http is fine when accessing site over https? Does only css and js matters? or shall I have to get all the data through HTTPS? If so how is my scenario justifiable (getting images over http from other server on https page without warning)?
If you load CSS and JS over HTTP then an attacker can inject executable code. Unfortunately IE will execute JavaScript within CSS. The problem with loading images over HTTP from the same domain is that the browser will likely spill the session id in plain text which is a violation OWASP a9.
You can use the protocol-relative URL on all your urls to avoid this issue in IE.
Basicaly, instead of linking to a js/image/css by using its full path with the protocol, you instead link to it by leaving out the protocol bit and just using a double slash, //.
This will have the effect of all the above links inheriting the protocol from the parent page.
Of course this depends on you having valid SSL certs on the domains you're serving the different files form.
One other thing to note also is that images in your pages or CSS that are done using data URI could also cause mixed content warnings in IE.
To find out what files are causing issues, I recommend using Fiddler
There is also another tool that a fellow SO user, Eric Law wrote:
Install it from http://www.bayden.com/dl/scriptfreesetup.exe and you will get a different mixed content prompt which shows the exact URL of the first insecure resource on the page. That tool is basically a prototype and you should uninstall it when you're done with it. It works on IE8 and you should install it as admin.

Categories