Углубленный анализ безопасности Spring OAuth2

задняя часть сервер Spring Безопасность

Углубленный анализ безопасности Spring OAuth2

1. Обзор OAuth2

1.1.Основной процесс OAuth2

Без лишних слов, начнем с картинки:

OAuth2流程图

Проанализируйте волну:

  • client: стороннее приложение (например, приложение или внешний интерфейс)
  • ResourceВладелец: владелец ресурса (т.е. пользователь)
  • Authentication Server: Служба аутентификации авторизации (распространение токена доступа)
  • Resource Server: Сервер ресурсов (хранит ресурсы, такие как информация о пользовательских ресурсах)

Фактически, WeChat или QQ обычно используют этот базовый процесс OAuth2:

  1. Сторонние приложения запрашивают авторизацию пользователя;
  2. Пользователь соглашается на авторизацию и возвращает код авторизации (code);
  3. Стороннее приложение авторизует сервис аутентификации авторизации по авторизационному коду (коду);
  4. Сервер авторизации проходит проверку по авторизационному коду (code), и возвращает его токену стороннего приложения (Access Token);
  5. Стороннее приложение запрашивает соответствующие ресурсы у службы ресурсов в соответствии с токеном (токен доступа);
  6. Сервер ресурсов проверяет токен (токен доступа), проходит проверку и возвращает ресурс, запрошенный третьей стороной.

1.2 Тип услуги

OAuth2 можно разделить на две категории по поставщику услуг:

  • Авторизованная служба аутентификации:AuthenticationServer

@Configuration
@EnableAuthorizationServer
public class CustomAuthenticationServerConfig extends AuthorizationServerConfigurerAdapter 
  • Служба приобретения ресурсов:ResourceServer

@Configuration
@EnableResourceServer
public class CustomResourceServerConfig extends ResourceServerConfigurerAdapter

Примечание. Иногда оба могут существовать в одном приложении (например, в архитектуре SOA). В Spring OAuth его можно легко назначить двум приложениям (то есть микросервисам), а несколько сервисов получения ресурсов могут совместно использовать сервис авторизации и аутентификации.

1.3 Служба авторизации и аутентификации

Основные операции:

  1. Получить код авторизации (код), отправленный сторонним приложением, и идентификацию стороннего приложения.
  2. Верификация на основе кода авторизации и идентификации
  3. Если проверка пройдена, отправьте токен (токен доступа)

Проанализируйте волну:
1)первый шаг:

  • Код авторизации (код): Когда стороннее приложение выполняет первый шаг «Запроса авторизации», оно запрашивает ссылку обратного вызова в параметре redirect_uri, и служба генерирует соответствующие учетные данные пользователя и прикрепляет код к ссылке обратного вызова.
  • Идентификатор стороннего пользователя:
    • client_id: идентификатор стороннего пользователя (понимается как учетная запись)
    • client_secret: учетные данные безопасности между сторонним приложением и сервером авторизации (можно понимать как пароль)

Примечание: из нихclient_id иclient_secret отправляется сервером авторизации сторонним приложениям, таким как: WeChat и другие серии авторизаций, регистрация на его платформе и получение его appid и secret (лично понимается как пароль учетной записи).

Поскольку это секрет учетной записи, его нельзя запросить с помощью get, и это слишком небезопасно. Поэтому OAuth2 требует, чтобы запрос был POST-запросом, и в то же время он должен обслуживаться HTTPS для обеспечения безопасности полученного сертификата безопасности (токена доступа).

2)Второй шаг:

  • Сервер аутентификации авторизации проверяет подлинность стороннего приложения по идентификатору
  • Сервер аутентификации авторизации проверяет учетные данные пользователя в соответствии с кодом авторизации (code)

3)Третий шаг:

  • Сгенерировать токен доступа (тип MD5, тип uuid, тип jwt и т. д.)

1.4. Служба приобретения ресурсов

Основные операции:

  • Проверить токен доступа
  • Распространение информации о ресурсах

Во-вторых, использование Spring Security OAuth2.

1. Авторизованная служба аутентификации

