Общие сведения о безопасности SignalR (SignalR 1.x)
Патрик Флетчер (Patrick Fletcher), Том ФитцМаккен (Tom FitzMacken)
Предупреждение
Эта документация не подходит для последней версии SignalR. Ознакомьтесь с ASP.NET Core SignalR.
В этой статье описываются проблемы безопасности, которые необходимо учитывать при разработке приложения SignalR.
Общие сведения
Этот документ содержит следующие разделы.
Основные понятия безопасности SignalR
Аутентификация и авторизация
SignalR предназначен для интеграции в существующую структуру проверки подлинности для приложения. Он не предоставляет никаких функций для проверки подлинности пользователей. Вместо этого вы выполняете проверку подлинности пользователей, как обычно в приложении, а затем работаете с результатами проверки подлинности в коде SignalR. Например, вы можете пройти проверку подлинности пользователей с помощью ASP.NET форм проверки подлинности, а затем в центре принудительно определить, какие пользователи или роли имеют разрешение на вызов метода. В центре можно также передать клиенту сведения о проверке подлинности, такие как имя пользователя или принадлежность пользователя к роли.
SignalR предоставляет атрибут Authorize , чтобы указать, какие пользователи имеют доступ к концентратору или методу. Атрибут Authorize применяется к концентратору или определенным методам в концентраторе. Без атрибута Authorize все открытые методы в концентраторе доступны для клиента, подключенного к концентратору. Дополнительные сведения о центрах см. в статье Проверка подлинности и авторизация для Центров SignalR.
Атрибут Authorize
используется только с концентраторами. Чтобы применить правила авторизации при использовании , PersistentConnection
необходимо переопределить AuthorizeRequest
метод . Дополнительные сведения о постоянных подключениях см. в разделе Проверка подлинности и авторизация для постоянных подключений SignalR.
Маркер подключения
SignalR снижает риск выполнения вредоносных команд, проверяя удостоверение отправителя. Маркер подключения, содержащий идентификатор подключения и имя пользователя для пользователей, прошедших проверку подлинности, передается между клиентом и сервером для каждого запроса. Идентификатор подключения — это уникальный идентификатор, который случайным образом создается сервером при создании нового подключения и сохраняется на протяжении всего соединения. Имя пользователя предоставляется механизмом проверки подлинности для веб-приложения. Маркер подключения защищен с помощью шифрования и цифровой подписи.
Для каждого запроса сервер проверяет содержимое маркера, чтобы убедиться, что запрос поступает от указанного пользователя. Имя пользователя должно соответствовать идентификатору подключения. Проверяя идентификатор подключения и имя пользователя, SignalR не позволяет злоумышленнику легко олицетворять другого пользователя. Если серверу не удается проверить маркер подключения, запрос завершается ошибкой.
Так как идентификатор подключения является частью процесса проверки, не следует раскрывать идентификатор подключения одного пользователя другим пользователям или хранить значение на клиенте, например в файле cookie.
Повторное присоединение групп при повторном подключении
По умолчанию приложение SignalR автоматически повторно назначит пользователя соответствующим группам при повторном подключении после временного сбоя, например при разрыве и повторном подключении до истечения времени ожидания подключения. При повторном подключении клиент передает маркер группы, включающий идентификатор подключения и назначенные группы. Маркер группы имеет цифровую подпись и шифруется. Клиент сохраняет тот же идентификатор подключения после повторного подключения; следовательно, идентификатор подключения, передаваемый от повторно подключенного клиента, должен соответствовать предыдущему идентификатору подключения, используемому клиентом. Эта проверка предотвращает передачу злоумышленником запросов на присоединение к несанкционированным группам при повторном подключении.
Однако важно отметить, что срок действия маркера группы не истекает. Если пользователь в прошлом входил в группу, но был запрещен в ней, он может имитировать маркер группы, включающий запрещенную группу. Если необходимо безопасно управлять пользователями, принадлежащими к тем или иным группам, необходимо хранить эти данные на сервере, например в базе данных. Затем добавьте в приложение логику, которая проверяет на сервере, принадлежит ли пользователь к группе. Пример проверки членства в группах см. в разделе Работа с группами.
Автоматическое повторное присоединение к группам применяется только при повторном подключении после временного сбоя. Если пользователь отключается путем перехода от приложения или перезапуска приложения, приложение должно обрабатывать, как добавить этого пользователя в правильные группы. Дополнительные сведения см. в разделе Работа с группами.
Как SignalR предотвращает подделку межсайтовых запросов
Подделка межсайтовых запросов (CSRF) — это атака, при которой вредоносный сайт отправляет запрос на уязвимый сайт, где пользователь в данный момент выполнил вход. SignalR предотвращает CSRF, делая крайне маловероятным, чтобы вредоносный сайт создавал допустимый запрос для приложения SignalR.
Описание атаки CSRF
Ниже приведен пример атаки CSRF:
Пользователь входит в
www.example.com
, используя проверку подлинности на основе форм.Сервер выполняет проверку подлинности пользователя. Ответ с сервера содержит файл cookie для проверки подлинности.
Без выхода пользователь посещает вредоносный веб-сайт. Этот вредоносный сайт содержит следующую html-форму:
<h1>You Are a Winner!</h1> <form action="http://example.com/api/account" method="post"> <input type="hidden" name="Transaction" value="withdraw" /> <input type="hidden" name="Amount" value="1000000" /> <input type="submit" value="Click Me"/> </form>
Обратите внимание, что действие формы публикуется на уязвимом сайте, а не на вредоносном сайте. Это "межсайтовая" часть CSRF.
Пользователь нажимает кнопку "Отправить". Браузер включает файл cookie проверки подлинности с запросом.
Запрос выполняется на сервере example.com с контекстом проверки подлинности пользователя и может выполнять все, что разрешено пользователю, прошедшему проверку подлинности.
Хотя в этом примере пользователю требуется нажать кнопку формы, вредоносная страница может так же легко запустить скрипт, который отправляет запрос AJAX в приложение SignalR. Кроме того, использование SSL не предотвращает атаку CSRF, так как вредоносный сайт может отправить запрос "https://".
Как правило, атаки CSRF возможны на веб-сайты, использующие файлы cookie для проверки подлинности, так как браузеры отправляют все соответствующие файлы cookie на целевой веб-сайт. Однако атаки CSRF не ограничиваются использованием файлов cookie. Например, базовая и дайджест-проверка подлинности также уязвимы. После входа пользователя с помощью обычной или дайджест-проверки подлинности браузер автоматически отправляет учетные данные до завершения сеанса.
Устранение рисков CSRF, принятых SignalR
SignalR выполняет следующие действия, чтобы предотвратить создание допустимых запросов к приложению SignalR на вредоносном сайте. Эти действия выполняются по умолчанию и не требуют каких-либо действий в коде.
- Отключение междоменных запросов
По умолчанию междоменные запросы отключены в приложении SignalR, чтобы запретить пользователям вызывать конечную точку SignalR из внешнего домена. Любой запрос, поступающий из внешнего домена, автоматически считается недопустимым и блокируется. Рекомендуется оставить это поведение по умолчанию. В противном случае вредоносный сайт может обмануть пользователей при отправке команд на ваш сайт. Если вам нужно использовать междоменные запросы, см. статью Установка междоменного подключения . - Передача маркера подключения в строке запроса, а не в файл cookie
SignalR передает маркер подключения в виде значения строки запроса, а не в виде файла cookie. Если маркер подключения не хранится в виде файла cookie, он не будет случайно переадресован браузером при обнаружении вредоносного кода. Кроме того, маркер подключения не сохраняется за пределами текущего подключения. Таким образом, злоумышленник не может выполнить запрос с учетными данными проверки подлинности другого пользователя. - Проверка маркера подключения
Как описано в разделе Маркер подключения , серверу известно, какой идентификатор подключения связан с каждым пользователем, прошедшим проверку подлинности. Сервер не обрабатывает запросы от идентификатора подключения, который не соответствует имени пользователя. Маловероятно, что злоумышленник может угадать допустимый запрос, так как злоумышленник должен знать имя пользователя и текущий случайным образом созданный идентификатор подключения. Этот идентификатор подключения становится недействительным, как только подключение будет завершено. Анонимные пользователи не должны иметь доступа к какой-либо конфиденциальной информации.
Рекомендации по безопасности SignalR
Протокол SSL
Протокол SSL использует шифрование для защиты передачи данных между клиентом и сервером. Если приложение SignalR передает конфиденциальную информацию между клиентом и сервером, используйте ssl для транспорта. Дополнительные сведения о настройке SSL см. в статье Настройка SSL в IIS 7.
Не используйте группы в качестве механизма безопасности
Группы — это удобный способ сбора связанных пользователей, но они не являются безопасным механизмом ограничения доступа к конфиденциальной информации. Это особенно актуально, когда пользователи могут автоматически повторно присоединиться к группам во время повторного подключения. Вместо этого рассмотрите возможность добавления привилегированных пользователей в роль и ограничения доступа к методу концентратора только для членов этой роли. Пример ограничения доступа на основе роли см. в разделе Проверка подлинности и авторизация для Центров SignalR. Пример проверки доступа пользователей к группам при повторном подключении см. в разделе Работа с группами.
Безопасная обработка входных данных от клиентов
Все входные данные от клиентов, предназначенные для трансляции другим клиентам, должны быть закодированы, чтобы злоумышленник не отправлял скрипт другим пользователям. Лучше всего кодировать сообщения на принимающих клиентах, а не на сервере, так как приложение SignalR может иметь множество различных типов клиентов. Таким образом, кодирование HTML работает для веб-клиента, но не для других типов клиентов. Например, метод веб-клиента для отображения сообщения чата будет безопасно обрабатывать имя пользователя и сообщение путем вызова html()
функции .
chat.client.addMessageToPage = function (name, message) {
// Html encode display name and message.
var encodedName = $('<div />').text(name).html();
var encodedMsg = $('<div />').text(message).html();
// Add the message to the page.
$('#discussion').append('<li><strong>' + encodedName
+ '</strong>: ' + encodedMsg + '</li>');
};
Согласование изменения состояния пользователя с активным подключением
Если состояние проверки подлинности пользователя изменяется при наличии активного подключения, он получит сообщение об ошибке "Удостоверение пользователя не может измениться во время активного подключения SignalR". В этом случае приложение должно повторно подключиться к серверу, чтобы убедиться, что идентификатор подключения и имя пользователя согласованы. Например, если приложение позволяет пользователю выйти из системы при наличии активного подключения, имя пользователя для подключения больше не будет совпадать с именем, которое передается для следующего запроса. Вам потребуется остановить подключение, прежде чем пользователь выйдет из системы, а затем перезапустить его.
Однако важно отметить, что большинству приложений не нужно вручную останавливать и запускать подключение. Если приложение перенаправляет пользователей на отдельную страницу после выхода из системы, например поведение по умолчанию в приложении веб-формы или приложении MVC, или обновляет текущую страницу после выхода, активное подключение автоматически отключается и не требует каких-либо дополнительных действий.
В следующем примере показано, как остановить и запустить подключение при изменении состояния пользователя.
<script type="text/javascript">
$(function () {
var chat = $.connection.sampleHub;
$.connection.hub.start().done(function () {
$('#logoutbutton').click(function () {
chat.connection.stop();
$.ajax({
url: "Services/SampleWebService.svc/LogOut",
type: "POST"
}).done(function () {
chat.connection.start();
});
});
});
});
</script>
Кроме того, состояние проверки подлинности пользователя может измениться, если на сайте используется скользящий срок действия с проверкой подлинности с помощью форм и нет действий по поддержанию допустимости файла cookie проверки подлинности. В этом случае пользователь выйдет из системы, и имя пользователя больше не будет совпадать с именем пользователя в маркере подключения. Эту проблему можно устранить, добавив скрипт, который периодически запрашивает ресурс на веб-сервере, чтобы сохранить действительный файл cookie проверки подлинности. В следующем примере показано, как запрашивать ресурс каждые 30 минут.
$(function () {
setInterval(function() {
$.ajax({
url: "Ping.aspx",
cache: false
});
}, 1800000);
});
Автоматически созданные прокси-файлы JavaScript
Если вы не хотите включать все концентраторы и методы в прокси-файл JavaScript для каждого пользователя, можно отключить автоматическое создание файла. Этот параметр можно выбрать, если у вас есть несколько концентраторов и методов, но не все пользователи должны знать обо всех методах. Автоматическое создание можно отключить, задав для EnableJavaScriptProxies значение false.
var hubConfiguration = new HubConfiguration();
hubConfiguration.EnableJavaScriptProxies = false;
RouteTable.Routes.MapHubs("/signalr", hubConfiguration);
Дополнительные сведения о файлах прокси-сервера JavaScript см. в разделе Созданный прокси-сервер и его действия.
Исключения
Не следует передавать объекты исключений клиентам, так как объекты могут предоставлять клиентам конфиденциальную информацию. Вместо этого вызовите метод на клиенте, который отображает соответствующее сообщение об ошибке.
public Task SampleMethod()
{
try
{
// code that can throw an exception
}
catch(Exception e)
{
// add code to log exception and take remedial steps
return Clients.Caller.DisplayError("Sorry, the request could not be processed.");
}
}