I have a secure (HTTPS) web app which needs to load a custom stylesheet from an insecure (HTTP) origin (customer's own website). This is blocked by modern browsers, however I need a workaround because:
1) I cannot ask my customers to host their custom stylesheets on HTTPS. They don't have the know-how and some of them have policies about what hosts and regions stuff can be hosted in (ironically, not about HTTPS though).
2) I obviously cannot ask the end user to disable security features in their browser.
I tried, loading stylesheets using <style>#import url(...);</style>, I tried creating an iframe with src="about:blank" and loading the stylesheet from within there, I tried XHR and fetch (but that will require CORS to be enabled on the remote host which I cannot reasonably expect).
Short of creating a secure proxy that will serve any stylesheet on the web, is there any other workaround I'm missing here?
Any sorcery to get my page to load a cross-origin stylesheet over HTTP?
If there was a workaround to be able to load insecure resources on secure pages, it should be patched ASAP. No, the policy exists because without HTTPS on all resources, you're not truly secured. Any HTTP connection may be intercepted and man-in-the-middled, so the page is not secure. Even something minor like a stylesheet can undermine that security.
You will have to serve the stylesheet over HTTPS, and if your customers can't do it, you will have to do it for them.
Is it perhaps possible to download their CSS server-side, and serve it to your own users via HTTPS?
I tried to do the same thing with a webapp that i builded. The real issue with what you want to do is the browser. It doesnt allow a secure connection to be spoiled by an insecure connection, especially when you want to inject something on that page. I used this technic:
document.createElement("link")
to inject. And with browser security being a big issue, I don't think you'll find a hack..
Best of luck! :)
Related
I recently switched my http site to https.
Since I made this change, one of my projects no longer works.
In this random generator, the background using the Three.js library does not appear when the url is in https
But in http , it works beautiful and well.
Does anyone know any solution to this problem?
Thank you for your consideration in this matter.
You can download the three.min.js file and save it on to your https server.
And instead of loading the script from http server, provide the path of your https server where you put the three.min.js file.
<script src="https://[path to your server]/js/three.min.js"></script>
Open your developer tools and look at the console, you'll find the explanation:
What this means is that you're not allowed to have an https:// site that loads some content via http://. This is called "mixed content" and it's a security vulnerability. If you're serving a secure site, make sure all your content is using the HTTPS protocol.
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.
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.
We have a big website with mix of https and http pages. And when i am on https page it tries to load resources by http protocol and some browsers block it as insecure (chrome for ex.).
So the question: how can i do some filter that allows me to load resources by https only from certain pages?
We are using httpd server and Spring security in our application.
So, how can i construct urls in JSP relative by context and by protocol? (I mean i cant simple write relative URLs in my page, because it is used in different contexts, for example
as example.com/resource.css and mydomain.corp/resource.css)
Use scheme relative URIs.
//example.com/foo/bar/baz
Get the protocol then load the assets you need. I think you should use assertProtocolAndFilenames in Spring.
I am posting this question on Super User as well. In my opinion this question overlaps the two...
I am creating a simple JavaScript wrapper for CouchDB's REST-ful interface, but I am stuck on same-origin policy issues.
So far I've been developing my code to work locally - and only as a proof of concept - on Mozilla FireFox. My server is running on localhost, port 5984.
To disable cross-origin policy in Mozilla FireFox you can use the PrivilegeManager, but it only gets me half-way in the sense that I can't do PUT requests against my server...
/*
* Including this in my JavaScript file only seems to disable cross-origin
* policy checks for POST and GET requests in Mozilla FireFox.
* PUT requests fail.
*/
netscape.security.PrivilegeManager.enablePrivilege(
"UniversalBrowserRead UniversalBrowserWrite"
);
Is there any way that I can configure my server to hide it's location so I won't have to implement browser-specific work-arounds to avoid same-origin policy issues? If not: what browser work-arounds exist to disable same-origin policy completely?
Unfortunately, any browser workarounds to disable same-origin policies are likely to be treated as serious security bugs and fixed as soon as possible.
See if you can come up with a way to work within the same-origin policy without trying to bypass it.
Can you serve your example scripts on the target server? Could you build a reflection script that would load the target script on your server after a local script on the users computer uploaded whatever they modified?
There should be a good solution that doesn't involve bypassing the same-origin policy. Trying to hack your way around it is a good way to ensure that your code doesn't work properly in future browsers.
I strugled with that issue too, trying to run automated tests on a local html file connecting to a virtualized CouchDB server, here's my solution:
I created a small implementation (and open sourced it) of the simplest solution when you can't enable CORS on the server,
you need to upload a .js and an .html file to the target server, (you can use any security mechanism to restrict access to this file if you want). Or you can change some simple parameters on the html file to restrict by domain.
On your page you use the same script to create an invisible iframe where the hosted .html is loaded, and proxy certain methods (sort-of RPC) thru that iframe using window.postMessage(), by default jQuery ajax methods can be proxied without extra configuration.
All this with one line of js code :)
FrameProxy at GitHub
(fell free to use it and fork it!)