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… . |