Веб плеер в Unity 3.0 реализует модель безопасности очень похожую на используемую в Adobe Flash player™. Эти ограничения безопасности применяются только к веб плееру и редактору (если в bild settings текущей платформой является WebPlayer). Модель безопасности разбита на несколько частей:
В настоящий момент только первые две части модели безопасности эмулируются в редакторе.
Встроенный в Unity функционал мультиплеера (классы UnityEngine.Network
, UnityEngine.NetworkView
и т.п.) не влияют на модель безопасности.
WWW класс и сокеты используют схожую схему, но совершенно разные системы. WWW только определяет права доступа на веб сервис, где политика состоялась, но сокеты применяются ко всем TCP/UDP соединениям.
Unity поставляется с “Эмуляцией Web Security”, что полагает модель безопасности веб плеера. Это облегчает обнаружение проблем в редакторе. Подробные настройки в Edit->Project Settings->Editor. Также см. Editor settings.
Веб плеер Unity ожидает http файл сервера политики под названием crossdomain.xml
, чтобы быть доступным на домене, к которому вы пытаетесь получить доступ с WWW классом
(хотя это не потребуется, если домен тот же, на котором размещен unity3d файл)
Например, представьте тетрис, размещенный по следующему адресу:
http://gamecompany.com/games/tetris.unity3d
нужно получить доступ к листу highscore, размещенному по адресу:
http://highscoreprovider.net/gethighscore.php
В этом случае вам нужно разместить crossdomain.xml
файл в корень highscoreprovider.net, вот так например:
http://highscoreprovider.net/crossdomain.xml
Содержимое из файла crossdomain.xml
имеет формат используемый Flash плеером. Очень вероятно что вы
обнаружите файл crossdomain.xml
уже на месте. Установки файла выглядят примерно так:
<?xml version="1.0"?>
<cross-domain-policy>
<allow-access-from domain="*"/>
</cross-domain-policy>
Когда этот файл размещен в http://highscoreprovider.net/crossdomain.xml, владелец домена объявляет что контент вебсервера может быть доступен любому вебплееру, пришедшему из любого домена.
Веб плеер Unity не поддерживает <allow-http-request-headers-from domain> и <site-control permitted-cross-domain-policies> теги. Обратите внимание, что crossdomain.xml
должен быть ASCII файлом.
Установка переменной окружения ENABLE_CROSSDOMAIN_LOGGING
в 1, позволит контролировать сообщения, сгенерированные в рантайме и декодировать файл crossdomain.xml
. На Mac вы можете установить глобальные переменные окружения в /etc/launchd.conf
. На PC используйте Control Panel->System And Security->System->Advanced system settings->Environment Variables…
Пример выхода с этой переменной окружения, когда веб плеер пытается получить изображение с удаленного сервера:
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
Во время работы редактора, сообщения записываются в Editor.log. Попытка прочитать crossdomain.xml
, некорректно сохраненный как utf16
, с BOM
, выдаст ошибку парсинга xml:
BuildFlashPolicy caught an exception while parsing http://www.remoteserver.com/crossdomain.xml: Expected element
Это потому что BOM
не ожидается. Использование не поддерживаемого utf16
файла без BOM
вернет:
BuildFlashPolicy caught an exception while parsing http://www.remoteserver.com/crossdomain.xml: Policy can't be constructed from empty stream.
Это потому что первый байт в этом файле нуль и парсер думает что он достиг конца файла. Crossdomain.xml
должен быть ASCII файлом.
Для подключения к конкретному хосту, веб плееру Unity необходима сокет политика. Это политика по умолчанию присваивается целевому хосту порта 843, но она может быть назначена и другим портам. Единственное различие - то что его нужно назначить вручную Security.PrefetchSocketPolicy(). Если вызываемое API размещено на порту выше 1024, политика может получить доступ только к таким портам.
Когда используется порт по умолчанию, это работает примерно так: веб плеер Unity пытается установить TCP сокет соединение к хосту, он сначала проверяет что хост-сервер будет проверять соединение. Он делает это путем открытия сокета TCP на порт 843, выдает запрос и ожидает получить политику сокета над новым соединением. Затем веб плеер Unity проверяет, позволяет ли политика сокета идти дальше, нет ли ошибок. Этот процесс происходит незаметно для пользовательского кода, который не нужно изменять для использования этой модели безопасности. Например, политика сокета может выглядеть примерно так:
<?xml version="1.0"?>
<cross-domain-policy>
<allow-access-from domain="*" to-ports="1200-1220"/>
</cross-domain-policy>"
Эта политика эффективно говорит: “Контент под любым доменом может свободно сделать сокет соединения в хостах 1200–1220”. Веб плеер Unity будет соблюдать это и отклонять любые попытки сокет соединения, используемые порт вне этого диапазона (будет выброшено исключение SecurityException).
Когда используется UDP соединения, политика может быть автоматически получена таким же образом, как и при TCP. Разница лишь в том, что при TCP автоматическое получение происходит когда вы подключаетесь к чему то (гарантирует вам разрешение подключатся к серверу), а при UDP, т.к. нет установления соединения, это случается когда вы вызываете метод любого API, который отправляет или получает данные (гарантирует разрешение отправлять/принимать траффик в сервер и из сервера).
Формат, используемый для политики сокетов такой же, как и у Flash плеера, кроме некоторых не поддерживаемых тегов. Веб плеер Unity поддерживает “*” как валидное значение для настроек домена и настройки “to-ports” являются обязательными.
<?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>
Политика сокетов, применяемая и к TCP и к UDP соединениям, может контролироваться одним сервером.
Для вашего удобства мы предоставляем небольшую программу, которая просто прослушивает порт 843. Во время соединения она получает строку запроса и будет отвечать только с валидным файлом политики сокета. Код сервера находится в корневой папке Unity, в Data/Tools/SocketPolicyServer на Windows или /Unity.app/Contents/Tools/SocketPolicyServer на OS X. Следует заметить, что предварительно настроенный, он может быть запущен на Mac, т.к. у него среда Mono. Для запуска просто введите “mono sockpol.exe”. Этот пример кода показывает корректное поведение сервера политики сокета. В частности, сервер ожидает получить заканчивающуюся нулем строку, содержащую <policy-file-request/>. При получении этой строки, он отсылает клиенту сокет политики xml документ. Кроме того, требуется запись в сокет заголовка и тела xml. Разделение операций записи в сокет заголовка и тела может быть причиной исключений безопасности, всвязи с получением Unity неполной политики. Если у вас возникли проблемы со своим собственным сервером, используйте данный пример. Он позволит вам определить, в чем именно проблема.
Треть сетевых библиотек, используемых для многопользовательских игр, должна быть способна работать с этими требованиями до тех пор, пока они не зависят от функционала peer 2 peer (см. ниже), но использовать выделенные серверы. Они даже иногда приходят из коробки с поддержкой хостинг политики.
Примечание: Несмотря на то, что crossdomain.xml
и файлы политики сокетов являются xml документами и вообщем аналогичны, их назначения очень разные. Crossdomain.xml
(применяемый для http запросов) выбирается в порту 80, где как для политики сокетов извлекается из порта 843 используя тривиальный сервер, что реализует <policy-file-request/>. Вы не можете использовать http сервер для выдачи файла политики сокетов, ни настроить сервер что просто посылает файл политики сокетов в ответ на сокет соединение порта 843. Отметим также, что каждый подключаемый сервер требует собственный сервер политики сокетов.
Можете использовать telnet
для подключения к серверу политики сокетов. Пример приведен ниже:
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$
В этом примере, telnet используется для соединения к локальному хосту на порту 843. Telnet отвечает с тремя линиями и ожидает от пользователя ввода данных. Пользователь вводит строку запрос политики <policy-file-request/>, которую сокет сервер политики получает и отвечает с политикой сокета. Затем сервер разрывает соединение, сообщая telnet что соединение было закрыто.
Вы не можете создавать слушающие сокеты в веб плеере, в таком случае не будет работать сервер. Поэтому веб плеер не может контактировать с каждым направлением (peer 2 peer). При использовании TCP сокетов, вы можете подключится к удаленным точкам только при условии что сокет политика системы позволяет это сделать. Для UDP это работает также, только концепт немного отличается, т.к. это протокол без установления соединения, вы не можете подключится/прослушивать и отправлять/принимать пакеты. Вы можете принимать пакеты только с сервера если он ответил с валидной политикой с позволяющим доступ с домена
тегом.
Сокеты и функции безопасности WWW существуют для защиты людей, установивших Unity Web Player. Без этих ограничений могут быть возможны подобные атаки:
Благодаря WWW и сокет безопасности, эта атака провалится, потому что перед скачиванием pdf файла, unity проверит http://internal.whitehouse.gov/crossdomain.xml и спросит сервер “данные, хранящиеся на вашем сервере доступны для публичного использования?”. Размещение crossdomain.xml на вебсервере можно считать ответом на этот вопрос. В этом примере системный оператор из internal.whitehouse.gov не разместит crossdomain.xml на сервере, что приведет к тому, что Unity не будет скачивать pdf.
К сожалению, в связи с защитой людей, установивших Unity Web Player, люди, разрабатывающие игры в Unity, должны учитывать эти меры безопасности. Подобные ограничения присутствуют во всех основных плагинах (Flash, Silverlight, Shockwave).
В связи с поиском баланса между защитой пользователей веб плеера и облегчением жизни разработчиков, мы реализовали исключения в механизме безопасности:
Вы можете позволить скачивать изображения с сервера не имеющего файл crossdomain.xml. Однако, единственная вещь, которую вы можете сделать с этими изображениями - использовать их в качестве текстур в сцене. На них нельзя использовать GetPixel(). Также запрещено читать обратно с экрана. Обе попытки приведут к SecurityException:
SecurityException: No read access to the texture data:
at (wrapper managed-to-native) UnityEngine.Texture2D:GetPixel (int,int)
Скачивать изображение, так долго, как разработчик не получает к нему доступ, это нормально. Вы можете отображать это для пользователя, но не можете отправить байты изображения обратно серверу. Если вам нужен доступ к пиксельным данным, разместите файл crossdomain.xml
на сервер, из которого извлекается изображение.