RequireHttps и маршрутизация на https URL
Я использую атрибут RequireHttps для большинства действий в моем контроллере пользователя, который обрабатывает вход в систему и мои защищенные https-страницы.
На моей домашней странице, которая является http, у меня есть ссылка на мою страницу входа в систему (MVC 4 Razor View):-
<a href="@Url.Action("Login", "User")">Login</a>
Ссылка правильно переходит на страницу входа с адресом https. Однако, когда я просматриваю журнал IIS, я вижу две записи для URL-адреса входа: одну на порт 80 и одну на порт 443.
Это проблема, о которой я должен беспокоиться?
Я знаю, что на моем @Url.Action я мог включить режим https, но не уверен, что это лучший способ. Кроме того, это удаляет порт, что раздражает при использовании IIS Express в VS 2012. Затем мне нужно было бы расширить действие @Url.Action, чтобы включить порт hostname:port.
Поэтому я просто проверяю, (а) должно ли это быть проблемой, и (б) если есть проблема, есть ли какие-либо другие способы принуждения URL к https.
3 ответа
Большинство учебных пособий согласятся с тем, что, имея сайт в смешанном режиме (как HTTP, так и HTTPS), вы отказываетесь от цели SSL (для определенных путей требуется SSL, а затем переключение обратно на соединение без SSL). После того, как вы переключитесь на HTTPS, рекомендуется заставить пользователя продолжать использовать HTTPS для всего, по крайней мере, до тех пор, пока он не выйдет из системы. У меня есть один сайт, использующий HTTPS, и как только вы заходите на сайт, я просто использую правило перезаписи URL, чтобы переключить пользователя на HTTPS, и разрешен только HTTPS.
<rewrite>
<rules>
<rule name="Redirect HTTP to HTTPS" stopProcessing="true">
<match url="(.*)"/>
<conditions>
<add input="{HTTPS}" pattern="^OFF$"/>
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="SeeOther"/>
</rule>
</rules>
</rewrite>
После того, как вы это сделаете, также рекомендуется установить куки аутентификации, чтобы требовать HTTPS. Для проверки подлинности с помощью форм это так же просто, как установить следующее в вашем файле web.config.
<authentication>
<forms requireSSL="true" />
</authentication>
Я также рекомендовал бы взглянуть на некоторые заголовки, которые можно настроить, чтобы браузеры корректно обрабатывали сайт, например, используя Strict-Transport-Security, чтобы показать, что сайту требуется SSL. Имейте в виду, что, хотя заголовки являются отличной дополнительной мерой, которую вы можете предпринять, в конечном счете, они оставлены на усмотрение браузера и не должны полагаться исключительно на них.
Я рекомендую эти шаги, потому что я не страдаю от описываемого вами симптома и надеюсь, что они помогут решить проблему, которую вы заметили в журналах.
ПОПРАВКА: О, и я также забыл упомянуть, HTTPS немного более интенсивно устанавливает соединение, чем обычный старый HTTP. Не так много в общем плане вещей, но все же это что-то. Я бы порекомендовал вам использовать HTTP Keep Alive, чтобы уменьшить эту нагрузку.
ОБНОВЛЕНИЕ: общение через SSL не означает, что вы прошли аутентификацию. Это просто означает, что вы говорите по безопасному / зашифрованному соединению.
Возьмем ваш пример с Amazon, скажем так. Если вы зайдете на сайт, вы просто получите нормальное соединение по HTTP. Вы не авторизованы, вы просто просматриваете сайт. Если вы хотите, вы можете переключиться на HTTPS, и вы все равно получите тот же сайт, но вы еще не вошли в систему. Теперь, если вы попытаетесь войти в систему, вы будете перенаправлены так, чтобы вы общались по SSL (если вы еще этого не сделали), как отмечено в прозвище HTTPS. Даже после того, как вы действительно войдете в систему, вы все равно будете общаться по SSL. Даже если вы попытаетесь вручную отключить SSL, когда вы вошли в систему, удалив символ S из протокольной части URL-адреса, он все равно вернется к использованию HTTPS. Это правильный способ сделать это. Обычно рекомендуется не возвращаться в незашифрованный сеанс после аутентификации. Обычно это делается для того, чтобы избежать перехвата сеанса, поскольку ваш куки-файл аутентификации никогда не будет отправлен по обычному HTTP. Убедитесь, что ресурсы, имеющиеся у вас на внешних источниках, находятся на сайтах, которым вы доверяете. Доступ к внешним ресурсам во время соединения HTTP также должен осуществляться через соединение SSL. Опять же, только потому, что вы общаетесь по SSL, не означает, что вы вошли в эти источники. Для моего приложения это 100% доступ через SSL, но у меня также есть аналитика Google и интеграция карт Google на сайте (очевидно, что оба являются внешними по отношению к моему домену). Я просто проверяю, общаюсь ли я с Google по SSL. Мне не нужно входить в Google, чтобы использовать любую из этих вещей. То же самое касается ваших внешних изображений. Просто убедитесь, что ваш URL-адрес, используемый для ссылки на эти внешние изображения, определен с помощью HTTPS, так что он использует SSL.
ОБНОВЛЕНИЕ: Причина, по которой вы получаете два попадания в журнал, например, в том, что ваша ссылка для входа запрашивается по HTTP, атрибут Обязательный HTTPS-запрос первым обнаруживает, что вы не используете SSL, и перенаправляет вас обратно к себе с помощью HTTPS. протокол. Если вы обновите свой URL-адрес ActionLink, вы можете обойти это, но, как вы знаете, это будет ужасно.
Url.Action("Login", "User", null, "https", Request.Url.Host)
Добавьте это в ваш global.ascx
protected void Application_BeginRequest()
{
if (!Context.Request.IsSecureConnection)
Response.Redirect(Context.Request.Url.ToString().Replace
("http:", "https:"));
}
Это приведет к тому, что все запросы будут преобразованы в https вместо http
Я пишу расширение для Url.Action, которое генерирует правильный протокол в зависимости от декорации атрибута. Я позволю тебе проверить
public static class Extensions
{
public static string SecuredAction(this UrlHelper helper, string action, string controller)
{
bool requireSSL = false;
var route = System.Web.Routing.RouteTable.Routes.Select(r => r as System.Web.Routing.Route) .Where(r =>
r != null && r.Defaults != null && r.Defaults["controller"] != null && r.Defaults["controller"].ToString().Equals(controller, StringComparison.InvariantCultureIgnoreCase)
&& r.Defaults["action"] != null && r.Defaults["action"].ToString().Equals(action, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();
if(route == null)
return helper.Action(action, controller);
//Get the method and check if requiere ssl
MemberInfo method = route.DataTokens["TargetActionMethod"] as MemberInfo;
requireSSL = method.CustomAttributes.Any(a => a.AttributeType == typeof(RequireHttps)) || method.DeclaringType.CustomAttributes.Any(a => a.AttributeType == typeof(RequireHttps));
//Return the correct protocol
if(helper.RequestContext.HttpContext.Request.IsSecureConnection && !requireSSL)
return helper.Action(action, controller, null, "http");
if (!helper.RequestContext.HttpContext.Request.IsSecureConnection && requireSSL)
return helper.Action(action, controller, null, "https");
return helper.Action(action, controller);
}
}