En Unity 3.0, el Webplayer implementa un modelo de seguridad muy similar al utilizado por Adobe Flash player™. Estas restricciones de seguridad solo se aplican al reproductor web y al editor cuando el destino de compilación activo es el reproductor web. El modelo de seguridad tiene varias partes:
- Restricciones de acceso a los datos en un dominio que no sea el que aloja su .archivo unity3d.
- Alguna limitación en el uso de los Sockets.
- No permitir la invocación de ningún método que consideremos fuera de los límites. (cosas como Archivo.Eliminar, etc).
- No permitir el uso del sistema.Reflexión.* para llamar a métodos privados / internos en clases que no escribiste tú mismo.
Actualmente solo se emulan en el Editor las dos primeras partes del modelo de seguridad.
La funcionalidad de red de reproductores múltiples integrada de Unity (UnityEngine.Network
, UnityEngine.NetworkView
clases, etc.) no se ve afectada.
Este documento describe cómo asegurarse de que su contenido siga funcionando con la versión 3.0 de Unity webplayer.
- Consulte la referencia de la API de Unity para obtener información sobre la clase WWW.
- Consulte la referencia de la API de. NET para obtener información sobre la clase de socket. NET.
La clase WWW y los sockets utilizan el mismo esquema de política, pero además son sistemas completamente separados. La directiva WWW solo define permisos en el servicio web donde se aloja la directiva, pero las directivas de sockets se aplican a todas las conexiones de sockets TCP/UDP.
El editor de Unity viene con una función de «Emular seguridad web», que impone el modelo de seguridad del reproductor web.Esto facilita la detección de problemas desde la comodidad del editor. Puede encontrar esta configuración en Edit – >Configuración del proyecto-> Editor. Consulte también la configuración del editor.
El Unity webplayer espera que un archivo de política servido http llamado crossdomain.xml
esté disponible en el dominio al que desea acceder con la clase WWW(aunque esto no es necesario si es el mismo dominio que aloja el archivo unity3d).
Por ejemplo, imagine un juego tetris, alojado en la siguiente url:
http://gamecompany.com/games/tetris.unity3d
necesita acceder a una lista de mejores puntuaciones desde la siguiente url:
http://highscoreprovider.net/gethighscore.php
En este caso, tendría que colocar un archivo crossdomain.xml
en la raíz de la highscoreprovider.net dominio como este: http://highscoreprovider.net/crossdomain.xml
El contenido del archivo crossdomain.xml
está en el formato utilizado por el reproductor Flash. Es muy probable que encuentre el archivo crossdomain.xml
ya en su lugar. La política en el archivo se ve así:
<?xml version="1.0"?><cross-domain-policy><allow-access-from domain="*"/></cross-domain-policy>
Cuando este archivo se coloca en http://highscoreprovider.net/crossdomain.xml, el propietario de ese dominio declara que el contenido del servidor web puede ser accedido por cualquier reproductor web procedente de cualquier dominio.
Unity webplayer no admite las etiquetas <permitir encabezados de solicitud http desde dominio> y <directivas de control de sitios permitidos entre dominios>. Tenga en cuenta que crossdomain.xml
debe ser un archivo ASCII.
Depuración
Si se establece una variable de entorno ENABLE_CROSSDOMAIN_LOGGING
en 1
, se generarán mensajes de consola a medida que el tiempo de ejecución de Unity obtenga y decodifique el archivo crossdomain.xml
. En un Mac, puede establecer variables de entorno globales en /etc/launchd.conf
. En un PC use Panel de control – >Sistema y Seguridad – > Sistema – > Configuración avanzada del sistema – >Variables de entorno
Aquí hay un ejemplo de salida con esta variable de entorno establecida, cuando el reproductor web intenta obtener una imagen de un servidor remoto:
Determining crossdomain.xml location for request: http://www.remoteserver.com/image.jpgAbout to parse url: http://www.remoteserver.com/image.jpgDetermining crossdomain.xml location for request: http://www.remoteserver.com/image.jpgAbout to parse url: http://www.remoteserver.com/crossdomain.xmlAbout to parse url: http://www.remoteserver.com/image.jpgDetermining crossdomain.xml location for request: http://www.remoteserver.com/image.jpgDownload had OK statuscodeReceived the following crossdomain.xml--------------------------------------<?xml version="1.0"?><cross-domain-policy><allow-access-from domain="*"/></cross-domain-policy>----------------------received policyParsing: cross-domain-policycross-domain-policyParsing: allow-access-fromallow-access-from domain: *done parsing policycrossdomain.xml was succesfully parsedAbout to parse url: http://www.remoteserver.com/image.jpgChecking if http://www.remoteserver.com/image.jpg is a valid domainChecking request-host: www.remoteserver.com against valid domain: *All requirements met, the request is approved
Cuando se ejecuta en el Editor, estos mensajes se escriben en el Editor.registro. Intentar leer un archivo crossdomain.xml
almacenado incorrectamente como utf16
con un BOM
resultará en un error al analizar el xml:
BuildFlashPolicy caught an exception while parsing http://www.remoteserver.com/crossdomain.xml: Expected element
Esto se debe a que no se espera el BOM
. El uso de un archivo utf16
sin soporte y sin BOM
dará lugar a:
BuildFlashPolicy caught an exception while parsing http://www.remoteserver.com/crossdomain.xml: Policy can't be constructed from empty stream.
Esto se debe a que el primer byte en el archivo es cero, lo que hace que el analizador piense que ha llegado al final del archivo. Crossdomain.xml
debe ser un archivo ASCII.
Implicaciones para el uso de Sockets:
Un Unity webplayer necesita una política de socket servido para conectarse a un host en particular. Esta directiva está alojada de forma predeterminada por el host de destino en el puerto 843, pero también se puede alojar en otros puertos. La diferencia funcional con un puerto no predeterminado es que se debe recuperar manualmente con Seguridad.Llamada a la API PrefetchSocketPolicy () y si está alojada en un puerto superior a 1024, la directiva solo puede dar acceso a otros puertos superiores a 1024.
Cuando se usa el puerto predeterminado, funciona de la siguiente manera: Un Unity webplayer intenta hacer una conexión de socket TCP a un host, primero comprueba que el servidor host aceptará el connection.It lo hace abriendo un socket TCP en el puerto 843, emite una solicitud y espera recibir una directiva de socket a través de la nueva conexión. A continuación, Unity webplayer comprueba que la política del host permite que la conexión siga adelante y, de ser así, continuará sin errores. Este proceso ocurre de forma transparente con el código del usuario, que no necesita ser modificado para usar este modelo de seguridad. Un ejemplo de una política de sockets se ve así:
<?xml version="1.0"?><cross-domain-policy> <allow-access-from domain="*" to-ports="1200-1220"/> </cross-domain-policy>"
Esta directiva dice efectivamente «El contenido de cualquier dominio es libre de hacer conexiones de sockets en los puertos 1200-1220». El Unity webplayer respetará esto y rechazará cualquier intento de conexión de socket que use un puerto fuera de ese rango (se lanzará una excepción de seguridad).
Cuando se utilizan conexiones UDP, la directiva también se puede recuperar automáticamente cuando es necesario aplicarla de forma similar a la de TCP. La diferencia es que la recuperación automática con TCP ocurre cuando se conecta a algo (garantiza que se le permita conectarse a un servidor), pero con UDP, ya que no tiene conexión, también sucede cuando llama a cualquier punto API que envíe o reciba datos (garantiza que se le permita enviar/recibir tráfico a/desde un servidor).
El formato utilizado para la directiva de sockets es el mismo que el utilizado por Flash player, excepto que algunas etiquetas no son compatibles. Unity webplayer solo admite » * » como valor válido para la configuración de dominio y la configuración «to-ports» es obligatoria.
<?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>
La directiva de sockets se aplica a los tipos de conexión TCP y UDP, por lo que el tráfico UDP y TCP se puede controlar mediante un solo servidor de directivas.
Para su comodidad, proporcionamos un pequeño programa que simplemente escucha en el puerto 843; cuando en una conexión recibe una cadena de solicitud, responderá con una política de socket válida.El código del servidor se puede encontrar dentro de la carpeta de instalación de Unity, en Data/Tools/SocketPolicyServer en Windows o /Unity.app / Contents/Tools / SocketPolicyServer en OS X. Tenga en cuenta que el ejecutable preconstruido se puede ejecutar en Mac, ya que es un ejecutable Mono. Simplemente escribe «mono sockpol».exe» para ejecutarlo. Tenga en cuenta que este código de ejemplo muestra el comportamiento correcto de un servidor de directivas de sockets. Específicamente, el servidor espera recibir una cadena con terminación cero que contenga < policy-file-request / >. Solo envía al cliente el documento xml de directiva de sockets cuando se ha recibido esta cadena (y exactamente esta cadena). Además, se requiere que el encabezado xml y el cuerpo xml se envíen con una sola escritura de socket. Dividir el encabezado y el cuerpo en operaciones de escritura de sockets separadas puede causar excepciones de seguridad debido a que Unity recibe una política incompleta. Si experimenta algún problema con su propio servidor, considere usar el ejemplo que proporcionamos. Esto le ayudará a diagnosticar si tiene problemas de servidor o de red.
Las bibliotecas de redes de terceros, comúnmente utilizadas para redes de juegos multijugador, deben poder funcionar con estos requisitos siempre que no dependan de la funcionalidad de pares 2 (consulte a continuación), sino que utilicen servidores dedicados. Estos a veces incluso vienen de la caja con soporte para políticas de alojamiento.
Nota: Si bien los archivos crossdomain.xml
y de política de sockets son documentos xml y son similares en general, la forma en que se sirven estos documentos es muy diferente. Crossdomain.xml
(que se aplica a las solicitudes http) se obtiene mediante http en el puerto 80, donde-como la directiva de socket se obtiene desde el puerto 843 mediante un servidor trivial que implementa el archivo de política <solicitud/>. No puede usar un servidor http para emitir el archivo de política de sockets, ni configurar un servidor que simplemente envíe el archivo de política de sockets en respuesta a una conexión de sockets en el puerto 843. Tenga en cuenta también que cada servidor al que se conecte requiere su propio servidor de directivas de sockets.
Depuración
Puede usar telnet
para conectarse al servidor de directivas de sockets. A continuación se muestra una sesión de ejemplo:
host$ telnet localhost 843Trying 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$
En esta sesión de ejemplo, telnet se utiliza para conectarse al host local en el puerto 843. Telnet responde con las tres primeras líneas, y luego se sienta a esperar a que el usuario ingrese algo. El usuario ha introducido la cadena de solicitud de directiva < policy-file-request / >, que el servidor de directivas de sockets recibe y responde con la directiva de sockets. A continuación, el servidor se desconecta, lo que hace que telnet informe de que la conexión se ha cerrado.
Sockets de escucha
No puede crear sockets de escucha en el reproductor web, no puede actuar como un servidor. Por lo tanto, los jugadores web no pueden comunicarse entre sí directamente (peer 2 peer). Al usar sockets TCP, solo puede conectarse a puntos de conexión remotos siempre que se permita a través del sistema de directivas de sockets. Para UDP funciona igual, pero el concepto es un poco diferente, ya que es un protocolo sin conexión, no tiene que conectarse/escuchar para enviar/recibir paquetes. Funciona al imponer que solo puede recibir paquetes de un servidor si ha respondido primero con una política válida con la etiqueta allow-access-from domain
.
Todo esto es tan molesto, ¿por qué existen todas estas cosas?
Las funciones de seguridad de socket y WWW existen para proteger a las personas que instalan el reproductor Web de Unity. Sin estas restricciones, un ataque como el siguiente sería posible:
- Bob trabaja en la casa blanca.
- Frank es malvado. Escribe un juego web de unity que pretende ser un juego, pero en segundo plano hace una solicitud WWW a http://internal.whitehouse.gov/LocationOfNuclearBombs.pdf. interno.whitehouse.gov es un servidor al que no se puede acceder desde Internet, pero sí desde la estación de trabajo de Bob porque trabaja en la casa blanca.
- Frank envía esos bytes pdf a http://frank.com/secretDataUploader.php
- Frank coloca este juego en http://www.frank.com/coolgame.unity3d
- Frank de alguna manera convence a Bob de jugar el juego.
- Bob juega el juego.
- El juego descarga silenciosamente el documento secreto y lo envía a Frank.
Con las características de seguridad WWW y socket, este ataque fallará, porque antes de descargar el pdf, unity comprueba http://internal.whitehouse.gov/crossdomain.xml, con la intención de preguntar a ese servidor: «¿ los datos que tiene en su servidor están disponibles para uso público?». Colocando un dominio cruzado.xml en un servidor web puede ser visto como la respuesta a esa pregunta. En el caso de este ejemplo, el operador del sistema de internal.whitehouse.gov no colocará un dominio cruzado.xml en su servidor, lo que hará que Unity no descargue el pdf.
Desafortunadamente, para proteger a las personas que instalan el reproductor web de Unity, las personas que se desarrollan en Unity deben tener en cuenta estas medidas de seguridad al desarrollar contenido. Las mismas restricciones están presentes en todas las principales tecnologías de complementos. (Flash, Silverlight, Shockwave)
Excepciones
Para encontrar el equilibrio adecuado entre proteger a los usuarios de reproductores web y facilitar la vida de los desarrolladores de contenido, hemos implementado una excepción al mecanismo de seguridad descrito anteriormente:
Se le permite descargar imágenes de servidores que no tienen un dominio cruzado.archivo xml. Sin embargo, lo único que se le permite hacer con estas imágenes es usarlas como texturas en su escena. No se le permite usar GetPixel () en ellos. Tampoco se le permite volver a leer desde la pantalla. Ambos intentos resultarán en que se lance una excepción de seguridad:
SecurityException: No read access to the texture data: at (wrapper managed-to-native) UnityEngine.Texture2D:GetPixel (int,int)
El razonamiento es que está bien descargar la imagen, siempre y cuando el desarrollador de contenido no tenga acceso a ella. Por lo tanto, puede mostrarlo al usuario, pero no puede enviar los bytes de la imagen a otro servidor. Si necesita acceso a los datos de píxeles, coloque un archivo crossdomain.xml
en el servidor desde donde se obtienen las imágenes.