Allowing Flash movie to communicate to containing window without exposing full ExternalInterface? - javascript

I'm working on a site that allows administrators to upload arbitrary SWFs and embed them on the page. Administrators are in theory trusted, but I still want to protect against potentially malicious administrators or misguided administrators from harming the site.
A part of the functionality of the site is that the SWFs can communicate to the containing browser page when it's finished and for the page to react.
Now, I can think of two ways to do this:
Use ExternalInterface.addCallback to create a global callback named something like isComplete that does logic and returns true or false depending on whether the Flash app is in a completed state. Then, just do something like setTimeout to just call that function repeatedly. I don't think this would require me to open up allowscriptaccess to the movie.
Embed the movie with allowscriptaccess and have the movie call something like ExternalInterface.call('done') when it's finished. This option seems like it requires me to open up allowscriptaccess, which is a potential threat since I can't control the SWFs that would be embedded with this directive.
Is there a solution I'm missing that doesn't involve doing the infinite loop and also doesn't require me to open up a security risk?

Instead of embedding your SWFs directly in the main page, embed them in a separate page that's hosted on a subdomain (or some other domain). Then, display that subpage via an <iframe> in your main page. This way, you'll have a cross-domain <iframe>. Go ahead and give the SWF allowscriptaccess permissions. Then, communicate via postMessage (or a cross-browser simulation script) with the iframe. This way, the SWF can do anything they want to the page, but there's only one controlled "tunnel" to the main page.

Related

any way to auto-execute custom js lib function on external websites?

I was wondering if there's any way to attach a js lib to an external webpage after the page has loaded?
To provide a simple example, could I load www.google.com into IE and somehow display the webpage with a green scroll bar?
I would like this process to happen automatically on each page load instead of having to manually execute this process on each page load.
I am assuming that you are talking from a web developer's point of view.
I don't think it is possible without any hacks.
This would also be a huge security risk, because loading javascript code on an external website means that the code can potentially do anything on behalf of the user. It can capture keystrokes, take screenshots, note down passwords and do a lot of illegal stuff.
So instead of this, you can create a browser extension (add-on) which will have to be installed by user's permission (and his knowledge), and can run any code on any page (if the user allows it)

Can I change the 'window.location' property inside a Bookmarklet and then continue doing things on the new document?

I want know if you can guide to users for a series of steps that imply visit different web pages using actions inside a Bookmarklet. What I want is a kind of Wizard or automated actions cross web pages.
Afraid not. What you're describing would actually be very dangerous. If there were any malicious code in the bookmarklet, it would have access to every site you are logged into, email, amazon etc. Some pseudocode for an attack could look like this:
window.location = "www.gmail.com";
ajax.post("www.gmail.com/deleteAllMail");
window.location = "www.amazon.com";
ajax.post("www.amazon.com/buyReallyExpensiveStuff");
You partially can, if you open the new pages inside an iframe. However, you won't be able to modifying the content of the webpages anymore, but just modifying the url of the iframe, and going through different websites (like a kind of slideshow).
Notice that if you're the owner of the pages, you can use postMessage to interact with them, even if they're in different domains.
Or, you could do a "tunneling" on server side, and inject each team you got the page back with the JS you need.
But probably the cleanest approach if you're not the owner of the pages is just create a simple restartless add-on for the browsers you want to support.

How do JavaScript-based modal/popup services like KissInsights and Hello Bar work?

