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

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

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

58e952ea302f1fa452f69c9d8204a8bc?s=128

Vladimir Plizga

September 15, 2020
Tweet

Transcript

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

  2. 2 1. Теория 2. ☕ 3. Практика 3. Применение План

  3. 3 Цель

  4. 1. Теория Введение О чём вообще пойдёт речь?

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

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

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

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

  9. Вместо disclaimer’а 9 ◦ Пробежимся по верхушкам ◦ Только для

    общего представления ◦ Без примеров и конкретики
  10. Интерфейс 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); }
  11. Интерфейс AccessDecisionManager 11 ✢ Центральный компонент авторизации ✢ Опрашивает других

    участников выбора "пускать или нет" ✢ Обычно делегирует имплементациям интерфейса AccessDecisionVoter
  12. Интерфейс 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); }
  13. Авторизация в веб-приложениях 13 ✢ Включается через @EnableWebSecurity ✢ Работает

    как 1 фильтр FilterChainProxy ✢ Делегирует внутренним фильтрам (бинам)
  14. 14 Фильтры Spring Security https://spring.io/guides/topicals/spring-security-architecture

  15. Фильтры собираются в цепочки 15 ✢ Цепочек может быть несколько

    ✢ На каждый запрос срабатывает только одна ✢ В spring-boot-starter-security из коробки 6 цепочек: ◦ Для статики ◦ Для ошибок, для ... ◦ Для всего остального 11 фильтров
  16. Цепочки фильтров Spring Security 16 https://spring.io/guides/topicals/spring-security-architecture

  17. А что-нибудь покруче? Есть кое-что... 17

  18. Авторизация на уровне методов 18 ✢ Включается через аннотацию: @EnableGlobalMethodSecurity(securedEnabled=true)

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

    @Secured("ROLE_USER") public String secure() { return "Hello Security"; } } @PreAuthorize("hasRole('ADMIN')") @PostAuthorize("hasPermission(filterObject, 'read')") SpEL Но должно же у них быть что-то общее?
  20. 1. Теория Устройство Как это работает

  21. SecurityContext Краеугольный камень Spring Security. Содержит саму “аутентификацию”. 21

  22. Интерфейс SecurityContext 22 public interface SecurityContext extends Serializable { Authentication

    getAuthentication(); void setAuthentication(Authentication authentication); } Та самая “аутентификация”
  23. Интерфейс 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; }
  24. Что содержит Authentication 24 principal — это обычно пользователь (наследник

    UserDetails; у нас это карта) credentials — это обычно пароль (String) authorities — список разрешений/доступов details — что угодно (IP, свойства и т.п.) authenticated — признак успешной проверки
  25. 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 } почти
  26. SecurityContext доступен отовсюду 26 ✢ Опосредованно из сервлет-контейнера: @RequestMapping("/foo") public

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

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

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

    использует reactor.util.context.Context ✢ Для веб-приложений работает за счёт ReactorContextWebFilter ✢ Нуждается в @EnableWebFluxSecurity и @EnableReactiveMethodSecurity
  30. 1. Теория Аутентификация “Ты ли это?”

  31. Пара слов о менеджерах 31

  32. Интерфейс AuthenticationManager 32 public interface AuthenticationManager { Authentication authenticate(Authentication authentication)

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

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

    набору AuthenticationProvider’ов ✢ Швыряет ProviderNotFoundException, если не находит подходящего провайдера
  35. AuthenticationManager AuthenticationProvider 35 Вася Менеджер

  36. ProviderManager может иметь родителя 36 https://spring.io/guides/topicals/spring-security-architecture

  37. ProviderManager умеет рассылать события 37

  38. Как создать AuthenticationManager’а 38 Способы: ✢ С помощью AuthenticationManagerBuilder ‍♂

    ✢ Вручную, с нуля Области: ✢ Глобально на всё приложение ✢ Локально на заданную часть
  39. Пример 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"); } }
  40. Пример 2: глобально, с нуля 40 @Bean public AuthenticationManager globalAuthenticationManager(

    PasswordAuthenticationProvider passwordAuthenticationProvider, PinAuthenticationProvider pinAuthenticationProvider) { var providerManager = new ProviderManager(List.of( passwordAuthenticationProvider, pinAuthenticationProvider)); // всякие манипуляции с этим объектом return providerManager; } Перекроет бин, поставляемый spring-boot-starter-security
  41. Словарный запас Spring Security 41 ProviderManager AuthenticationManager AuthenticationProvider имплементирован делегирует

    подчинённый
  42. А что делать с учётками? Под интерфейс их! 42

  43. Интерфейс UserDetailsService 43 public interface UserDetailsService { UserDetails loadUserByUsername(String username)

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

    ✢ In-memory ✢ Кэширующая прослойка ✢ … ✢ И легко запилить свою
  45. UserDetails Абстрагирует фреймворк от прикладных моделей пользователей 45

  46. Интерфейс 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)
  47. Превратности контракта UserDetails 47 ✢ Метод getUserName() никогда не должен

    возвращать null. ✢ Метод getPassword() может вернуть null: ◦ Критичные данные могут стираться из памяти после успешной аутентификации. ◦ См. CredentialsContainer#eraseCredentials Кстати, о паролях...
  48. Интерфейс 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
  49. Какой алгоритм самый стойкий? В перспективе ‒ никакой! 49

  50. DelegatingPasswordEncoder ✔ Учитывает современные требования ИБ ✔ Обеспечивает миграцию на

    новые алгоритмы ✔ Поддерживает старые приложения 50
  51. Класс DelegatingPasswordEncoder 51 Хранит пароли в формате “{id}encodedPassword”: ✢ id

    ‒ идентификатор алгоритма ✢ encodedPassword ‒ кодированный пароль (может включать метаданные)
  52. Примеры хэшей от слова “password” 52 {bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG {pbkdf2}5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc {sha256}97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f27605abcbc0 {argon2}$argon2id$v=19$m=4096,t=3,p=1$PvvIwF0BSb/ycgO51cSkPg$xizQ/EyAyLYJb+/E+KiJf1bg5RUdcUUttly0bA6MjUU

    {noop}password
  53. Класс DelegatingPasswordEncoder 53 ✢ Используется в Spring Security по умолчанию

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

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

    ✢ Используется через класс Argon2PasswordEncoder ✢ Генерирует соль из SecureRandom ⇒ один пароль всякий раз даёт разные хэши
  56. Argon2 BCrypt 56 https://virgo.ftc.ru/x/YYwDOQ

  57. 1. Теория Заключение Резюме и выводы

  58. Кратко о Spring Security в целом 58 ✢ Помогает с

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

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

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

    ✢ ... 61 https://virgo.ftc.ru/x/YYwDOQ
  62. 62

  63. 2. Применение Как всё это выглядит на деле

  64. Show me the code! 64

  65. Спасибо! Вопросы? Материалы будут разосланы отдельным письмом 65

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

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