OpenAjax Hub 2.0 Specification Best Practices
From MemberWiki
NOTE: This wiki page holds part of the OpenAjax Hub 2.0 Specification.
9 OpenAjax Hub Best Practices
This chapter identifies various "best practices" associated with using the OpenAjax Hub.
The contents of this chapter are non-normative.
Undetermined order, asynchronous execution of callback functions
The Managed Hub often uses asynchronous techniques, particularly when the IframeContainer is used. Depending on the implementation and the particular circumstances, the Unmanaged Hub might also deliver messages asynchronously.
Implementations SHOULD deliver messages in a time-ordered manner. In particular, if Client A publishes event 1 followed by event 2, Client B SHOULD receive event 1 before event 2. However, an implementation is NOT required to enforce any particular sequence when events 1 and 2 are published by DIFFERENT clients.
While Hub implementations SHOULD normally deliver messages in a simple time-ordered manner, client developers SHOULD NOT depend on any particular invocation order as a number of different operational factors can impact the order in which messages are delivered.
While Hub implementations SHOULD normally invoke subscriber callback functions as soon as possible, which in some cases translates into immediate execution, developers SHOULD NOT depend on immediate execution of subscriber callback functions as there are various scenarios where subscriber callback functions might execute asynchronously.
Callbacks should not throw exceptions
Publishers and subscribers SHOULD NOT use exceptions as part of the protocol by which they communicate with each other and share information. In particular, subscribers SHOULD NOT rely on exceptions to communicate with publishers. When an iframe Container is used, the IframeHubClient.publish operation is often implemented such that it returns before the subscriber callback is invoked. Also, the Manager Application typically inserts logic through which all communication between publishers and subscribers must pass. Therefore, even if the specifications allowed subscribers to throw exceptions, exceptions thrown by a subscriber generally would not be received by the publisher.
The OpenAjax Hub API specification defines a number of callback functions, including subscription callbacks, onComplete functions, onConnect functions and the like. The API specification requires that these functions SHOULD NOT throw exceptions. If a callback function throws an exception, arbitrary behavior may occur. Callback functions SHOULD therefore contain code that catches and handles all exceptions.
Callback function guidelines
OpenAjax Hub 2.0 includes a number of callback functions, including subscription callbacks and functions for handling errors.
Callbacks execute within the single-threaded browser JavaScript context and therefore SHOULD execute and return quickly to prevent the Web page from becoming unresponsive.
Callbacks functions MAY invoke other OpenAjax Hub APIs as part of their processing. All OpenAjax Hub API calls are legal within these callback functions, as long as the state of the Hub permits the execution of the API functions. For example, the onComplete callback associated with HubClient.connect() can call HubClient.subscribe, HubClient.publish, HubClient.unsubscribe and even HubClient.disconnect(). Subscribe and unsubscribe callbacks may even publish, subscribe and unsubscribe on the same topic. However, be careful; if a subscriber on topic "com.example.foo" has an onData callback function that publishes on "com.example.foo", this may cause an infinite cycle.
Note that all of the same guidelines that ordinarily apply to published events (e.g., general guideline about publisher/subscriber independence) also apply to events published by callback functions.
Even when placed in the same browser frame as the Manager Application (e.g., due to the use of the InlineContainer), Client Applications SHOULD only invoke the Hub's client APIs (i.e., HubClient APIs for the Managed Hub or the Unmanaged Hub APIs). Therefore, Client Applications SHOULD NOT invoke Container APIs or invoke APIs found in the Manager Application. This helps clients to remain isolated from each other, so that they can easily be moved into iframe containers if isolation is required.
General guideline: publisher/subscriber independence
As a general rule, publishers and subscribers SHOULD be designed to operate independently and SHOULD NOT assume that publishers and subscribers share the same JavaScript environment. This is especially true in the Managed Hub case, because when the iframe Container is used, Client Applications are isolated inside iframes and have no access whatsoever to each other's or the Manager's JavaScript environment.
Pass-by-value, read-only publisherData
The data
that represents the payload to a publish()
call SHOULD consist of JSON-serializable JavaScript objects and will be passed by value to subscriber callbacks. Therefore, publishers SHOULD NOT pass references to JavaScript objects within publisherData
and instead pass the values of those objects.
In some scenarios, such as when a particular topic has multiple subscribers that are all using InlineContainers, the Hub implementation MAY pass the same publisherData
object to multiple callback functions. Therefore, callback functions SHOULD treat publisherData
as read-only.
Responding to FramePhishing alerts
An instance of IframeContainer may raise a FramePhishing security alert when the iframe's src attribute is changed unexpectedly. The IframeContainer may also hide the iframe. This behavior is intended to thwart frame phishing attacks, in which the iframe is navigated to a phishing page.
A manager's response to a Frame Phishing alert may depend on the expected behavior of the application.
- Manager might start a load timer. If the client in the window reconnects quickly, verifying its identity, then everything may be okay.
- Manager might destroy the IframeContainer
- Manager might destroy and recreate the IframeContainer
- Manager might abort by removing all sensitive information, logging out of all sessions, closing all sub-windows and rendering an error page.
How to handle LoadTimeout
In IframeContainer implementations, the LoadTimeout security alert is part of the mechanism for preventing frame phishing attacks. A Container raises the LoadTimeout security alert to notify the Manager Application that the Container's client application has failed to connect as expected. This might be an innocent delay, e.g. the server might be very slow and thus the page within the iframe might not have loaded in a timely way, but in some cases the delay will constitute evidence that a frame phishing attack replaced the client before the client could call connect().
When a LoadTimeout security alert occurs, the Manager SHOULD destroy the IframeContainer and replace it with an error message.
Clients in IframeContainer should connect immediately
To ensure that the Container does not raise a security alert of type LoadTimeout, client components should execute HubClient.connect() as quickly as possible after they are instantiated.
Handle onDisconnect for all IframeContainer instances
After an iframe Container disconnects, the Container is no longer able to detect frame phishing attacks on the iframe. The manager application should therefore register an onDisconnect callback function to detect and handle the disconnect event. This function might display a warning message in front of the iframe, or it might destroy the iframe container. The behavior of onDisconnect depends on the needs of the application.
IframeContainer clients should not change the iframe src URL
On some browsers, an IframeContainer instance may use the URL's fragment identifier to communicate with the IframeHubClient instance within the iframe, using a technique known as "fragment identifier messaging."
If a client application within an iframe tries to modify the URL of the iframe that contains it, this may either disrupt communication between the IframeContainer and the IframeHubClient or cause the whole client application to be unloaded, resulting in a FramePhishing security alert or a Message Forgery security alert.
Thus, client applications sandboxed within IframeContainer instances SHOULD NOT try to change the iframe URL.
If iframe URL changes are unavoidable, the client application in the iframe SHOULD ask the Manager Application to change the URL, rather than changing the URL itself. However, such a protocol is not part of the OpenAjax Hub specification; applications and frameworks are free to implement it at a higher level.
"Polite" vs "abrupt" removal of Containers
A Manager Application could destroy a Container in one of two ways:
- Abrupt: Immediately destroy the Container without giving the Container's client any advance warning. If the Container is an IframeContainer, then immediately destroy the iframe. Do not give the Container's client any advance warning.
- Polite: Send a "shutdown" message to the client, telling it to clean itself up and shut down gracefully. When the client has finished its cleanup, the client should call disconnect(), causing the Manager Application to call ManagedHub.removeContainer and destroy the client.
Abrupt removal
Manager Applications SHOULD support the abrupt case so that an IframeContainer can be removed even if the client in the iframe is hung, broken, busy, malicious, etc. Manager Applications SHOULD use the abrupt approach to remove clients that are suspected of being hostile or of being the victims of frame phishing (see above).
An abrupt shutdown consists simply of calling ManagedHub.removeContainer, which immediately destroys the Container by calling Container.remove. Container.remove automatically destroys all subscriptions that the Container created in the ManagedHub. If the Container instance is an IframeContainer, then the "remove" operation also destroys the iframe, thus eliminating anything running in the iframe.
In the "abrupt" case, the Manager Application does not give the client any warning that it will be destroyed, does not negotiate with the client and does not wait for the client to clean itself up or to agree to be removed.
Polite removal
Abrupt removal is necessary in some cases, but it has some serious drawbacks. It does not permit a Client Application to clean itself up gracefully; an abruptly terminated Client Application cannot terminate any login sessions, Comet connections or other application state associated with the client. This may waste scarce server resources.
There are many scenarios in which abrupt removal is NOT required, and in which the Container can be removed in a more "polite" manner. For example, if a user clicks on a "close button" in the chrome around a gadget, the shutdown and removal of the gadget should probably be as graceful as possible.
A polite shutdown SHOULD involve the following steps:
- Using publish, the Manager Application sends a message known as a "shutdown" message to the client component. As far as the Hub knows, the shutdown message is simply another data message. It has no special semantics.
- The client component receives the shutdown message. It responds by cleaning up its state (comet connections, server state, etc.).
- After all of this cleanup (which might have involved asynchronous operations) is completed, the client component calls HubClient.disconnect
- After the client disconnects, the Container detects the disconnect (possibly asynchronously) and invokes the Manager Application's onDisconnect callback function.
- The onDisconnect function calls ManagedHub.removeContainer, abruptly removing the Container.
- Because the client cleaned up all relevant state before calling disconnect, this removal no longer causes "resource leaks" on servers to which the client was connected.
A shutdown message such as the one in step 1 can optionally be implemented at an application level; it is not part of the OpenAjax Hub specification, nor is it provided by the reference implementation.
When to use which approach
Polite removal allows for graceful shutdown of the client; abrupt removal does not. Therefore, use abrupt removal in situations in which shutdown must be immediate, e.g. cases involving a SecurityAlert, or cases where potential resource leaks are not a problem. A more polite approach is probably best in most other cases.
Browser Specific Behavior
Some implementations of the OpenAjax Hub standard may utilize features whose behavior varies from browser to browser. For example, some versions of some browsers may not support the HTML 5 postMessage feature, and on such browsers, an IframeContainer implementation may fall back on some other mechanism for achieving communication between sandboxes.
As with other implementations, the behavior of OpenAjax Alliance open source reference implementation may be affected by the behavior of the web browser on which it is running. The OpenAjax Interoperability Working Group provides a wiki page (Browser Variation of the Hub Reference Implementation (Illustrative)) in order to illustrate how browser variation may impact the behavior of the reference implementation. The page is NOT part of this OpenAjax Hub specification; the link is provided for informative purposes only.
Charsets and UTF-8
Manager Applications and Client Applications SHOULD use UTF-8 charset for all files and data to minimize potential charset conflicts when integrated with other software. This includes the charset value on the META tag, charset values on HTTP headers, and the charset used when encoding URLs.
Hub implementation security concerns
A conformant implementation of the OpenAjax Hub SHOULD implement various security techniques to guard against malicious attacks. The techniques described in this section have been implemented within OpenAjax Alliance's open source reference implementation of OpenAjax Hub 2.0 (the "reference implementation").
To help guard against frame phishing attacks, the reference implementation passes a unique randomly-generated manager security token at load time to each client and has a short timeout period within which the client must respond. The reference implementation includes other safeguards, such as raising errors if the client application unloads unexpectedly and requiring that each message from clients include the manager security token.
Hub implementations SHOULD establish safe, private communications channels that prevent malicious clients from monitoring communications with other clients in the mashup and prevent malicious components from generating forged messages that can be sent to other clients. The reference implementation takes advantage of HTML5 postMessage in recent browsers and fragment-identifier messaging (FIM) techniques on older browsers, where each of the methods is used in a manner such that only the manager application and a single client can read and write on their private communications channel.
The reference implementation makes use of security tokens, one on the manager side and (for FIM messaging) another on the client side. This technique helps the manager application ensure that it is receiving a message from the same client that it previously loaded and therefore helps prevent frame phishing attacks.
Other Manager Application security concerns
To deliver a secure environment to end-users and their organizations, manager applications SHOULD pay close attention to security concerns.
Trusted and Untrusted Clients
When used in the context of a Manager Application, clients SHOULD be classified as either trusted or untrusted. This determination SHOULD be made by IT experts. If the trustworthiness of a particular client is uncertain, that client SHOULD be classified as untrusted. Clients that are considered to be trusted MAY be embedded within an InlineContainer, which has performance advantages over the IframeContainer. All other clients SHOULD use the IframeContainer so that they are isolated into a secure sandbox.
Security Manager Callbacks
Manager applications SHOULD provide a security manager component that includes a policy manager to control message flow among the clients. The policy manager APIs in Hub 2.0 is fine-grained and provide the manager application with the ability to allow or deny each separate client subscription request and, for each published message, whether to allow or deny transmission of that message to a particular client. It is critical that the manager application establish and implement a carefully crafted conservative security manager that defaults to deny all requests from untrusted clients, and only allows requests from untrusted clients for selected actions that are known to be appropriate for that client.
Sub-Domains
Manager applications SHOULD isolate untrusted client applications from one another so that the two clients cannot directly access each other's content or code. Manager applications use IframeContainers to accomplish such isolation. IframeContainers, in turn, accomplish such isolation by using the same-domain security features found in modern Web browsers. Thus, to isolate one client application from another, a manager application SHOULD ensure that iframe URLs of the two IframeContainers have different domains or subdomains (e.g., a001.mydomain.com, a002.mydomain.com, etc.). The manager application SHOULD also ensure that the mashup page itself has a subdomain that is different from those of either client.
If it is necessary to isolate a wide variety of client applications within a mash-up, the manager application's server may need to provide a large set (or pool) of subdomains.