Asp.Net Core Google аутентификация

Мое приложение работает на Google Compute Engine. Nginx используется в качестве прокси-сервера. Nginx был настроен на использование SSL. Ниже приведено содержимое /etc/nginx/sites-available/default:

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name mywebapp.com;
    return 301 https://$server_name$request_uri;
}
server {
    listen 443 ssl http2 default_server;
    listen [::]:443 ssl http2 default_server;
    include snippets/ssl-mywebapp.com.conf;
    include snippets/ssl-params.conf;
    root /home/me/MyWebApp/wwwroot;
    location /.well-known/ {
    }
    location / {
        proxy_pass http://localhost:5000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection keep-alive;
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

В Startup.cs у меня есть:

app.UseGoogleAuthentication(new GoogleOptions()
{
    ClientId = Configuration["Authentication:Google:ClientId"],
    ClientSecret = Configuration["Authentication:Google:ClientSecret"],
});

Теперь в Google Cloud Platform мне нужно указать URI авторизованного перенаправления. Если я введу следующее, мое веб-приложение будет работать как положено:

http://mywebapp.com/signin-google

Но это не сработает, если https используется; браузер отображает следующую ошибку:

The redirect URI in the request, http://mywebapp.com/signin-google, does
not match the ones authorized for the OAuth client.

В этом случае безопасно ли использовать http в качестве авторизованного URI перенаправления? Какая конфигурация мне нужна, если я хочу, чтобы это был https?

2 ответа

Решение

Это происходит потому, что ваше приложение, которое работает за обратным прокси-сервером, не имеет ни малейшего представления, что первоначально запрос пришел по HTTPS.

Терминальный прокси SSL/TLS

Описанная в вопросе конфигурация обратного прокси-сервера называется обратным прокси-сервером завершения SSL/TLS. Это означает, что между клиентом и прокси-сервером устанавливается безопасный трафик. Прокси-сервер расшифровывает запрос и затем перенаправляет его в приложение по протоколу HTTP.

Проблема с этой конфигурацией состоит в том, что приложение позади нее не знает, что клиент отправил запрос по HTTPS. Поэтому, когда дело доходит до перенаправления к себе, он использует HttpContext.Request.Scheme, HttpContext.Request.Host а также HttpContext.Request.Port создать действительный URL для перенаправления.

Заголовки X-Forwarded-* HTTP

Это где X-Forwarded-* Заголовки вступают в игру. Чтобы приложение знало, что запрос изначально идет через прокси-сервер через HTTPS, нам нужно настроить прокси-сервер на X-Forwarded-For а также X-Forwarded-Proto Заголовки HTTP.

location / {
    proxy_pass http://localhost:5000;
    proxy_http_version 1.1;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection keep-alive;
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
}

Хорошо, теперь, если мы вернемся к приложению ASP.NET Core и посмотрим на входящий HTTP-запрос, мы увидим оба X-Forwarded-* заголовки установлены, однако URL перенаправления все еще использует схему HTTP.

Промежуточное ПО перенаправленных заголовков

В основном это промежуточное программное обеспечение переопределяет HttpContext.Request.Scheme а также HttpContext.Connection.RemoteIpAddress к значениям, которые были предоставлены X-Forwarded-Proto а также X-Forwarded-For заголовки соответственно. Чтобы это произошло, давайте добавим его в конвейер, добавив следующую строку где-то в начале Startup.Configure() метод.

        var forwardedHeadersOptions = new ForwardedHeadersOptions
        {
            ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto,
            RequireHeaderSymmetry = false
        };
        forwardedHeadersOptions.KnownNetworks.Clear();
        forwardedHeadersOptions.KnownProxies.Clear();

        app.UseForwardedHeaders(forwardedHeadersOptions);

Это должно в конечном итоге заставить ваше приложение создавать допустимые URL-адреса по схеме HTTPS.

Моя история

Код выше выглядит иначе, чем предлагает Microsoft. Если мы посмотрим в документации, их код будет выглядеть немного короче:

app.UseForwardedHeaders(new ForwardedHeadersOptions
{
     ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});

Однако это не сработало для меня. Также по комментариям под этим вопросом я не одинок.

У меня nginx, настроенный в качестве обратного прокси-сервера для приложения ASP.NET Core, работающего в Docker-контейнере. Все стало сложнее после того, как я поставил все за Amazon Load Balancer (ELB).

Сначала я последовал совету из документации, но у меня это не сработало. В моем приложении появилось следующее предупреждение:

Несоответствие количества параметров между X-Forwarded-For и X-Forwarded-Proto

Затем я посмотрел на X-Forwarded-* Заголовки и понял, что они были разной длины. X-Forwarded-For заголовок содержал 2 записи (IP-адреса, разделенные запятыми), а X-Forwarded-Proto только одна запись https, Вот как я подошел к настройке собственности RequireHeaderSymmetry в false,

Ну, я избавился от предупреждающего сообщения "Счетчик параметров...", но сразу после этого я столкнулся с другим странным отладочным сообщением:

Неизвестный прокси: 172.17.0.6:44624

Изучив исходный код Forwarded Headers Middleware, я наконец понял, что мне нужно либо очистить оба KnownNetworks а также KnownProxies Коллекции ForwardedHeadersOptions или добавить мою сеть докеров 172.17.0.1/16 к списку известных сетей. Сразу после этого у меня наконец-то все заработало.

PS: для тех, кто устанавливает ограничение SSL/TLS на балансировщике нагрузки (например, Amazon Load Balancer или ELB), НЕ устанавливайте заголовок X-Forwarded-Proto в конфигурации nginx. Это переопределит правильно https значение, которое пришло от баланса нагрузки к http Схема и URL перенаправления будут неверными. Я еще не нашел, как просто добавить схему, используемую в nginx, в заголовок вместо того, чтобы переопределять его.

Для пользователей apache необходимо добавить только один заголовок: RequestHeader установить X-Forwarded-Proto "https"

Во-первых, нужно убедиться, что mod_headers включен.

Другие вопросы по тегам