В весеннем OAuth2 мы настраиваем службу аутентификации авторизации, У нас в основном есть следующие три пункта:

  1. Сведения о клиенте стороннего пользователя → Клиент
  2. Управление генерацией токенов → Токен доступа
  3. доступ к конечной точке → конечные точки

Есть три конфигурации пружины, которые последовательно соответствуют этим трем точкам:

  • ClientDetailsServiceConfigurer: используется для настройки службы сведений о клиенте.
  • AuthorizationServerSecurityConfigurer: используется для настройки ограничений безопасности конечной точки токена.
  • AuthorizationServerEndpointsConfigurer: для настройки конечных точек авторизации и доступа к маркерам, а также служб маркеров.

1.1. Сведения о клиенте стороннего пользователя

Помимо вышеперечисленногоclient_id иclient_secret, также требует, чтобы некоторые службы поставлялись с некоторыми параметрами аутентификации авторизации.

1).Grant Type

На самом деле OAuth2 не только обеспечивает авторизацию в формате кода авторизации (code), но и предоставляет несколько других типов. Среди них Grant Type представляет текущий тип авторизации. Типы грантов включают:

  • авторизация_код: традиционный режим кода авторизации
  • неявный: неявный режим авторизации
  • пароль: Режим пароля владельца ресурса (т.е. пользователя)
  • client_credentials: режим учетных данных клиента (идентификатор клиента и ключ)
  • refresh_token: новый режим токена, используемый для обновления токена доступа при его получении.

2).scope

Фактически авторизация предоставляет сторонним пользователям возможность получать ресурсы с сервера ресурсов.Обычно запрос API сопровождается токеном.Однако вызов API имеет такие функции, как добавление, удаление, проверка и изменение, а также значение scopes - это все (все разрешения), чтение, запись и прочие разрешения. Это разрешение и объем доступа для доступа третьих лиц к ресурсам.


3).accessTokenValiditySeconds

Вы также можете установить свойство accessTokenValiditySeconds, чтобы установить время жизни токена доступа.

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

    clients.inMemory()
            .withClient("catalpaFlat")
            .secret("catalpaFlat-secret")
            .accessTokenValiditySeconds(7200)
            .authorizedGrantTypes("refresh_token","password")
            .scopes("all");
}

1.2 Генерация токенов и управление ими

Смысл существования AccessToken:

  • Создайте AccessToken и сохраните его, чтобы последующие запросы на доступ можно было успешно аутентифицировать и можно было получить ресурсы.
  • AccessToken также имеет потенциальную функцию, то есть при использовании jwt для создания токена его можно использовать для загрузки некоторой информации и включения некоторых связанных разрешений в AccessToken.

1).AuthorizationServerTokenServices
AuthorizationServerTokenServices предоставляет связанные операции для создания, обновления и получения AccessToken.

public interface AuthorizationServerTokenServices {

	OAuth2AccessToken createAccessToken(OAuth2Authentication authentication) throws AuthenticationException;

	
	OAuth2AccessToken refreshAccessToken(String refreshToken, TokenRequest tokenRequest)
			throws AuthenticationException;

	
	OAuth2AccessToken getAccessToken(OAuth2Authentication authentication);

}

2).DefaultTokenServices

AuthorizationServerTokenServices может фактически управлять AccessToken, тогда OAuth2 предоставляет нам по умолчанию DefaultTokenServices. Содержит некоторые полезные реализации, которые можно использовать для изменения формата токена и хранения токена и т. д., но сгенерированный токен представляет собой случайное число.

3).TokenStore

