текст презентации по security. Презентация текст. 4 слайд Что такое Spring Security и как она работает
Скачать 305.51 Kb.
|
4 слайд Что такое Spring Security и как она работает? По своей сути Spring Security – это просто набор фильтров, которые помогают добавлять аутентификацию и авторизацию в наше веб-приложение. Он также хорошо интегрируется с такими фреймворками, как Spring Web, а также с протоколами аторизации, такими как например OAuth2. Он автоматически генерирует страницы входа/выхода и защищает от распространенных эксплойтов, таких как CSRF. 1. АутентификацияВо-первых, мы используем обычное (веб-) приложение, нам нужно, чтобы пользователи аутентифицировались. Это означает, что приложение должно проверить, является ли пользователь тем, за кого он себя выдает, обычно это делается с помощью проверки имени пользователя и пароля. Например: Пользователь: Я хочу войти на сайт мой логин “Pro100Pro_228” Веб - приложение : “Конечно, а какой у вас пароль ? “ Пользователь : “Мой пароль: убийца нубов 1337”. Веб - приложение : : “Правильно. Добро пожаловать Pro100Pro_228” 2. Авторизация В более простых приложениях аутентификации может быть достаточно: Как только пользователь проходит аутентификацию, он может получить доступ ко всем частям приложения. Но в большинстве приложений существует концепция разрешений (или ролей или прав). Представьте себе: клиенты, у которых есть доступ к общедоступному интерфейсу вашего интернет-магазина, и администраторы, у которых есть доступ к отдельной области администрирования. Пользователям обоих типов необходимо войти в систему, но сам факт аутентификации ничего не говорит о том, что им разрешено делать в нашей системе. Следовательно, нам также необходимо проверить разрешения аутентифицированного пользователя, т.е. нам необходимо авторизовать пользователя. Пользователь : “Я хочу удалить этот товар” Веб-приложение : “Секунду, мне нужно сначала проверить ваши права. Да у вас есть право удалять этот товар”. Удаляю товар AuthenticationManager - интерфейс, с помощью которого Spring Security понимает, как выполнять проверку подлинности. У него есть метод authenticate, в котором описывается логика аутентификации пользователя. Метод принимает объект класса Authentication, который содержит в себе некие credentials (логин и пароль пользователя) и возвращает тоже объект класса Authentication но уже с информацией о пользователе( имя, фамилия, и тд…) 5 слайд Тут показан порядок работы простого spring security приложения, в дальнейшем эта схема будет усложняться. И усложниться довольно сильно, но пока все довольно просто ( рассказать по схеме, что куда идет что содержит и откуда возвращается) 6 слайд CSRF (Cross-site request forgery) - межсайтовая подделка запросов. Важная вещь. В чем ее суть ? Если пользователь авторизовался в нашей системе, и мы его запомнили, а затем он попал на сайт злоумышленника. То злодей, зная что пользователя мы запомнили может делать что угодно от его имени. Например если мы являемся банком, то он может переводить себе на счет деньги. Чтобы этого избежать в spring по умолчанию включена CSRF защита на все POST PATCH PUT DELETE запросы. Как она работает. В каждой такой запрос мы кладем токен, который сами генерируем. Этот токен является подтверждением что пользователь действительно является пользователем а не злоумышленником. Но в данный момент это нам все только усложнит. Поэтому во время практики мы всегда будем отключать CSRF. 7 слайд Давайте наконец приступим к практической части первого модуля, а именно подключим необходимую зависимость и напишем простое приложение. Все исходники и итоги можно найти на моем гите. Практика. Открываю свой проект и клонирую его с гита. Гайд по написанию простого Spring security приложения: Запустить приложение проверить эндпоинт. Добавить зависимость implementation 'org.springframework.boot:spring-boot-starter-security:3.0.4’ Запустить приложение проверить эндпоинт. Показать где лежит пароль (Логин – user) Перейти в класс User и там имплементировать userDetails @Table(name = "users") @Entity @Getter @Setter @Builder @EqualsAndHashCode(of = "email") @NoArgsConstructor @AllArgsConstructor public class User implements UserDetails { @Id @SequenceGenerator(name = "users_sequence", allocationSize = 1) @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "users_sequence") private Long id; private String email; private String password; @Enumerated(EnumType.STRING) private Role role; @Override public Collection extends GrantedAuthority> getAuthorities() { return List.of(new SimpleGrantedAuthority(role.name())); } @Override public String getPassword() { return password; } @Override public String getUsername() { return email; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } } Создаем простой SecurityConfig. На него вешаем аннотацию @Configrution и @EnableWebSecurity Создаем простой SecurityFilterChain: @Configuration @EnableWebSecurity @RequiredArgsConstructor public class SecurityConfig { private final AuthenticationProvider authenticationProvider; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http //отключаем csrf .csrf() .disable() //расставляем эндпоинты, куда можно будет войти без авторизации, а куда только авторизовавшись //используем лямбду для удобства, также показать более старый вариант написания .authorizeHttpRequests(request -> request .requestMatchers("/api/v1/auth/register") .permitAll() .anyRequest() .authenticated() ) .authenticationProvider(authenticationProvider) //для удобства .httpBasic(); return http.build(); } } Далее создаем ApplicationConfig: @Configuration @RequiredArgsConstructor public class ApplicationConfig { private final UserRepository userRepository; //нам необходима реализовать интерфейс, тут тоже самое что и с юзер детаилс //можно сделать как лямбдой так и нет, показать как делается не лямбдой, потом лямбдой @Bean public UserDetailsService userDetailsService() { return username -> userRepository.findUserByEmail(username) .orElseThrow(() -> new UsernameNotFoundException("User not found")); } @Bean public AuthenticationProvider authenticationProvider() { //это одна из реализаций authProvider DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider(); //тут мы говорим возьму нашу информацию о пользователях authenticationProvider.setUserDetailsService(userDetailsService()); // тут мы какой кодировщик паролей использовать authenticationProvider.setPasswordEncoder(passwordEncoder()); return authenticationProvider; } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } Дальше контроллер: @RestController @RequestMapping("/api/v1/auth") @RequiredArgsConstructor public class AuthController { private final AuthenticateService authenticateService; @PostMapping("/register") public void register(@RequestBody UserDto userDto) { authenticateService.register(userDto); } @GetMapping("/register") public String register() { return "Register"; } } Сервис и ДТО @Service @RequiredArgsConstructor public class AuthenticateService { private final UserRepository userRepository; private final PasswordEncoder passwordEncoder; public void register(UserDto userDto) { User user = new User(); user.setEmail(userDto.getEmail()); user.setPassword(passwordEncoder.encode(userDto.getPassword())); user.setRole(Role.USER); userRepository.save(user); } } Слайд 9 Причины появления перечислены на слайде, подробно остановися на одной, а именно микросервиснйо архитектуре. Если наше приложение монолитной то вполне достаточно авторизации с помощью сессий и кукис, НО что делать если у нас микросервисная архитектура, тогда каждому микросервису надо класть данные о сесиии и о данных в отдельный сервис, но таким образом у нас может появиться единая точка отказа системы. Отказал этот сервис и все, данные не обновить не записать. Токен позволяет хранить данные о сессия на своем компьюетер и передавать данные в виде токена на каждый микросервис. И таким образов каждый сервис не хранит информацию о пользователе. Слайд 10 Структура токена Слайд 11 В OAuth 2 и некоторых других схемах авторизации (например, у нас) есть не один, а целых два токена. Первый, access token, используется при запросах к серверу (например, при логине). У него есть два свойства: он многоразовый и короткоживущий. Наш, к примеру, живет 48 часов, а у кого-то 30 минут. Время выбирается на основании того, как используется сервис. Второй, refresh token, используется для обновления пары access и refresh токенов. У него тоже есть два свойства, обратные первому токену: он одноразовый и долгоживущий. Совсем долгоживуший, наш живет месяц. Схема использования у токенов следующая: Пользователь логинится в приложении, передавая логин и пароль на сервер. Они не сохраняются на устройстве, а сервер возвращает два токена и время их жизни Приложение сохраняет токены и использует access token для последующих запросов Когда время жизни access token подходит к концу (приложение может само проверять время жизни, или дождаться пока во время очередного использования сервер ответит «ой, всё»), приложение использует refresh token, чтобы обновить оба токена и продолжить использовать новый access token Примерно так это все объяснено в документации OAuth, на Википедии, Зачем на самом деле нужен второй токенВсе оказалось и проще, и сложнее чем я думал. Следите за руками: Случай 1: Боб узнал оба токена Алисы и не воспользовался refresh В этом случае Боб получит доступ к сервису на время жизни access token. Как только оно истечет и приложение, которым пользуется Алиса, воспользуется refresh token, сервер вернет новую пару токенов, а те, что узнал Боб, превратятся в тыкву. Случай 2: Боб узнал оба токена Алисы и воспользовался refresh В этом случае оба токена Алисы превращаются в тыкву, приложение предлагает ей авторизоваться логином и паролем, сервер возвращает новую пару токенов, а те, что узнал Боб, снова превратятся в тыкву (тут есть нюанс с device id, может вернуть ту же пару что и у Боба. В таком случае следующее использование refresh токена превратит токены Боба в то, что изображено справа). Таким образом, схема refresh + access токен ограничивает время, на которое атакующий может получить доступ к сервису. По сравнению с одним токеном, которым злоумышленник может пользоваться неделями и никто об этом не узнает Слайд 14 OAuth 2.0 — протокол авторизации, позволяющий выдать одному сервису (приложению) права на доступ к ресурсам пользователя на другом сервисе. Протокол избавляет от необходимости доверять приложению логин и пароль, а также позволяет выдавать ограниченный набор прав, а не все сразу. Чем отличаются OpenID и OAuth OpenID предназначен для аутентификации — то есть для того, чтобы понять, что этот конкретный пользователь является тем, кем представляется. Например, с помощью OpenID некий сервис Ололо может понять, что зашедший туда пользователь, это именно Рома Новиков с Mail.Ru. При следующей аутентификации Ололо сможет его опять узнать и понять, что, это тот же Рома, что и в прошлый раз. OAuth же является протоколом авторизации, то есть позволяет выдать права на действия, которые сам Ололо сможет производить в Mail.Ru от лица Ромы. При этом Рома после авторизации может вообще не участвовать в процессе выполнения действий, например, Ололо сможет самостоятельно заливать фотографии на Ромин аккаунт. |