I'm developing a modal/popup system for my users to embed in their sites, along the lines of what KissInsights and Hello Bar (example here and here) do.
What is the best practice for architecting services like this? It looks like users embed a bit of JS but that code then inserts additional script tag.
I'm wondering how it communicates with the web service to get the user's content, etc.
TIA
You're right that usually it's simply a script that the customer embeds on their website. However, what comes after that is a bit more complicated matter.
1. Embed a script
The first step as said is to have a script on the target page.
Essentially this script is just a piece of JavaScript code. It's pretty similar to what you'd have on your own page.
This script should generate the content on the customer's page that you wish to display.
However, there are some things you need to take into account:
You can't use any libraries (or if you do, be very careful what you use): These may conflict with what is already on the page, and break the customer's site. You don't want to do that.
Never override anything, as overriding may break the customer's site: This includes event listeners, native object properties, whatever. For example, always use addEventListener or addEvent with events, because these allow you to have multiple listeners
You can't trust any styles: All styles of HTML elements you create must be inlined, because the customer's website may have its own CSS styling for them.
You can't add any CSS rules of your own: These may again break the customer's site.
These rules apply to any script or content you run directly on the customer site. If you create an iframe and display your content there, you can ignore these rules in any content that is inside the frame.
2. Process script on your server
Your embeddable script should usually be generated by a script on your server. This allows you to include logic such as choosing what to display based on parameters, or data from your application's database.
This can be written in any language you like.
Typically your script URL should include some kind of an identifier so that you know what to display. For example, you can use the ID to tell which customer's site it is or other things like that.
If your application requires users to log in, you can process this just like normal. The fact the server-side script is being called by the other website makes no difference.
Communication between the embedded script and your server or frames
There are a few tricks to this as well.
As you may know, XMLHttpRequest does not work across different domains, so you can't use that.
The simplest way to send data over from the other site would be to use an iframe and have the user submit a form inside the iframe (or run an XMLHttpRequest inside the frame, since the iframe's content resides on your own server so there is no cross domain communication)
If your embedded script displays content in an iframe dialog, you may need to be able to tell the script embedded on the customer site when to close the iframe. This can be achieved for example by using window.postMessage
For postMessage, see http://ejohn.org/blog/cross-window-messaging/
For cross-domain communication, see http://softwareas.com/cross-domain-communication-with-iframes
You could take a look here - it's an example of an API created using my JsApiToolkit, a framework for allowing service providers to easily create and distribute Facebook Connect-like tools to third-party sites.
The library is built on top of easyXDM for Cross Domain Messaging, and facilitates interaction via modal dialogs or via popups.
The code and the readme should be sufficient to explain how things fit together (it's really not too complicated once you abstract away things like the XDM).
About the embedding itself; you can do this directly, but most services use a 'bootstrapping' script that can easily be updated to point to the real files - this small file could be served with a cache pragma that would ensure that it was not cached for too long, while the injected files could be served as long living files.
This way you only incur the overhead of re-downloading the bootstrapper instead of the entire set of scripts.
Best practice is to put as little code as possible into your code snippet, so you don't ever have to ask the users to update their code. For instance:
<script type="text/javascript" src="http://your.site.com/somecode.js"></script>
Works fine if the author will embed it inside their page. Otherwise, if you need a bookmarklet, you can use this code to load your script on any page:
javascript:(function(){
var e=document.createElement('script');
e.setAttribute('language','javascript');
e.setAttribute('src','http://your.site.com/somecode.js');
document.head.appendChild(e);
})();
Now all your code will live at the above referenced URI, and whenever their page is loaded, a fresh copy of your code will be downloaded and executed. (not taking caching settings into account)
From that script, just make sure that you don't clobber namespaces, and check if a library exists before loading another. Use the safe jQuery object instead of $ if you are using that. And if you want to load more external content (like jQuery, UI stuff, etc.) use the onload handler to detect when they are fully loaded. For example:
function jsLoad(loc, callback){
var e=document.createElement('script');
e.setAttribute('language','javascript');
e.setAttribute('src',loc);
if (callback) e.onload = callback;
document.head.appendChild(e);
}
Then you can simply call this function to load any js file, and execute a callback function.
jsLoad('http://link.to/some.js', function(){
// do some stuff
});
Now, a tricky way to communicate with your domain to retrieve data is to use javascript as the transport. For instance:
jsLoad('http://link.to/someother.js?data=xy&callback=getSome', function(){
var yourData = getSome();
});
Your server will have to dynamically process that route, and return some javascript that has a "getSome" function that does what you want it to. For instance:
function getSome(){
return {'some':'data','more':'data'};
}
That will pretty effectively allow you to communicate with your server and process data from anywhere your server can get it.
You can serve a dynamically generated (use for example PHP or Ruby on Rails) to generate this file on each request) JS file from your server that is imported from the customers web site like this:
<script type="text/javascript" src="//www.yourserver.com/dynamic.js"></script>
Then you need to provide a way for your customer to decide what they want the modal/popup to contain (e.g. text, graphics, links etc.). Either you create a simple CMS or you do it manually for each customer.
Your server can see where each request for the JS file is coming from and provide different JS code based on that. The JS code can for example insert HTML code into your customers web site that creates a bar at the top with some text and a link.
If you want to access your customers visitors info you probably need to either read it from the HTML code, make your customers provide the information you want in a specific way or figure out a different way to access it from each customers web server.

How can an iFrame from another domain get rid of itself?

I am building a bookmarklet for various sites that functions basically like this:
User navigates to foo.com (an external site not on my control)
User clicks a bookmarklet on his browsers that grabs some information from foo.com and displays it on a form in bar.com inside an iframe
User submits the form inside bar.com which is inside foo.com
The iframe dissapears
The problem is getting the iFrame to remove itself. Since I can't access a function inside a parent domain in another domain I cannot create a custom function parent.removeIFrame() or even do a window.top.location.reload(). I tried many techniques but all of them fail because of cross domain scriptings.
The way I solved it was to change the top.location.href to a custom page I built at bar.com/back.html in which all it does is simply to send a single "history.back()" command that bounces the user on the original page. Althought creative, I don't think it's very elegant solution. Is there a better way?
You can try fragment identifier for cross domain messaging. There is a YUI library for it: http://www.julienlecomte.net/blog/2007/11/31/
When you injected the JS code to create the form on the site's page you can have it poll (js outside of the newly created iframe) your server to know when to remove the iframe. You can use all kinds of methods of doing this including jsonp, long polling, post message, fragment identifiers, etc. You do not need to load a big library for this - the smaller the better for bookmarklets.

Why do some websites (like facebook) load scripts in an iframe?

Why do some websites (like facebook) load scripts in an iframe?
Is this to allow the site to load more than 2 resources at a time because the iframe's resources are at different URLs?
What you are seing, might be an application of "Comet" communication, using a hidden iframe as data channel. A short explanation of the technique according to Wikipedia:
A basic technique for dynamic web application is to use a hidden IFrame HTML element (an inline frame, which allows a website to embed one HTML document inside another). This invisible IFrame is sent as a chunked block, which implicitly declares it as infinitely long (sometimes called “forever frame”). As events occur, the iframe is gradually filled with script tags, containing JavaScript to be executed in the browser. Because browsers render HTML pages incrementally, each script tag is executed as it is received.
This could be used for something like a chat, where messages are expected to appear without noticeable delay, and preferably without periodical "polling" for new data. If this is what you have come across, you should see several <script> elements in the frame, and more should be added as times go by.
EDIT
So to actually address your question... I don't know! The following information might be helpful, however:
Facebook prepends all of the JS variables and functions with your application ID.
var ID;
becomes
var 1262682068026-ID;
This limits the scope of your javascript to only your application so you can't use the DOM to get at their friends, phone number, email, address, etc, unless authorized. It makes a little sub-sandbox for you to play in.
More info on scoping here:
Facebook Docs
javascript loaded in iframe have no access to parent page objects (cross-domain restriction)
They load comet (aka comet, HTTP Push, long-lived, etc) connections in an iFrame because Internet Explorer eventually drops it:
http://cometdaily.com/2007/10/25/http-streaming-and-internet-explorer/
As it is effectively a continuous long poll, this is a blocker, this hack also increases IE's 2 connection limit leading to better responsiveness, background info:
http://alex.dojotoolkit.org/2006/02/what-else-is-burried-down-in-the-depths-of-googles-amazing-javascript/

Categories

Resources