Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Краткий экскурс в Spring Security (core)

Краткий экскурс в Spring Security (core)

Слайды вводной лекции о фреймворке Spring Security

Vladimir Plizga

September 15, 2020
Tweet

More Decks by Vladimir Plizga

Other Decks in Programming

Transcript

  1. Spring Security — это: ✓ Какая-то приблуда для безопасности ✓

    Очередной фреймворк зоопарка Spring ✓ “Коробочное” решение для защиты приложений от рисков ИБ 5 Интуитивное представление: ОК ✔
  2. “Spring Security is a powerful and highly customizable authentication and

    access-control framework” 6 По мнению авторов Ни слова про light-weight
  3. Аутентификация Отвечает на вопрос: “Ты ли это?” Имеет дело с

    логинами и паролями. Устраняем любимую путаницу Авторизация Отвечает на вопрос: “Можно ли тебе сюда?” Имеет дело с правами, ролями, доступами... 7 Наша главная тема сегодня Но начнём с этой
  4. Вместо disclaimer’а 9 ◦ Пробежимся по верхушкам ◦ Только для

    общего представления ◦ Без примеров и конкретики
  5. Интерфейс AccessDecisionManager 10 public interface AccessDecisionManager { void decide(Authentication authentication,

    Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException; boolean supports(ConfigAttribute attribute); boolean supports(Class<?> clazz); }
  6. Интерфейс AccessDecisionManager 11 ✢ Центральный компонент авторизации ✢ Опрашивает других

    участников выбора "пускать или нет" ✢ Обычно делегирует имплементациям интерфейса AccessDecisionVoter
  7. Интерфейс AccessDecisionVoter 12 public interface AccessDecisionVoter<S> { int ACCESS_GRANTED =

    1; int ACCESS_ABSTAIN = 0; int ACCESS_DENIED = -1; int vote(Authentication authentication, S object, Collection<ConfigAttribute> attributes); boolean supports(ConfigAttribute attribute); boolean supports(Class<?> clazz); }
  8. Авторизация в веб-приложениях 13 ✢ Включается через @EnableWebSecurity ✢ Работает

    как 1 фильтр FilterChainProxy ✢ Делегирует внутренним фильтрам (бинам)
  9. Фильтры собираются в цепочки 15 ✢ Цепочек может быть несколько

    ✢ На каждый запрос срабатывает только одна ✢ В spring-boot-starter-security из коробки 6 цепочек: ◦ Для статики ◦ Для ошибок, для ... ◦ Для всего остального 11 фильтров
  10. Авторизация на уровне методов 18 ✢ Включается через аннотацию: @EnableGlobalMethodSecurity(securedEnabled=true)

    ✢ Работает как прокси (можно на AOP) ✢ При нарушении доступа выбрасывает: AccessDeniedException
  11. Варианты авторизации для методов 19 @Service public class MyService {

    @Secured("ROLE_USER") public String secure() { return "Hello Security"; } } @PreAuthorize("hasRole('ADMIN')") @PostAuthorize("hasPermission(filterObject, 'read')") SpEL Но должно же у них быть что-то общее?
  12. Интерфейс SecurityContext 22 public interface SecurityContext extends Serializable { Authentication

    getAuthentication(); void setAuthentication(Authentication authentication); } Та самая “аутентификация”
  13. Интерфейс Authentication 23 public interface Authentication extends Principal, Serializable {

    Collection<? extends GrantedAuthority> getAuthorities(); Object getCredentials(); Object getDetails(); Object getPrincipal(); boolean isAuthenticated(); void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException; }
  14. Что содержит Authentication 24 principal — это обычно пользователь (наследник

    UserDetails; у нас это карта) credentials — это обычно пароль (String) authorities — список разрешений/доступов details — что угодно (IP, свойства и т.п.) authenticated — признак успешной проверки
  15. SecurityContext доступен отовсюду 25 ✢ Напрямую через SecurityContextHolder: SecurityContext context

    = SecurityContextHolder.getContext(); Authentication authentication = context.getAuthentication(); assert authentication.isAuthenticated(); ✢ Опосредованно через аннотации: @RequestMapping("/foo") public String foo(@AuthenticationPrincipal User user) { // do stuff with user } почти
  16. SecurityContext доступен отовсюду 26 ✢ Опосредованно из сервлет-контейнера: @RequestMapping("/foo") public

    String foo(Principal principal) { Authentication authentication = (Authentication) principal; User user = (User) authentication.getPrincipal(); // do stuff with user } почти Но откуда он попадает во все эти места?
  17. “Spring Security is fundamentally thread bound because it needs to

    make the current authenticated principal available to a wide variety of downstream consumers” 27 По словам авторов
  18. “Fundamentally thread bound” 28 ✢ В каждом потоке свой SecurityContext

    ✢ Как правило, за нас это делает Spring Security ✢ Но иногда можно/нужно самим: @Configuration public class ApplicationConfiguration extends AsyncConfigurerSupport { @Override public Executor getAsyncExecutor() { return new DelegatingSecurityContextExecutorService(newFixedThreadPool(5)); } } А как же реактивщина?
  19. Reactive Spring Security ⚛ 29 ✢ ReactiveSecurityContextHolder ✢ Под капотом

    использует reactor.util.context.Context ✢ Для веб-приложений работает за счёт ReactorContextWebFilter ✢ Нуждается в @EnableWebFluxSecurity и @EnableReactiveMethodSecurity
  20. Интерфейс AuthenticationManager 32 public interface AuthenticationManager { Authentication authenticate(Authentication authentication)

    throws AuthenticationException; } Является входной точкой во всю логику аутентификации Spring Security
  21. Варианты ответа метода authenticate() 33 ✢ Объект Authentication (authenticated=true) ⇒

    Всё ОК ✅ ✢ Исключение AuthenticationException ⇒ Пшёлвон ⛔ ✢ null, просто null ⇒ Я не в курсе, спроси другого ‍♂
  22. Класс ProviderManager 34 ✢ Основная имплементация для AuthenticationManager’а ✢ Делегирует

    набору AuthenticationProvider’ов ✢ Швыряет ProviderNotFoundException, если не находит подходящего провайдера
  23. Как создать AuthenticationManager’а 38 Способы: ✢ С помощью AuthenticationManagerBuilder ‍♂

    ✢ Вручную, с нуля Области: ✢ Глобально на всё приложение ✢ Локально на заданную часть
  24. Пример 1: локально, builder’ом 39 @Configuration public class ApplicationSecurity extends

    WebSecurityConfigurerAdapter { @Autowired DataSource dataSource; @Override public void configure(AuthenticationManagerBuilder builder) { builder.jdbcAuthentication().dataSource(dataSource) .withUser("dave").password("secret") .roles("USER"); } }
  25. Пример 2: глобально, с нуля 40 @Bean public AuthenticationManager globalAuthenticationManager(

    PasswordAuthenticationProvider passwordAuthenticationProvider, PinAuthenticationProvider pinAuthenticationProvider) { var providerManager = new ProviderManager(List.of( passwordAuthenticationProvider, pinAuthenticationProvider)); // всякие манипуляции с этим объектом return providerManager; } Перекроет бин, поставляемый spring-boot-starter-security
  26. Интерфейс UserDetailsService 43 public interface UserDetailsService { UserDetails loadUserByUsername(String username)

    throws UsernameNotFoundException; } Является "мостом" между прикладным хранилищем учётных данных и Spring Security
  27. Интерфейс UserDetailsService 44 Имеет реализации в Spring Security: ✢ JDBC

    ✢ In-memory ✢ Кэширующая прослойка ✢ … ✢ И легко запилить свою
  28. Интерфейс UserDetailsService 46 public interface UserDetails extends Serializable { Collection<?

    extends GrantedAuthority> getAuthorities(); String getPassword(); String getUsername(); boolean isAccountNonExpired(); boolean isAccountNonLocked(); boolean isCredentialsNonExpired(); boolean isEnabled(); } * Есть реализация в Spring Security (класс User)
  29. Превратности контракта UserDetails 47 ✢ Метод getUserName() никогда не должен

    возвращать null. ✢ Метод getPassword() может вернуть null: ◦ Критичные данные могут стираться из памяти после успешной аутентификации. ◦ См. CredentialsContainer#eraseCredentials Кстати, о паролях...
  30. Интерфейс PasswordEncoder 48 public interface PasswordEncoder { String encode(CharSequence rawPassword);

    boolean matches(CharSequence rawPassword, String encodedPassword); } (Де)Кодирует пароли для безопасного хранения https://docs.spring.io/spring-security/site/docs/5.2.6.RELEASE/reference/htmlsingle/#core-services-password-encoding
  31. Класс DelegatingPasswordEncoder 51 Хранит пароли в формате “{id}encodedPassword”: ✢ id

    ‒ идентификатор алгоритма ✢ encodedPassword ‒ кодированный пароль (может включать метаданные)
  32. Класс DelegatingPasswordEncoder 53 ✢ Используется в Spring Security по умолчанию

    ✢ Умеет “совершенствовать” хэши паролей ✢ Удобно создавать через PasswordEncoderFactories
  33. Алгоритмы хэширования паролей 54 SHA-1, SSHA (ldap), SHA-256, MD-5, MD-4

    Не безопасны, не рекомендованы, вызывают головную боль и предупреждения в IDE ➖ scrypt, bcrypt Широко распространённые варианты (не только в экосистеме JVM) pbkdf2, argon2 Современные намеренно-ресурсоёмкие алгоритмы
  34. Алгоритм Argon2 в Spring Security 55 ✢ Реализован в org.bouncycastle:bcprov-jdk15on:1.64

    ✢ Используется через класс Argon2PasswordEncoder ✢ Генерирует соль из SecureRandom ⇒ один пароль всякий раз даёт разные хэши
  35. Кратко о Spring Security в целом 58 ✢ Помогает с

    аутентификацией и авторизацией ✢ Обеспечивает гибкость через интерфейсы ✢ Состоит из модулей (core, web, config, ldap, ...)
  36. Резюме по авторизации 59 ✢ Работает в веб-приложениях за счёт

    фильтров ✢ Умеет защищать методы через прокси-обёртки ✢ Основные классы: ◦ @EnableWebSecurity, @EnableGlobalMethodSecurity ◦ AccessDecisionManager, AccessDecisionVoter ◦ @PreAuthorize, @PostAuthorize
  37. Резюме по аутентификации 60 ✢ Является “скелетом” для подключения разных

    механизмов проверки ✢ Предоставляет средства работы с паролями ✢ Основные классы: ◦ Authentication, AuthenticationManager ◦ SecurityContext, SecurityContextHolder ◦ UserDetails, UserDetailsService
  38. 62

  39. Credits Special thanks to all the people who made and

    released these awesome resources for free: ✢ Presentation template by SlidesCarnival ✢ Photographs by Unsplash 66