Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Предупреждение
Эта документация не подходит для последней версии SignalR. Посмотрите на ASP.NET Core SignalR.
В этой статье описываются проблемы безопасности, которые необходимо учитывать при разработке приложения SignalR.
Версии программного обеспечения, используемые в этом разделе
- Visual Studio 2013
- .NET 4.5
- SignalR версии 2
Предыдущие версии этого раздела
Сведения о более ранних версиях SignalR см. в разделе SignalR более ранних версий.
Вопросы и комментарии
Оставьте отзыв о том, что вам понравилось в этом руководстве и что стоит улучшить в комментариях внизу страницы. Если у вас есть вопросы, которые не связаны напрямую с руководством, их можно опубликовать на форуме ASP.NET SignalR или StackOverflow.com.
Обзор
Этот документ содержит следующие разделы:
Основные понятия безопасности SignalR
Проверка подлинности и авторизация
SignalR не предоставляет никаких функций для проверки подлинности пользователей. Вместо этого вы интегрируете функции SignalR в существующую структуру проверки подлинности для приложения. Вы выполняете проверку подлинности пользователей, как правило, в приложении и работаете с результатами проверки подлинности в коде SignalR. Например, вы можете аутентифицировать ваших пользователей с помощью аутентификации форм ASP.NET, а затем в вашем центре настроить, какие пользователи или роли имеют право вызвать метод. В вашем хабе можно также передать клиенту данные аутентификации, такие как имя пользователя или информация о роли, к которой относится пользователь.
SignalR предоставляет атрибут Authorize , чтобы указать, какие пользователи имеют доступ к концентратору или методу. Атрибут Authorize применяется либо к концентратору, либо к определенным методам в концентраторе. Без атрибута Authorize все общедоступные методы в концентраторе доступны клиенту, подключенного к концентратору. Дополнительные сведения об центрах см. в разделе "Проверка подлинности и авторизация для Центров SignalR".
Атрибут Authorize применяется к концентраторам, но не к постоянным подключениям. Чтобы применить правила авторизации при использовании PersistentConnection метода, необходимо переопределить AuthorizeRequest метод. Дополнительные сведения о постоянных подключениях см. в разделе "Проверка подлинности и авторизация для постоянных подключений SignalR".
Маркер подключения
SignalR снижает риск выполнения вредоносных команд, проверяя удостоверение отправителя. Для каждого запроса клиент и сервер передают маркер подключения, содержащий идентификатор подключения и имя пользователя для прошедших проверку подлинности пользователей. Идентификатор подключения однозначно идентифицирует каждый подключенный клиент. Сервер случайным образом создает идентификатор подключения при создании нового подключения и сохраняет этот идентификатор в течение длительности подключения. Механизм проверки подлинности для веб-приложения предоставляет имя пользователя. SignalR использует шифрование и цифровую подпись для защиты токена соединения.
Для каждого запроса сервер проверяет содержимое маркера, чтобы убедиться, что запрос поступает от указанного пользователя. Имя пользователя должно соответствовать идентификатору подключения. Проверяя идентификатор подключения и имя пользователя, SignalR запрещает злоумышленнику легко олицетворение другого пользователя. Если сервер не может проверить маркер подключения, запрос завершается сбоем.
Так как идентификатор подключения является частью процесса проверки, не следует отображать идентификатор подключения одного пользователя другим пользователям или хранить значение на клиенте, например в файле cookie.
Маркеры подключения и другие типы маркеров
Маркеры подключения иногда помечаются средствами безопасности, так как они, как представляется, являются маркерами сеансов или маркерами проверки подлинности, что представляет угрозу при наличии.
Маркер подключения SignalR не является маркером проверки подлинности. Этот процесс используется для подтверждения того, что пользователь, выполняющий этот запрос, является тем же, кто создал соединение. Маркер подключения необходим, так как ASP.NET 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 из внешнего домена. 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>
Кроме того, состояние проверки подлинности пользователя может измениться, если ваш сайт использует скользящее истечение срока действия с Forms Authentication, и нет активности, чтобы поддерживать файл cookie проверки подлинности действительным. В этом случае пользователь будет выходить из системы, и имя пользователя больше не будет совпадать с именем пользователя в маркере подключения. Эту проблему можно устранить, добавив некоторый скрипт, который периодически запрашивает ресурс на веб-сервере, чтобы сохранить файл cookie проверки подлинности допустимым. В следующем примере показано, как запрашивать ресурс каждые 30 минут.
$(function () {
setInterval(function() {
$.ajax({
url: "Ping.aspx",
cache: false
});
}, 1800000);
});
Автоматически созданные прокси-файлы JavaScript
Если вы не хотите включать все центры и методы в прокси-файл JavaScript для каждого пользователя, можно отключить автоматическое создание файла. Этот параметр можно выбрать, если у вас есть несколько центров и методов, но не требуется, чтобы каждый пользователь знал обо всех методах. Вы отключаете автоматическое создание, задав параметру EnableJavaScriptProxies значение false.
var hubConfiguration = new HubConfiguration();
hubConfiguration.EnableJavaScriptProxies = false;
app.MapSignalR(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.");
}
}