Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Предупреждение
Эта документация не подходит для последней версии 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>
Кроме того, состояние проверки подлинности пользователя может измениться, если на вашем сайте используется скользящий срок действия для проверки подлинности в рамках форм Windows, и отсутствует активность, чтобы сохранить файл 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.");
}
}