[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"question-sovremennaya-razrabotka-web-kak-nastroit-bezopasnost-rest-api-s-pomoshchyu-spring-security":3},{"id":4,"slug":5,"topicId":6,"topicSlug":7,"topicName":8,"topicEmoji":9,"question":10,"answer":11,"codeLang":12,"codeSrc":12,"important":12,"commonMistakes":12,"modernUsage":12,"difficulty":13,"tags":14,"related":20,"progress":21,"seo":22},1192,"kak-nastroit-bezopasnost-rest-api-s-pomoshchyu-spring-security",37,"sovremennaya-razrabotka-web","Современная разработка WEB","🌐","Как настроить безопасность REST API с помощью Spring Security?","Spring Security 6 полностью перешёл на компонентную модель с SecurityFilterChain, заменив устаревший WebSecurityConfigurerAdapter.\n\n\u003Cdetails>\n\u003Csummary>Конфигурация SecurityFilterChain\u003C\u002Fsummary>\n\n```java\n@Configuration\n@EnableWebSecurity\n@EnableMethodSecurity\npublic class SecurityConfig {\n\n    @Bean\n    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {\n        return http\n            .csrf(csrf -> csrf.disable()) \u002F\u002F Для stateless API\n            .cors(cors -> cors.configurationSource(corsConfigurationSource()))\n            .sessionManagement(session ->\n                session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))\n            .authorizeHttpRequests(auth -> auth\n                .requestMatchers(\"\u002Fapi\u002Fv1\u002Fpublic\u002F**\").permitAll()\n                .requestMatchers(\"\u002Factuator\u002Fhealth\", \"\u002Factuator\u002Finfo\").permitAll()\n                .requestMatchers(HttpMethod.POST, \"\u002Fapi\u002Fv1\u002Forders\").hasRole(\"USER\")\n                .requestMatchers(\"\u002Fapi\u002Fv1\u002Fadmin\u002F**\").hasRole(\"ADMIN\")\n                .anyRequest().authenticated()\n            )\n            .oauth2ResourceServer(oauth2 -> oauth2\n                .jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthConverter()))\n            )\n            .build();\n    }\n\n    @Bean\n    public JwtAuthenticationConverter jwtAuthConverter() {\n        JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter =\n            new JwtGrantedAuthoritiesConverter();\n        grantedAuthoritiesConverter.setAuthoritiesClaimName(\"roles\");\n        grantedAuthoritiesConverter.setAuthorityPrefix(\"ROLE_\");\n\n        JwtAuthenticationConverter converter = new JwtAuthenticationConverter();\n        converter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);\n        return converter;\n    }\n\n    @Bean\n    public CorsConfigurationSource corsConfigurationSource() {\n        CorsConfiguration config = new CorsConfiguration();\n        config.setAllowedOrigins(List.of(\"https:\u002F\u002Fapp.example.com\"));\n        config.setAllowedMethods(List.of(\"GET\", \"POST\", \"PUT\", \"DELETE\"));\n        config.setAllowedHeaders(List.of(\"Authorization\", \"Content-Type\"));\n        config.setMaxAge(3600L);\n\n        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();\n        source.registerCorsConfiguration(\"\u002Fapi\u002F**\", config);\n        return source;\n    }\n}\n```\n\n\u003C\u002Fdetails>\n\n### Rate Limiting (Bucket4j + Redis)\n\n\u003Cdetails>\n\u003Csummary>RateLimitInterceptor\u003C\u002Fsummary>\n\n```java\n@Component\npublic class RateLimitInterceptor implements HandlerInterceptor {\n\n    private final ProxyManager\u003CString> proxyManager;\n\n    @Override\n    public boolean preHandle(HttpServletRequest request,\n            HttpServletResponse response, Object handler) {\n        String clientId = extractClientId(request);\n\n        Bucket bucket = proxyManager.builder()\n            .build(clientId, () -> BucketConfiguration.builder()\n                .addLimit(Bandwidth.builder()\n                    .capacity(100)\n                    .refillGreedy(100, Duration.ofMinutes(1))\n                    .build())\n                .build());\n\n        if (bucket.tryConsume(1)) {\n            return true;\n        }\n        response.setStatus(429);\n        return false;\n    }\n}\n```\n\n\u003C\u002Fdetails>\n\n### Ключевые принципы\n\n- Stateless API: SessionCreationPolicy.STATELESS + JWT. Никаких HTTP-сессий\n- CSRF отключается для stateless REST API. Для Thymeleaf CSRF обязателен\n- Method Security (@PreAuthorize, @Secured) — для fine-grained авторизации\n- Secrets никогда не хранятся в коде — переменные окружения, Vault, Kubernetes Secrets\n\n### Частые ошибки\n\n- Хранение JWT в localStorage — уязвимость к XSS. Для браузеров: HttpOnly cookie с SameSite=Strict\n- Отсутствие rate limiting — уязвимость к DDoS и brute-force\n- Логирование токенов и паролей — критическая уязвимость\n- Использование @Secured(\"ROLE_ADMIN\") без юнит-тестов на авторизацию\n\n> **На собеседовании:** покажите, что знаете новый API (SecurityFilterChain вместо WebSecurityConfigurerAdapter). Обязательные пункты: STATELESS для API, CSRF отключён для REST но включён для HTML, Method Security для бизнес-правил. Вопрос про хранение JWT в браузере — ответ: HttpOnly cookie, никогда localStorage.","","middle",[15,16,17,18,19],"rest-api","rate-limiting","security","jwt","spring-security",[],null,{"title":23,"description":24,"ogTitle":25,"ogDescription":26,"keywords":27,"schemaAnswer":37,"featuredSnippetReady":38},"Как настроить безопасность REST API с помощью Spring Security — Gymterview","Spring Security 6: SecurityFilterChain, stateless JWT, CORS, Method Security, Rate Limiting с Bucket4j. Переход с WebSecurityConfigurerAdapter, частые ошибки.","Безопасность REST API: Spring Security 6, JWT, Rate Limiting — Gymterview","Spring Security 6: SecurityFilterChain, stateless JWT, CORS, Rate Limiting. Новый API вместо WebSecurityConfigurerAdapter.",[28,29,30,31,32,33,34,35,36],"Spring Security 6","SecurityFilterChain","JWT","CORS","Rate Limiting","Bucket4j","stateless API","OAuth2 Resource Server","собеседование","Spring Security 6 использует SecurityFilterChain вместо устаревшего WebSecurityConfigurerAdapter. Для REST API: SessionCreationPolicy.STATELESS, CSRF отключён, JWT через oauth2ResourceServer. Method Security (@PreAuthorize) для fine-grained авторизации. Rate Limiting через Bucket4j + Redis. JWT хранить в HttpOnly cookie, не в localStorage.",true]