После создания AccessToken, помимо выдачи его третьей стороне, его необходимо сохранить, прежде чем его можно будет использовать. Так что TokenStore делает это за нас, сохраняя или сохраняя токен (AccessToken).
TokenStore также имеет класс реализации по умолчанию InMemoryTokenStore, который, как известно из имени, сохраняет токен доступа, сохраняя его в памяти. Существует много типов реализаций TokenStore, и тип хранилища токена доступа может быть изменен в соответствии с бизнес-требованиями:

  • InMemoryTokenStore: это реализация OAuth2 по умолчанию. Он может показать хорошие результаты для отдельной службы (то есть параллелизм невелик, и его резервная копия не будет создаваться в случае сбоя), и этот метод можно использовать в большинстве проектов. В конце концов, он существует в памяти, а не на диске, и его легко отлаживать.
  • JdbcTokenStore: это реализация на основе JDBC, и токен (токен доступа) будет сохранен в базе данных. Таким образом, совместное использование токенов может быть достигнуто между несколькими службами.
  • JwtTokenStore: полное имя jwt — JSON Web Token. Этой реализации не важно, как она хранится (в памяти или на диске), потому что она может кодировать соответствующие информационные данные в маркере. JwtTokenStore не хранит никаких данных, но играет ту же роль, что и DefaultTokenServices, в преобразовании значений токенов и информации об авторизации. Но есть два недостатка:
    • Отозвать уже авторизованный токен может быть сложно, поэтому он подходит только для работы с недолговечным и отозванным токеном обновления.
    • Токен занимает много места. Если добавить слишком много учетных данных пользователя, возникнет избыточность передачи.

4).JWT Token

Для использования токенов jwt необходимо настроить JwtTokenStore в службе авторизации. Как я уже говорил, jwt кодирует некоторые информационные данные и сохраняет их в токене, поэтому на самом деле он очень небезопасен во время передачи, поэтому Spring OAuth2 предоставляет JwtAccessTokenConverter для кодирования и декодирования токена. Используйте JwtAccessTokenConverter для настройки подписи (SigningKey). Использование SigningKey заключается в создании и кодировании подписи на сервере аутентификации авторизации, а также в декодировании и проверке ее на сервере получения ресурсов в соответствии с SigningKey.

JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();

 jwtAccessTokenConverter.setSigningKey("CatalpaFlat")

jwt存储

1.3 Конечные точки доступа к конечной точке

Аутентификация авторизации контролируется конечной точкой AuthorizationEndpoint, обычно использующей AuthorizationServerEndpointsConfigurer для настройки.

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {}

1) Настройка связанных свойств конечных точек:

  • authenticationManager: Менеджер аутентификации. Если для нашего Типа гранта выше установлен пароль, нам нужно установить объект AuthenticationManager.
  • userDetailsService: если мы реализуем UserDetailsService для управления информацией о пользователе, тогда мы должны установить наш объект userDetailsService
  • авторизацияCodeServices: службы кода авторизации. Если для нашего Типа гранта выше установлено значение authorization_code, то мы должны установить объект AuthorizationCodeServices.
  • tokenStore: это то, что мы сказали выше, установив тип токена доступа, которого мы хотим достичь.
  • accessTokenConverter: кодировщик для токена доступа. Это JwtAccessTokenConverter
  • tokenEnhancer: расширение токена. При использовании jwt можно реализовать TokenEnhancer для расширения информации, содержащейся в jwt.
  • tokenGranter: Когда типа гранта по умолчанию недостаточно для нашей бизнес-логики, реализуйте интерфейс TokenGranter, авторизация будет контролироваться нами, а некоторые свойства типа гранта будут игнорироваться.

2) URL-адрес авторизации конечных точек: Для авторизации и аутентификации он должен быть запрошен URL-адресом, прежде чем его можно будет передать. Таким образом, OAuth2 предоставляет URL-адрес для настройки конечной точки авторизации.
AuthorizationServerEndpointsConfigurer, или этот объект конфигурации настроен, в котором метод pathMapping() используется для настройки URL-пути конечной точки авторизации.По умолчанию предоставляются два параметра defaultPath и customPath:

public AuthorizationServerEndpointsConfigurer pathMapping(String defaultPath, String customPath) {
		this.patternMap.put(defaultPath, customPath);
		return this;
}

Путь по умолчанию для pathMapping:

  • /oauth/authorize: конечная точка авторизации
  • /oauth/token: конечная точка токена
  • /oauth/confirm_access: пользователь подтверждает авторизацию для отправки конечной точки
  • /oauth/error: конечная точка сообщения об ошибке службы авторизации
  • /oauth/check_token: конечная точка разрешения токена для доступа к службе ресурсов.
  • /oauth/token_key: конечная точка для предоставления открытого ключа при использовании токена JWT.

