In Unity 3.0, the webplayer implements a security model very similar to the one used by the Adobe Flash player™. This security restrictions apply only to the webplayer, and to the editor when the active build target is WebPlayer. The security model has several parts:
Currently only the first two parts of the security model are emulated in the Editor.
The built-in muti-player networking functionality of Unity (UnityEngine.Network
, UnityEngine.NetworkView
classes etc) is not affected.
The WWW class and sockets use the same policy schema but besides that they are completely separate systems. The WWW policy only defines permissions on the web service where the policy is hosted but socket policies apply to all TCP/UDP socket connections.
The Unity editor comes with an “Emulate Web Security” feature, that imposes the webplayer’s security model. This makes it easy to detect problems from the comfort of the editor. You can find this setting in Edit->Project Settings->Editor. See also the Editor settings.
The Unity webplayer expects a http served policy file named crossdomain.xml
to be available on the domain you want to access with the WWW class,
(although this is not needed if it is the same domain that is hosting the unity3d file).
For example, imagine a tetris game, hosted at the following url:
http://gamecompany.com/games/tetris.unity3d
needs to access a highscore list from the following url:
http://highscoreprovider.net/gethighscore.php
In this case, you would need to place a crossdomain.xml
file at the root of the highscoreprovider.net domain like this: http://highscoreprovider.net/crossdomain.xml
The contents of the crossdomain.xml
file are in the format used by the Flash player. It is very likely that you’ll
find the crossdomain.xml
file already in place. The policy in the file look like this:
<?xml version="1.0"?>
<cross-domain-policy>
<allow-access-from domain="*"/>
</cross-domain-policy>
When this file is placed at http://highscoreprovider.net/crossdomain.xml, the owner of that domain declares that the contents of the webserver may be accessed by any webplayer coming from any domain.
The Unity webplayer does not support the <allow-http-request-headers-from domain> and <site-control permitted-cross-domain-policies> tags. Note that crossdomain.xml
should be an ASCII file.
Setting an environment variable ENABLE_CROSSDOMAIN_LOGGING
to 1
will cause console messages to be generated as the Unity runtime fetches and decodes the crossdomain.xml
file. On a Mac you can set global environment variables in /etc/launchd.conf
. On a PC use Control Panel->System And Security->System->Advanced system settings->Environment Variables…
Here is an example output with this environment variable set, when the webplayer attempts to fetch an image from a remote server:
Determining crossdomain.xml location for request: http://www.remoteserver.com/image.jpg
About to parse url: http://www.remoteserver.com/image.jpg
Determining crossdomain.xml location for request: http://www.remoteserver.com/image.jpg
About to parse url: http://www.remoteserver.com/crossdomain.xml
About to parse url: http://www.remoteserver.com/image.jpg
Determining crossdomain.xml location for request: http://www.remoteserver.com/image.jpg
Download had OK statuscode
Received the following crossdomain.xml
--------------------------------------
<?xml version="1.0"?>
<cross-domain-policy>
<allow-access-from domain="*"/>
</cross-domain-policy>
----------------------
received policy
Parsing: cross-domain-policy
cross-domain-policy
Parsing: allow-access-from
allow-access-from
domain: *
done parsing policy
crossdomain.xml was succesfully parsed
About to parse url: http://www.remoteserver.com/image.jpg
Checking if http://www.remoteserver.com/image.jpg is a valid domain
Checking request-host: www.remoteserver.com against valid domain: *
All requirements met, the request is approved
When running in the Editor these messages are written to the Editor.log. Attempting to read a crossdomain.xml
file incorrectly stored as utf16
with a BOM
will result in a failure to parse the xml:
BuildFlashPolicy caught an exception while parsing http://www.remoteserver.com/crossdomain.xml: Expected element
This is because the BOM
is not expected. Using an unsupported utf16
file with no BOM
will result in:
BuildFlashPolicy caught an exception while parsing http://www.remoteserver.com/crossdomain.xml: Policy can't be constructed from empty stream.
This is because the first byte in the file is zero, which causes the parser to think it’s reached the end of the file. Crossdomain.xml
must be an ASCII file.
A Unity webplayer needs a socket served policy in order to connect to a particular host. This policy is by default hosted by the target host on port 843 but it can be hosted on other ports as well. The functional difference with a non-default port is that it must be manually fetched with Security.PrefetchSocketPolicy() API call and if it is hosted on a port higher than 1024 the policy can only give access to other ports higher than 1024.
When using the default port it works like this: A Unity webplayer tries to make a TCP socket connection to a host, it first checks that the host server will accept the connection. It does this by opening a TCP socket on port 843, issues a request, and expects to receive a socket policy over the new connection. The Unity webplayer then checks that the host’s policy permits the connection to go ahead and it will proceed without error if so. This process happens transparently to the user’s code, which does not need to be modified to use this security model. An example of a socket policy look like this:
<?xml version="1.0"?>
<cross-domain-policy>
<allow-access-from domain="*" to-ports="1200-1220"/>
</cross-domain-policy>"
This policy effectively says “Content from any domain is free to make socket connections at ports 1200–1220”. The Unity webplayer will respect this, and reject any attempted socket connection using a port outside that range (a SecurityException will be thrown).
When using UDP connections the policy can also be auto fetched when they need to be enforced in a similar manner as with TCP. The difference is that auto fetching with TCP happens when you Connect to something (ensures you are allowed to connect to a server), but with UDP, since it’s connectionless, it also happens when you call any API point which sends or receives data (ensures you are allowed to send/receive traffic to/from a server).
The format used for the socket policy is the same as that used by the Flash player except some tags are not supported. The Unity webplayer only supports “*” as a valid value for the domain setting and the “to-ports” setting is mandatory.
<?xml version="1.0" encoding="ISO-8859-1"?>
<!ELEMENT cross-domain-policy (allow-access-from*)>
<!ELEMENT allow-access-from EMPTY>
<!ATTLIST allow-access-from domain CDATA #REQUIRED>
<!ATTLIST allow-access-from to-ports CDATA #REQUIRED>
The socket policy applies to both TCP and UDP connection types so both UDP and TCP traffic can be controlled by one policy server.
For your convenience, we provide a small program which simply listens at port 843; when on a connection it receives a request string, it will reply with a valid socket policy. The server code can be found inside the Unity install folder, in Data/Tools/SocketPolicyServer on Windows or /Unity.app/Contents/Tools/SocketPolicyServer on OS X. Note that the pre-built executable can be run on Mac since it is a Mono executable. Just type “mono sockpol.exe” to run it. Note that this example code shows the correct behaviour of a socket policy server. Specifically the server expects to receive a zero-terminated string that contains <policy-file-request/>. It only sends to the client the socket policy xml document when this string (and exactly this string) has been received. Further, it is required that the xml header and xml body are sent with a single socket write. Breaking the header and body into separate socket write operations can cause security exceptions due to Unity receiving an incomplete policy. If you experience any problems with your own server please consider using the example that we provide. This should help you diagnose whether you have server or network issues.
Third party networking libraries, commonly used for multiplayer game networking, should be able to work with these requirements as long as they do not depend on peer 2 peer functionality (see below) but utilize dedicated servers. These sometimes even come out of the box with support for hosting policies.
Note: Whilst the crossdomain.xml
and socket policy files are both xml documents and are broadly similar, the way that these documents are served are very different. Crossdomain.xml
(which applied to http requests) is fetched using http on port 80, where-as the socket policy is fetched from port 843 using a trivial server that implements the <policy-file-request/>. You cannot use an http server to issue the socket policy file, nor set up a server that simply sends the socket policy file in response to a socket connection on port 843. Note also that each server you connect to requires its own socket policy server.
You can use telnet
to connect to the socket policy server. An example session is shown below:
host$ telnet localhost 843
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
<policy-file-request/>
<?xml version='1.0'?>
<cross-domain-policy>
<allow-access-from domain="*" to-ports="*" />
</cross-domain-policy>Connection closed by foreign host.
host$
In this example session, telnet is used to connect to the localhost on port 843. Telnet responds with the first three lines, and then sits waiting for the user to enter something. The user has entered the policy request string <policy-file-request/>, which the socket policy server receives and responds with the socket policy. The server then disconnects causing telnet to report that the connection has been closed.
You cannot create listening sockets in the webplayer, it cannot act as a server. Therefore webplayers cannot communicate with each other directly (peer 2 peer). When using TCP sockets you can only connect to remote endpoints provided it is allowed through the socket policy system. For UDP it works the same but the concept is a little bit different as it is a connectionless protocol, you don’t have to connect/listen to send/receive packets. It works by enforcing that you can only receive packets from a server if he has responded first with a valid policy with the allow-access-from domain
tag.
The socket and WWW security features exist to protect people who install the Unity Web Player. Without these restrictions, an attack such as the following would be possible:
With the WWW and socket security features, this attack will fail, because before downloading the pdf, unity checks http://internal.whitehouse.gov/crossdomain.xml, with the intent to ask that server: “is the data you have on your server available for public usage?”. Placing a crossdomain.xml on a webserver can be seen as the response to that question. In the case of this example, the system operator of internal.whitehouse.gov will not place a crossdomain.xml on its server, which will lead Unity to not download the pdf.
Unfortunately, in order to protect the people who install the Unity Web Player, people who develop in Unity need to take these security measures into account when developing content. The same restrictions are present in all major plugin technologies. (Flash, Silverlight, Shockwave)
In order to find the right balance between protecting Web Player users and making life of content developers easy, we have implemented an exception to the security mechanism described above:
You are allowed to download images from servers that do not have a crossdomain.xml file. However, the only thing you are allowed to do with these images is use them as textures in your scene. You are not allowed to use GetPixel() on them. You are also not allowed to read back from the screen. Both attempts will result in a SecurityException being thrown:
SecurityException: No read access to the texture data:
at (wrapper managed-to-native) UnityEngine.Texture2D:GetPixel (int,int)
The reasoning is here is that it’s okay to download the image, as long as the content developer gets no access to it. So you can display it to the user, but you cannot send the bytes of the image back to some other server. If you need access to the pixel data then place an crossdomain.xml
file on the server where the images are fetched from.