Widgets security model
Network access rights model
The access rights model determines whether a widget should be allowed to access any particular URL, where "access" can mean any of the following:- Access by opening a URL in an external resource, such as the browser, by means of a link with an appropriate target, a call to widget.openURL or similar.
- Access by loading an embedded document or object inside the widget, such as an image, iframe, object, svg:foreignObject and similar.
- Access to resources from a child window in the widget. This includes, but is not limited to, resources such as images, frames, objects, embeds and similar that are contained in a document that is embedded in the widget, and displayed with Opera as a viewer. This relates to the previous point in a "turtles all the way down" manner, in that all URL access from a widget instance must be checked.
- Access to the URL through API calls, such as XMLHttpRequest, or any other current or future mechanism.
Network classes
The security model defines two classes of networks: private and public. A private network, or local network, is defined as the user's local machine, including any IP address that resolves to the local machine. Further, the IP ranges, as defined by RFC 1918, are considered to be private. These addresses are primarily being used in systems set up behind a NAT-translation device, and provides machines with unique addresses, where there is only one public IP address for several machines. These addresses are:10.0.0.0 - 10.255.255.255 (10/8 prefix) 172.16.0.0 - 172.31.255.255 (172.16/12 prefix) 192.168.0.0 - 192.168.255.255 (192.168/16 prefix)In addition, when a user is within an ad-hoc network, networking equipment (including software components in operating systems), typically use the IPv4 Link-Local addresses, as defined by RFC 3927, which is also considered to be part of the local network.
169.254.0.0 - 169.254.255.255 (169.254/16 prefix)Using the Opera security policy file (widgets.xml) it is possible to define the four network ranges described above as falling within the private IP range. This policy is editable by the user; they can add items to, or remove items from, the list of private networks and hosts.
Network access configuration
Network access is not enabled for widgets by default. The rules for accessing the network are determined by the following components:- The widget's declaration of network intent (config.xml)
- Opera's declaration of global network policy (widgets.xml)
Widget's declaration of network intent
A widget must declare its intention with regard to API and network access through the config.xml file, using the syntax described in the below config.xml fragment:
element widget attribute "network" optional value = "public|&private"
To acquire access to the network, the widget must declare this by adding the network attribute to the widget element in the widget's config.xml file. The value accepted for this attribute is a list of DOMStrings that can specify which network class it intends to access. The values are case sensitive. Valid values are as follows:
- private
- Governs any network the user has classified as a private network in configuration
- public
- Governs any network NOT classified as private
Examples:
Only request access to a user's Intranet or private/trusted network
<widget network="private">
Only request access to what the user considers to a public/non-trusted network
<widget network="public">
Request unrestricted access:
<widget network="private public">
Do not request network access:
<widget>
Controlling the widget's security
You can use the widget’s config.xml file to limit its access to only specific domains, ports, and protocols. The "security" element is used for this purpose, as specified below:element "security" optional element "access" multiple element "protocol" multiple cdata element "host" multiple cdata element "port" multiple cdata element "path" multiple cdata element "content" attribute "plugin" value = "yes|no"
Access element syntax is described in the section Security Policy files explained below.
If the network is enabled and nothing is specified in the security section of the widget’s config.xml file, the following applies:- A widget can contact any host over the http and https protocols.
- A widget cannot contact protocols other than http or https, unless specified in its config.xml.
- A widget cannot access the file system using the file protocol.
- A widget cannot contact non-standard ports (0–1023, except 80), unless specified in its config.xml.
- A widget can make use of Java applets or plug-ins.
- A widget can access the local file system, but only through a directly user-initiated action.
Note also that many browsers block outgoing HTTP requests on port 443, as this is reserved for HTTPS. Defining access to this port and protocol combination will not work.
Opera Network Policy definition
Global network policy for widgets running inside Opera is governed by the widgets.xml file, which must be placed in the $OPERA_HOME folder. This describes which hosts and IP ranges belong to the private network, which hosts are allowable, and contains a blacklist of network rules, where access should always be denied. The syntax for the policy file is described below:element "widgets" element "access" multiple element "protocol" multiple cdata element "host" multiple cdata element "port" multiple cdata element "path" multiple cdata element "private-network" attribute allow value="none|restricted|unrestricted" element "protocol" multiple cdata element "host" multiple cdata element "port" multiple cdata element "path" multiple cdata element "blacklist" element exclude multiple element "protocol" multiple cdata element "host" multiple cdata element "port" multiple cdata element "path" multiple cdata element include multiple element "protocol" multiple cdata element "host" multiple cdata element "port" multiple cdata element "path" multiple cdata
Default widgets.xml
Below is a proposed default security configuration file:<widgets> <security> <access> <protocol>http</protocol> <protocol>https</protocol> </access> <private-network allow="unrestricted"> <host type="localhost" /> <host type="range">10.0.0.0-10.255.255.255</host> <host type="range">172.16.0.0-172.31.255.255</host> <host type="range">192.168.0.0-192.168.255.255</host> <host type="range">169.254.0.0-169.254.255.255</host> </private-network> </security> </widgets>
Security Policy files explained
In this topic, elements of both the Opera Security Policy file (widgets.xml) and the widget Security Policy file (config.xml) are explained. Note that not all the elements are available in both files: the only element available for each file are those specified in the topics above. Note also that, in some cases, the semantics of some elements/attributes can differ slightly between widgets.xml and config.xml and these differences are underlined in the following topics.The access element
The "access" element is used to specify the access permissions of the widget. If the contents of the "access" element is empty, then the element is treated as if it was not present. The combination of a missing access element for a widget, whose other configuration options would grant network access, would thus mean "grant all".For all the child elements of "access", with the exception of the "protocol" element, the absence of an element means the same as "match all", granting access to all resources not limiting access.
The private-network element
The "private-network" element is used to define which protocols, hosts, ports and IP ranges define the user's private network. As a child, this element defines the same elements as for access. The element also defines an attribute "allow", which is used to specify the kinds of network access the widget is allowed. The attribute accepts one of three values:- none
- Disallow access to all resources defined as being in the private network
- restricted
- Allow a widget to access either the private network, or the public network, but do not allow a widget to mix these modes.
- unrestricted
- Allow access to both the private network and the public network without restrictions.
The 'host' element
The host element is a syntactical construct used to determine which hosts a widget can contact. The element is defined as follows:element "host" attribute "type" optional "value"="localhost|string|range" cdataThe "type" attribute determines which kind of matching is done for the host element:
- localhost
- When the value of the type attribute is specified as "localhost", this refers to accessing the user's local machine, regardless of which method of access is chosen — hostname, or one of the IP addresses that resolves to the user's local machine. In the case that localhost is specified, the cdata in the element is disregarded for comparison purposes.
- string
- In the case where the value of the "type" attribute is "string", the cdata within the element is regarded as a string match for the hostname, including an optional leading wildcard.
- range
- When the value of the "type" attribute is "range", the content inside the element is expected to be an IP address, or a range of IP addresses separated by a single '-'.
- In the "access" element of widgets.xml, or in config.xml
- When a "host" element is missing from an "access" element, regardless of
which file this element occurs, the element is assumed to be present, as a
single wildcard value:
<host>*</host>
. When present, the default wildcard element is replaced with the exact value of any matching "host" elements. - In the "private-network", "exclude" and "include" elements
- In these elements, the "host" attribute is not assumed to be present if it is missing from the list, and so, any hosts not explicitly included in these elements will not go into the definitions of the private network, the blacklist or its overrides.
The "protocol" element
The "protocol" element is used to determine the protocols a widget should be able to access. When missing from config.xml, the element is assumed to be present three times, with the values "widget", "http" and "https". When missing from any other context, the element gets no value, and for instance, if missing from "access", a widget would not be allowed to get network access.The "port" element
The "port" element is used to define the port numbers a widget should be able to access when initiating network traffic. The "port" element accepts as its value a single port number, port numbers separated by a comma, or a range of ports separated using '-'. When missing from an "access" element, the "port" element is assumed to be present, matching all ports, and when a widget requests access to a resource using http, it can do so on every port. It should however be noted that there are certain port numbers for which Opera has disabled access for security reasons, and a configuration override cannot change these. When a different port number is specified for a protocol in an "access" element, the port numbers specified are the only ones by which a widget can communicate.The "path" element
The path element is used to restrict widget access to particular paths within the rule sets. When missing from anywhere within widget configuration, or policy file, the element is assumed to be present, allowing access to any path, thus implicitly bearing the value "/".
The path is treated as a wildcard path, allowing access to any matching subpath of the element. Example:
In this access fragment, placed within widgets.xml or config.xml, access to any resource contained within the "/cats" subpath is allowed:
<path>/cats</path>
thus, the widget can access all of
- /cats/siamese.html
- /cats/
- /catsoup
In the case that the author of either the widget.xml fragment, or config.xml fragment, meant to limit access to '/cats/', the specification of the path would have to include the forward slash:
<path>/cats/</path>
The blacklist element
The "blacklist" element specifies two child elements "exclude", which is used to define combinations of host, port, path and protocols that cannot, under any circumstance, be accessed, and an "include" element, which is used to individually override restrictions set in place by "exclude". Multiple "exclude" and "include" elements may be used.URL access rights
The term "URL access" specifies any access to a networked resource a widget may attempt. This includes the following:
- The widget directly requesting a resource through inclusion (such as iframes, objects and other elements)
- The widget including images, stylesheets, and scripts; including, indirectly, when a stylesheet or (SVG) image requests additional resources to be loaded.
- The widget attempting to open a resource in an external application (in effect, using links or widget.openURL)
- Resources contacted by API access: DOM3 Load/Save, XMLHttpRequest and similar
- The destination of form elements
- When Opera includes resources in iframes and similar, any access made by documents contained in these included documents.
Whenever Opera attempts to contact any resource, a number of checks must be made to see if access to the URL is permitted.
Failure modes
If a widget, by configuration, explicitly requires access to a resource forbidden by other configuration, installation of the widget will fail.
If a widget attempts to contact a resource that is in conflict with the widget's own stated security policy, or the widget attempts to contact a resource which it has been restricted from accessing (such as accessing a private-network resource when it has only requested access to public network resources), it will fail in one of two ways:
- If the access is via direct access, such as opening URLs using link constructs, form submissions, or similar methods, the action will fail silently.
- If the access is via API access, such as XMLHttpRequest, the action will generally fail with a security violation error in the same manner as a Web page that tries to do cross-domain requests.
Private network class
The algorithm for allowing access to the private network is as follows:
- If the widget has added "private" to the network attribute, continue. Otherwise, deny access.
- If the profile configuration, allows access, continue. Otherwise, deny access.
- If a per-widget override configuration allows access, continue. Otherwise, deny access.
Public-network class
The algorithm for accessing the public network mirrors the algorithm for the private network.
Multiple network classes
In the case that a widget requests access to both network classes, the algorithm for determining private networks and public networks are checked individually. In addition, the following algorithm is used.
- If the widget requires access to both network classes, continue.
- If a profile-configuration directive allows simultaneous access to both network classes, continue. Otherwise, deny access
In the case that any step in the above processes has resulted in "Deny access", deny access. Otherwise allow access.
URL-based access check
When a widget attempts to contact a resource, and this resource has been allowed by the network class above, the following algorithm is applied:
- Take the requested URL string, make any comparison based on the matching algorithm defined below
- Compare the URL components to the access element of the widget's config.xml. If no such directive exists, assume one is present with the same values as in the corresponding section in widgets.xml. If the requested URL is permitted by this step (meaning, the URL matches the directive), continue to the next step. If the requested URL does not match the directive, deny access.
- Compare the URL components to the blacklist. If the requested URL does not match a blacklist-exclude directive, allow access. If the requested URL matches a blacklist-exclude directive, continue to the next step.
- If there is no blacklist-include directive, deny access. If there is such a directive present, check if the requested URL matches the directive. If there is a match, allow access to the URL, otherwise deny.
URL comparison
When comparing a URL for a match with any given directive, use the following algorithm.
- Componentize the request URL into the following components: protocol, host, port and path.
- Compare the requested protocol on a character-by-character basis with the corresponding protocol element. If the directive is in an implicit-access directive (meaning it is not physically present in any document), assume it has the values http and https, respectively. If there is a match, continue. Otherwise, mark the URL as not matching.
- Reverse the two strings given for the requested host and the host specified for the directive (directive host). Do a case-insensitive character-by-character comparison of the strings. If a mismatch is found before the end of the directive host string is reached, and the last two characters in the directive host string are not the character sequence '.*', consider that the requested host is not a match. If there are characters left to parse in the requested host, and the last characters of the directive host were the wildcard sequence '.*' consider the host a match.
- Compare the requested port and the directive port. If the port number is missing from the requested URL, consider the port to be the default port for the given protocol. If there is no port number present in the directive, consider the directive port to match all port numbers. Make a numeric match between the request and the directive. If the requested port is in the range defined by the directive, consider it a match.
- For the requested path and the directive path, perform a case-sensitive character-by-character match. If there is a mismatch at any point, consider the path as "not matching". If there are no characters left to parse in the requested path, and there are characters left to parse in the directive path, consider the paths as "not matching". If there are no characters left to parse in the directive path, and there are more characters left to parse in the requested path, consider the path a match. If there is no path specified in the directive, always consider the path a match.
Known issues
The current release has some known issues that impacts the successful implementation of some of the mechanisms described above. We are aware of these and we are working actively to solve these issues for future releases. Below is a list of the current known issues:- Redefining private network in widgets.xml blocks widgets access to public network if allow="none".
- Blocking several ports (together with host) using a comma in the "blacklist" element in widgets.xml does not work. Only the first port in the list is excluded/blocked.
- Misformed widgets.xml file will causes Opera to hang during startup.
- widget.openURL and window.open are able to open external URLs even when the widget does not have network access defined by the network attribute.
- URLs in iframes, images and links do not follow restrictions of private and public network.
- A change in the internal URL representing widgets renders widgets:// URL's unusable by jsplugins.ini. It is possible to use CALLBACK in jsplugins.ini as a workaround.