Примечание. Оба параметра pathMapping будут строками, начинающимися с символов «/».

1.4. Пользовательская обработка ошибок (обработка ошибок)

Фактически, упомянутые выше конечные точки можно рассматривать как контроллеры, которые используются для возврата содержимого ответа различных конечных точек.

Сообщение об ошибке службы авторизации обрабатывается с использованием стандартного Spring MVC, то есть метода конечной точки, аннотированного @ExceptionHandler, и мы можем предоставить объект WebResponseExceptionTranslator. Лучший способ — изменить содержимое ответа, а не отображать его напрямую.

  • Если во время рендеринга конечной точки маркера возникает исключение, исключение делегируется объекту HttpMessageConverters (который можно добавить в конфигурацию MVC) для вывода.
  • Если аутентификация не пройдена при представлении конечной точки авторизации, она будет перенаправлена ​​на /oauth/error , конечную точку сообщения об ошибке. ошибка whitelabel (то есть страница ошибки по умолчанию, предоставляемая средой Spring). Конечная точка ошибки предоставляет ответ в формате HTML, но нам, вероятно, потребуется реализовать пользовательскую страницу ошибки (например, просто добавить сопоставление @Controller к пути запроса @RequestMapping( "/oauth/ошибка")).

2. Сервис получения ресурсов

Сервер ресурсов фактически хранит некоторые ресурсы, защищенные токенами. Только когда токены действительны и правильны, ресурсы могут быть получены. Внутри он защищен цепочкой фильтров Spring Security Authentication filter Spring OAuth2.

2.1.ResourceServerConfigurerAdapter

Мы можем наследовать ResourceServerConfigurerAdapter, чтобы использовать ResourceServerSecurityConfigurer для соответствующей конфигурации.

public class ResourceServerConfigurerAdapter implements ResourceServerConfigurer {

	@Override
	public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
	}

	@Override
	public void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests().anyRequest().authenticated();
	}
}

2.2.Свойства, связанные с ResourceServerSecurityConfigurer

  • tokenServices: экземпляр класса ResourceServerTokenServices, используемый для реализации служб токенов.
  • resourceId: идентификатор этой службы ресурсов, этот атрибут является необязательным, но рекомендуется установить его и проверить в службе авторизации.
  • tokenExtractor Средство извлечения токенов используется для извлечения токена в запросе.
  • Сопоставитель запросов используется для установки пути к ресурсу, который необходимо защитить.По умолчанию это все пути службы защищенных ресурсов.
  • Правила доступа к защищенным ресурсам, правило по умолчанию — простая проверка подлинности.
  • Другие настраиваемые правила защиты разрешений настраиваются с помощью HttpSecurity.

2.3.ResourceServerTokenServices

ResourceServerTokenServices — это вторая половина службы авторизации.

1) Если сервер ресурсов и служба авторизации находятся в одном приложении, можно использовать DefaultTokenServices

2).Если разошлись. ResourceServerTokenServices должен знать, как декодировать токен.

Метод ResourceServerTokenServices для анализа токена:

  • Используя RemoteTokenServices, сервер ресурсов декодирует маркер с помощью HTTP-запроса. Расшифруйте токен, каждый раз запрашивая конечную точку сервера авторизации - /oauth/check_toke
  • Если объем трафика большой, то после его получения по http он будет заменен на результат работы токена
  • Если это токен jwt, вам необходимо запросить ключ /oauth/token_key службы авторизации, чтобы получить ключ для декодирования.

Примечание. Служба авторизации и аутентификации должна открыть /oauth/check_toke и получить к ней доступ с разрешения.

@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
    oauthServer.tokenKeyAccess("isAnonymous() || hasAuthority('ROLE_TRUSTED_CLIENT')")
        .checkTokenAccess("hasAuthority('ROLE_TRUSTED_CLIENT')");
}

(~ ¯ ▽ ¯) ~ необученный...