RFC 6455 предоставляет полный список соображений безопасности для WebSockets. Некоторые из них запечены в самом протоколе, а другие нуждаются в дополнительном объяснении того, как их можно достичь на конкретном сервере. Давайте поговорим о безопасности, встроенной в сам протокол:
- Заголовок Origin в HTTP-запросе включает только информацию, необходимую для идентификации участника (веб-страницы, JavaScript или любого другого клиента), который инициировал запрос (обычно это схема, хост и порт инициирующего источника). Для WebSockets это поле заголовка включено в открывающее рукопожатие клиента. Это используется для информирования сервера о происхождении скрипта, генерирующего запрос соединения WebSocket. Затем сервер может принять решение принять или отклонить запрос квитирования соответственно. Это позволяет серверу защищать от несанкционированного использования сервера WebSocket из разных источников с помощью сценариев, использующих API WebSocket в браузере. Например, если образец Java EE 7 WebSocket Chat развернут в WildFly и доступен по адресу localhost: 8080 / chat / then заголовок источника — «http: // localhost: 8080». Клиенты без браузера могут использовать заголовок Origin для указания источника запроса. Серверы WebSocket должны быть осторожны при получении таких запросов.
- Открывающее рукопожатие WebSocket от клиента должно содержать поля заголовка HTTP Sec-WebSocket-Key и Sec-WebSocket-Version. XMLHttpRequest может использоваться для создания HTTP-запросов и позволяет устанавливать заголовки как часть этого запроса как:
0102030405060708091011
xhr.onreadystatechange = function (){if(xhr.readyState ==4&& xhr.status ==200){document.getElementById("myDiv").innerHTML = xhr.responseText;}}xhr.setRequestHeader("foo","bar");xhr.setRequestHeader("Sec-WebSocket-Key","myKey");xhr.send();Если XMLHttpRequest пытается установить какие-либо поля заголовка, начиная с Sec-, то они игнорируются. Таким образом, злоумышленник не может имитировать соединение WebSocket с сервером с помощью API-интерфейсов HTML и JavaScript.
В дополнение к этим двум основным способам WebSockets можно защитить с помощью механизма аутентификации клиента, доступного для любых серверов HTTP. Этот технический совет покажет, как аутентифицировать WebSockets Java EE 7, развернутые в WildFly.
Давайте начнем!
- Клон Java EE 7 Примеры рабочего пространства:
1
git clone https://github.com/javaee-samples/javaee7-samples.git - Пример «websocket / endpoint-security» показывает, как можно выполнить аутентификацию клиента до того, как клиент инициирует рукопожатие WebSocket. Это вызвано включением следующего дескриптора развертывания:
01020304050607080910111213141516171819
<security-constraint><web-resource-collection><web-resource-name>WebSocket Endpoint</web-resource-name><url-pattern>/*</url-pattern><http-method>GET</http-method></web-resource-collection><auth-constraint><role-name>g1</role-name></auth-constraint></security-constraint><login-config><auth-method>BASIC</auth-method><realm-name>file</realm-name></login-config><security-role><role-name>g1</role-name></security-role>Некоторые ключевые моменты, чтобы понять об этом дескрипторе:
- <url-pattern> указывает, что любой запрос к этому приложению будет запрашиваться для аутентификации
- <auth-constraint> определяет роль безопасности, которая может получить доступ к этому ресурсу
- <login-config> показывает, что файловая область используется с базовой аутентификацией
- <security-role> определяет роли безопасности, на которые ссылается это приложение
В нашем конкретном случае страница, которая создает соединение WebSocket, защищена базовой аутентификацией.
- Загрузите WildFly 8.1 , разархивируйте и добавьте нового пользователя, запустив следующий скрипт:
1
./bin/add-user.sh -a -u u1 -p p1 -g g1Это добавит пользователя «u1» с паролем «p1» в группу «g1». Указанная здесь группа должна соответствовать, как определено в <role-name> в дескрипторе развертывания.
- Разверните образец, дав команду:
1
mvn wildfly:deploy
Теперь, когда к приложению обращаются по адресу localhost: 8080 / endpoint-security, появляется диалоговое окно безопасности, как показано:
Введите «u1» в качестве имени пользователя и «p1» в качестве пароля для аутентификации. Эти учетные данные определены в группе «g1», на которую ссылается дескриптор развертывания. Любые другие учетные данные будут продолжать возвращать диалог.
Как только запрос успешно аутентифицирован, соединение WebSocket устанавливается и в браузере отображается сообщение.
Если вы заинтересованы в защите только URL-адреса WebSocket, измените шаблон URL с:
|
1
|
|
чтобы:
|
1
|
/websocket |
В файле websocket.js измените URL-адрес, чтобы создать конечную точку WebSocket из:
|
1
|
var wsUri = "ws://" + document.location.host + document.location.pathname + "websocket"; |
чтобы:
|
1
|
var wsUri = "ws://u1:p1@" + document.location.host + document.location.pathname + "websocket"; |
Обратите внимание, как учетные данные передаются в самом URL. Начиная с Google Chrome 38.0.2125.104, всплывающее окно браузера не отображается, если для проверки подлинности требуется только URL-адрес WebSocket.
Следующий технический совет объяснит, как защитить WebSocket с использованием протокола wss:// .
| Ссылка: | Защита WebSockets с использованием имени пользователя / пароля и Servlet Security от нашего партнера по JCG Аруна Гупта в блоге Miles to go 2.0… . |
