# Модуль 6: Безопасность и соответствие требованиям ## Содержание модуля 1. [Основы безопасности](#основы-безопасности) 2. [Уязвимости и межсервисное взаимодействие](#уязвимости-и-межсервисное-взаимодействие) 3. [Полный каталог уязвимостей информационной безопасности](#полный-каталог-уязвимостей-информационной-безопасности) 4. [Обфускация и защита кода](#обфускация-и-защита-кода) 5. [Security by Design](#security-by-design) 6. [Аутентификация и авторизация](#аутентификация-и-авторизация) 7. [Шифрование](#шифрование) 8. [Безопасность API](#безопасность-api) 9. [Безопасность данных](#безопасность-данных) 10. [Соответствие требованиям](#соответствие-требованиям) --- ## Основы безопасности ### Принципы информационной безопасности #### 1. CIA Triad - **Confidentiality (Конфиденциальность)** — доступ только авторизованным пользователям - **Integrity (Целостность)** — данные не изменяются несанкционированно - **Availability (Доступность)** — система доступна когда нужно #### 2. Defense in Depth **Принцип:** Многоуровневая защита системы. ``` ┌─────────────────────────────────────┐ │ Application │ ├─────────────────────────────────────┤ │ Network Security │ ├─────────────────────────────────────┤ │ Infrastructure │ ├─────────────────────────────────────┤ │ Physical Security │ └─────────────────────────────────────┘ ``` #### 3. Least Privilege **Принцип:** Предоставление минимально необходимых прав доступа. **Технический пример - Advanced Security Implementation:** ```java @Service @Transactional public class UserService { @Autowired private UserRepository userRepository; @Autowired private PasswordEncoder passwordEncoder; @Autowired private AuditService auditService; @PreAuthorize("hasRole('ADMIN')") @Audit(action = "DELETE_USER", resource = "USER") public void deleteUser(Long userId) { // Только админы могут удалять пользователей User user = userRepository.findById(userId) .orElseThrow(() -> new UserNotFoundException("User not found")); // Проверяем, что админ не удаляет сам себя Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth.getName().equals(user.getEmail())) { throw new SecurityException("Cannot delete your own account"); } // Логируем действие auditService.logAction("DELETE_USER", userId, auth.getName()); userRepository.deleteById(userId); } @PreAuthorize("hasRole('USER') and #userId == authentication.principal.id") public User getUserProfile(Long userId) { // Пользователи могут видеть только свой профиль return userRepository.findById(userId) .orElseThrow(() -> new UserNotFoundException("User not found")); } @PreAuthorize("hasRole('ADMIN') or hasRole('MANAGER')") public List getAllUsers() { // Админы и менеджеры могут видеть всех пользователей return userRepository.findAll(); } @PreAuthorize("hasRole('ADMIN')") @Audit(action = "UPDATE_USER_ROLE", resource = "USER") public void updateUserRole(Long userId, String newRole) { // Только админы могут изменять роли User user = userRepository.findById(userId) .orElseThrow(() -> new UserNotFoundException("User not found")); // Проверяем валидность роли if (!isValidRole(newRole)) { throw new IllegalArgumentException("Invalid role: " + newRole); } String oldRole = user.getRole(); user.setRole(newRole); userRepository.save(user); // Логируем изменение роли auditService.logAction("UPDATE_USER_ROLE", userId, SecurityContextHolder.getContext().getAuthentication().getName(), Map.of("oldRole", oldRole, "newRole", newRole)); } private boolean isValidRole(String role) { return Arrays.asList("USER", "MANAGER", "ADMIN").contains(role); } } // Security Configuration @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig { @Autowired private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; @Autowired private JwtRequestFilter jwtRequestFilter; @Autowired private UserDetailsService userDetailsService; @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(12); } @Bean public AuthenticationManager authenticationManager( AuthenticationConfiguration authConfig) throws Exception { return authConfig.getAuthenticationManager(); } @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeHttpRequests(authz -> authz .requestMatchers("/api/auth/**").permitAll() .requestMatchers("/api/public/**").permitAll() .requestMatchers("/actuator/health").permitAll() .requestMatchers("/api/admin/**").hasRole("ADMIN") .requestMatchers("/api/users/**").hasAnyRole("USER", "ADMIN", "MANAGER") .anyRequest().authenticated() ) .exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint) .and() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class) .headers(headers -> headers .frameOptions().deny() .contentTypeOptions().and() .httpStrictTransportSecurity(hstsConfig -> hstsConfig .maxAgeInSeconds(31536000) .includeSubdomains(true) ) ); return http.build(); } @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.setAllowedOriginPatterns(Arrays.asList("https://*.example.com")); configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); configuration.setAllowedHeaders(Arrays.asList("*")); configuration.setAllowCredentials(true); configuration.setMaxAge(3600L); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; } } // JWT Token Service @Service public class JwtTokenService { private static final String SECRET_KEY = "mySecretKey"; private static final int JWT_TOKEN_VALIDITY = 5 * 60 * 60; // 5 hours @Value("${jwt.secret}") private String jwtSecret; public String generateToken(UserDetails userDetails) { Map claims = new HashMap<>(); claims.put("roles", userDetails.getAuthorities()); claims.put("username", userDetails.getUsername()); return createToken(claims, userDetails.getUsername()); } private String createToken(Map claims, String subject) { return Jwts.builder() .setClaims(claims) .setSubject(subject) .setIssuedAt(new Date(System.currentTimeMillis())) .setExpiration(new Date(System.currentTimeMillis() + JWT_TOKEN_VALIDITY * 1000)) .signWith(SignatureAlgorithm.HS512, jwtSecret) .compact(); } public Boolean validateToken(String token, UserDetails userDetails) { final String username = getUsernameFromToken(token); return (username.equals(userDetails.getUsername()) && !isTokenExpired(token)); } public String getUsernameFromToken(String token) { return getClaimFromToken(token, Claims::getSubject); } public Date getExpirationDateFromToken(String token) { return getClaimFromToken(token, Claims::getExpiration); } public T getClaimFromToken(String token, Function claimsResolver) { final Claims claims = getAllClaimsFromToken(token); return claimsResolver.apply(claims); } private Claims getAllClaimsFromToken(String token) { return Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody(); } private Boolean isTokenExpired(String token) { final Date expiration = getExpirationDateFromToken(token); return expiration.before(new Date()); } } ``` **Node.js примеры - безопасность:** **JWT аутентификация с Express.js:** ```typescript import express, { Request, Response, NextFunction } from 'express'; import jwt from 'jsonwebtoken'; import bcrypt from 'bcrypt'; import rateLimit from 'express-rate-limit'; import helmet from 'helmet'; import cors from 'cors'; import { PrismaClient } from '@prisma/client'; const app = express(); const prisma = new PrismaClient(); // Middleware для безопасности app.use(helmet()); app.use(cors({ origin: process.env.ALLOWED_ORIGINS?.split(',') || ['http://localhost:3000'], credentials: true })); // Rate limiting const limiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 100, // limit each IP to 100 requests per windowMs message: 'Too many requests from this IP, please try again later.', standardHeaders: true, legacyHeaders: false, }); app.use('/api/', limiter); // JWT Token Service class JwtTokenService { private readonly secretKey: string; private readonly tokenValidity: number = 5 * 60 * 60; // 5 hours constructor() { this.secretKey = process.env.JWT_SECRET || 'mySecretKey'; } generateToken(userDetails: UserDetails): string { const claims = { roles: userDetails.roles, username: userDetails.username, userId: userDetails.id }; return jwt.sign( claims, this.secretKey, { subject: userDetails.username, expiresIn: this.tokenValidity, issuer: 'my-app', audience: 'my-app-users' } ); } validateToken(token: string, userDetails: UserDetails): boolean { try { const decoded = jwt.verify(token, this.secretKey) as any; return decoded.username === userDetails.username && !this.isTokenExpired(decoded); } catch (error) { return false; } } getUsernameFromToken(token: string): string | null { try { const decoded = jwt.verify(token, this.secretKey) as any; return decoded.username; } catch (error) { return null; } } private isTokenExpired(decoded: any): boolean { return Date.now() >= decoded.exp * 1000; } } // Security Filter class SecurityFilter { constructor(private jwtService: JwtTokenService) {} async authenticate(req: Request, res: Response, next: NextFunction): Promise { try { const token = this.extractToken(req); if (!token) { res.status(401).json({ error: 'Access token required' }); return; } const username = this.jwtService.getUsernameFromToken(token); if (!username) { res.status(401).json({ error: 'Invalid token' }); return; } req.user = { username }; next(); } catch (error) { res.status(401).json({ error: 'Authentication failed' }); } } addSecurityHeaders(req: Request, res: Response, next: NextFunction): void { res.setHeader('X-Content-Type-Options', 'nosniff'); res.setHeader('X-Frame-Options', 'DENY'); res.setHeader('X-XSS-Protection', '1; mode=block'); res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains'); next(); } private extractToken(req: Request): string | null { const authHeader = req.headers.authorization; if (authHeader && authHeader.startsWith('Bearer ')) { return authHeader.substring(7); } return null; } } // API endpoints app.post('/api/auth/login', async (req: Request, res: Response) => { const { username, password } = req.body; // Mock authentication if (username === 'admin' && password === 'password') { const jwtService = new JwtTokenService(); const token = jwtService.generateToken({ id: 1, username: 'admin', roles: ['ADMIN'] }); res.json({ token }); } else { res.status(401).json({ error: 'Invalid credentials' }); } }); app.get('/api/profile', new SecurityFilter(new JwtTokenService()).authenticate.bind(new SecurityFilter(new JwtTokenService())), (req: Request, res: Response) => { res.json({ user: req.user }); } ); app.listen(3000, () => { console.log('Server running on port 3000'); }); ``` // Rate Limiting @Component public class RateLimitingService { private final Map limiters = new ConcurrentHashMap<>(); public boolean isAllowed(String key, int maxRequests, Duration window) { RateLimiter limiter = limiters.computeIfAbsent(key, k -> RateLimiter.create(maxRequests / window.getSeconds())); return limiter.tryAcquire(); } public boolean isAllowedForUser(String userId, int maxRequests, Duration window) { return isAllowed("user:" + userId, maxRequests, window); } public boolean isAllowedForIP(String ip, int maxRequests, Duration window) { return isAllowed("ip:" + ip, maxRequests, window); } } // Security Filter @Component public class SecurityFilter implements Filter { @Autowired private RateLimitingService rateLimitingService; @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; String clientIP = getClientIP(httpRequest); String userId = getCurrentUserId(); // Rate limiting if (!rateLimitingService.isAllowedForIP(clientIP, 100, Duration.ofMinutes(1))) { httpResponse.setStatus(HttpStatus.TOO_MANY_REQUESTS.value()); return; } if (userId != null && !rateLimitingService.isAllowedForUser(userId, 1000, Duration.ofMinutes(1))) { httpResponse.setStatus(HttpStatus.TOO_MANY_REQUESTS.value()); return; } // Security headers httpResponse.setHeader("X-Content-Type-Options", "nosniff"); httpResponse.setHeader("X-Frame-Options", "DENY"); httpResponse.setHeader("X-XSS-Protection", "1; mode=block"); httpResponse.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains"); chain.doFilter(request, response); } private String getClientIP(HttpServletRequest request) { String xForwardedFor = request.getHeader("X-Forwarded-For"); if (xForwardedFor != null && !xForwardedFor.isEmpty()) { return xForwardedFor.split(",")[0].trim(); } return request.getRemoteAddr(); } private String getCurrentUserId() { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth != null && auth.isAuthenticated()) { return auth.getName(); } return null; } } ``` ### Угрозы безопасности #### 1. OWASP Top 10 (2021) ##### A01: Broken Access Control ```java // Плохо: нет проверки прав @GetMapping("/users/{id}") public User getUser(@PathVariable Long id) { return userRepository.findById(id); } // Хорошо: проверка прав @GetMapping("/users/{id}") @PreAuthorize("hasRole('ADMIN') or #id == authentication.principal.id") public User getUser(@PathVariable Long id) { return userRepository.findById(id); } ``` ##### A02: Cryptographic Failures ```java // Плохо: слабое шифрование @Value("${app.encryption.key:123456}") private String encryptionKey; // Хорошо: сильное шифрование @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(12); } ``` ##### A03: Injection ```java // Плохо: SQL injection String query = "SELECT * FROM users WHERE name = '" + userName + "'"; // Хорошо: параметризованные запросы @Query("SELECT u FROM User u WHERE u.name = :name") User findByName(@Param("name") String name); ``` ##### A04: Insecure Design ```java // Плохо: небезопасный дизайн public class User { private String password; // пароль в открытом виде public String getPassword() { return password; // возвращаем пароль } } // Хорошо: безопасный дизайн public class User { private String passwordHash; // хэш пароля public void setPassword(String password) { this.passwordHash = passwordEncoder.encode(password); } // нет геттера для пароля } ``` ##### A05: Security Misconfiguration ```yaml # Плохо: небезопасная конфигурация spring: security: user: name: admin password: admin123 # Хорошо: безопасная конфигурация spring: security: user: name: ${ADMIN_USERNAME:admin} password: ${ADMIN_PASSWORD:} ``` --- ## Уязвимости и межсервисное взаимодействие ### Типы уязвимостей в микросервисной архитектуре #### 1. Уязвимости межсервисного взаимодействия **Проблемы:** - Отсутствие аутентификации между сервисами - Передача чувствительных данных в открытом виде - Отсутствие валидации токенов - Man-in-the-middle атаки - Replay атаки **Решения:** - Mutual TLS (mTLS) - Service-to-Service токены - API Gateway с аутентификацией - Token Validation Middleware (TVM) #### 2. TVM (Token Validation Middleware) **TVM** — промежуточное ПО для валидации токенов между микросервисами. **Принципы работы:** 1. Сервис получает токен от клиента 2. TVM валидирует токен 3. TVM извлекает информацию о пользователе/сервисе 4. TVM передает валидные данные в целевой сервис **Технический пример - TVM Implementation:** ```java @Component public class TokenValidationMiddleware { @Autowired private JwtTokenService jwtTokenService; @Autowired private ServiceRegistry serviceRegistry; public ServiceTokenValidationResult validateServiceToken(String token, String targetService) { try { // Валидация токена Claims claims = jwtTokenService.validateToken(token); // Проверка прав доступа к сервису if (!hasAccessToService(claims, targetService)) { return ServiceTokenValidationResult.denied("No access to service: " + targetService); } // Проверка срока действия токена if (isTokenExpired(claims)) { return ServiceTokenValidationResult.denied("Token expired"); } // Извлечение информации о сервисе ServiceInfo serviceInfo = extractServiceInfo(claims); return ServiceTokenValidationResult.success(serviceInfo); } catch (JwtException e) { return ServiceTokenValidationResult.denied("Invalid token: " + e.getMessage()); } } private boolean hasAccessToService(Claims claims, String targetService) { List allowedServices = claims.get("allowed_services", List.class); return allowedServices != null && allowedServices.contains(targetService); } private boolean isTokenExpired(Claims claims) { Date expiration = claims.getExpiration(); return expiration.before(new Date()); } private ServiceInfo extractServiceInfo(Claims claims) { return ServiceInfo.builder() .serviceId(claims.getSubject()) .serviceName(claims.get("service_name", String.class)) .permissions(claims.get("permissions", List.class)) .issuedAt(claims.getIssuedAt()) .expiresAt(claims.getExpiration()) .build(); } } // Service Token Validation Result @Data @Builder public class ServiceTokenValidationResult { private boolean valid; private String errorMessage; private ServiceInfo serviceInfo; public static ServiceTokenValidationResult success(ServiceInfo serviceInfo) { return ServiceTokenValidationResult.builder() .valid(true) .serviceInfo(serviceInfo) .build(); } public static ServiceTokenValidationResult denied(String errorMessage) { return ServiceTokenValidationResult.builder() .valid(false) .errorMessage(errorMessage) .build(); } } // Service Info @Data @Builder public class ServiceInfo { private String serviceId; private String serviceName; private List permissions; private Date issuedAt; private Date expiresAt; } ``` **Rust примеры - TVM с Actix Web:** ```rust // Token Validation Middleware для Actix Web use actix_web::{web, HttpRequest, HttpResponse, Error, middleware::Next}; use jsonwebtoken::{decode, DecodingKey, Validation, Algorithm}; use serde::{Deserialize, Serialize}; use std::collections::HashSet; #[derive(Debug, Serialize, Deserialize)] struct ServiceClaims { sub: String, // service_id service_name: String, allowed_services: Vec, permissions: Vec, iat: u64, // issued_at exp: u64, // expires_at } #[derive(Debug, Clone)] pub struct ServiceInfo { pub service_id: String, pub service_name: String, pub permissions: Vec, } pub struct TokenValidationMiddleware { decoding_key: DecodingKey, validation: Validation, } impl TokenValidationMiddleware { pub fn new(secret: &str) -> Self { let mut validation = Validation::new(Algorithm::HS256); validation.set_issuer(&["microservices-platform"]); Self { decoding_key: DecodingKey::from_secret(secret.as_ref()), validation, } } pub fn validate_service_token( &self, token: &str, target_service: &str, ) -> Result { // Декодирование токена let token_data = decode::(token, &self.decoding_key, &self.validation) .map_err(|e| format!("Token validation failed: {}", e))?; let claims = token_data.claims; // Проверка срока действия let now = chrono::Utc::now().timestamp() as u64; if claims.exp < now { return Err("Token expired".to_string()); } // Проверка прав доступа к сервису if !claims.allowed_services.contains(&target_service.to_string()) { return Err(format!("No access to service: {}", target_service)); } Ok(ServiceInfo { service_id: claims.sub, service_name: claims.service_name, permissions: claims.permissions, }) } } // Middleware для Actix Web pub async fn token_validation_middleware( req: HttpRequest, next: Next, ) -> Result { // Извлечение токена из заголовка let token = req.headers() .get("Authorization") .and_then(|h| h.to_str().ok()) .and_then(|s| s.strip_prefix("Bearer ")) .ok_or_else(|| actix_web::error::ErrorUnauthorized("Missing or invalid token"))?; // Получение целевого сервиса из пути let target_service = req.path().split('/').nth(1) .ok_or_else(|| actix_web::error::ErrorBadRequest("Invalid service path"))?; // Валидация токена let middleware = TokenValidationMiddleware::new("your-secret-key"); let service_info = middleware.validate_service_token(token, target_service) .map_err(|e| actix_web::error::ErrorUnauthorized(e))?; // Добавление информации о сервисе в запрос req.extensions_mut().insert(service_info); next.run(req).await } // Handler с валидацией токена async fn protected_endpoint( req: HttpRequest, service_info: web::Data, ) -> Result { Ok(HttpResponse::Ok().json(serde_json::json!({ "message": "Access granted", "service": service_info.service_name, "permissions": service_info.permissions }))) } #[actix_web::main] async fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() .wrap(token_validation_middleware) .route("/api/protected", web::get().to(protected_endpoint)) }) .bind("127.0.0.1:8080")? .run() .await } ``` **Python примеры - TVM с FastAPI:** ```python # Token Validation Middleware для FastAPI from fastapi import FastAPI, HTTPException, Depends, Request from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials import jwt from datetime import datetime, timedelta from typing import List, Optional import asyncio app = FastAPI(title="TVM Service", version="1.0.0") security = HTTPBearer() class ServiceClaims: def __init__(self, service_id: str, service_name: str, allowed_services: List[str], permissions: List[str], issued_at: datetime, expires_at: datetime): self.service_id = service_id self.service_name = service_name self.allowed_services = allowed_services self.permissions = permissions self.issued_at = issued_at self.expires_at = expires_at class TokenValidationMiddleware: def __init__(self, secret_key: str): self.secret_key = secret_key self.algorithm = "HS256" def validate_service_token(self, token: str, target_service: str) -> ServiceClaims: try: # Декодирование токена payload = jwt.decode(token, self.secret_key, algorithms=[self.algorithm]) # Проверка срока действия exp_timestamp = payload.get('exp') if exp_timestamp and datetime.utcnow().timestamp() > exp_timestamp: raise HTTPException(status_code=401, detail="Token expired") # Проверка прав доступа к сервису allowed_services = payload.get('allowed_services', []) if target_service not in allowed_services: raise HTTPException( status_code=403, detail=f"No access to service: {target_service}" ) # Создание объекта ServiceClaims return ServiceClaims( service_id=payload.get('sub'), service_name=payload.get('service_name'), allowed_services=allowed_services, permissions=payload.get('permissions', []), issued_at=datetime.fromtimestamp(payload.get('iat', 0)), expires_at=datetime.fromtimestamp(exp_timestamp) ) except jwt.ExpiredSignatureError: raise HTTPException(status_code=401, detail="Token expired") except jwt.InvalidTokenError: raise HTTPException(status_code=401, detail="Invalid token") # Dependency для валидации токена async def validate_token( request: Request, credentials: HTTPAuthorizationCredentials = Depends(security) ) -> ServiceClaims: token = credentials.credentials # Получение целевого сервиса из пути path_parts = request.url.path.split('/') target_service = path_parts[1] if len(path_parts) > 1 else "default" # Валидация токена middleware = TokenValidationMiddleware("your-secret-key") return middleware.validate_service_token(token, target_service) # API endpoints @app.get("/api/protected") async def protected_endpoint(service_info: ServiceClaims = Depends(validate_token)): return { "message": "Access granted", "service": service_info.service_name, "permissions": service_info.permissions, "service_id": service_info.service_id } @app.get("/api/services/{service_name}/data") async def get_service_data( service_name: str, service_info: ServiceClaims = Depends(validate_token) ): # Проверка дополнительных прав if "read_data" not in service_info.permissions: raise HTTPException(status_code=403, detail="Insufficient permissions") return { "service": service_name, "data": f"Data for {service_name}", "accessed_by": service_info.service_name } # Utility для создания токенов (для тестирования) def create_service_token(service_id: str, service_name: str, allowed_services: List[str], permissions: List[str]) -> str: payload = { "sub": service_id, "service_name": service_name, "allowed_services": allowed_services, "permissions": permissions, "iat": datetime.utcnow(), "exp": datetime.utcnow() + timedelta(hours=1) } return jwt.encode(payload, "your-secret-key", algorithm="HS256") if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000) ``` **Node.js примеры - TVM с Express.js:** ```typescript // Token Validation Middleware для Express.js import express, { Request, Response, NextFunction } from 'express'; import jwt from 'jsonwebtoken'; import { z } from 'zod'; const app = express(); // Interfaces interface ServiceClaims { sub: string; // service_id service_name: string; allowed_services: string[]; permissions: string[]; iat: number; // issued_at exp: number; // expires_at } interface ServiceInfo { serviceId: string; serviceName: string; permissions: string[]; } // Token Validation Middleware class TokenValidationMiddleware { private secretKey: string; private algorithm: jwt.Algorithm = 'HS256'; constructor(secretKey: string) { this.secretKey = secretKey; } validateServiceToken(token: string, targetService: string): ServiceInfo { try { // Декодирование токена const decoded = jwt.verify(token, this.secretKey, { algorithms: [this.algorithm] }) as ServiceClaims; // Проверка срока действия const now = Math.floor(Date.now() / 1000); if (decoded.exp < now) { throw new Error('Token expired'); } // Проверка прав доступа к сервису if (!decoded.allowed_services.includes(targetService)) { throw new Error(`No access to service: ${targetService}`); } return { serviceId: decoded.sub, serviceName: decoded.service_name, permissions: decoded.permissions }; } catch (error) { if (error instanceof jwt.JsonWebTokenError) { throw new Error('Invalid token'); } throw error; } } } // Middleware для Express.js const tokenValidationMiddleware = (req: Request, res: Response, next: NextFunction) => { try { // Извлечение токена из заголовка const authHeader = req.headers.authorization; if (!authHeader || !authHeader.startsWith('Bearer ')) { return res.status(401).json({ error: 'Missing or invalid token' }); } const token = authHeader.substring(7); // Получение целевого сервиса из пути const pathParts = req.path.split('/'); const targetService = pathParts[2] || 'default'; // /api/services/{service} // Валидация токена const middleware = new TokenValidationMiddleware('your-secret-key'); const serviceInfo = middleware.validateServiceToken(token, targetService); // Добавление информации о сервисе в запрос (req as any).serviceInfo = serviceInfo; next(); } catch (error) { res.status(401).json({ error: error.message }); } }; // API endpoints app.get('/api/protected', tokenValidationMiddleware, (req: Request, res: Response) => { const serviceInfo = (req as any).serviceInfo; res.json({ message: 'Access granted', service: serviceInfo.serviceName, permissions: serviceInfo.permissions, serviceId: serviceInfo.serviceId }); }); app.get('/api/services/:serviceName/data', tokenValidationMiddleware, (req: Request, res: Response) => { const serviceInfo = (req as any).serviceInfo; const { serviceName } = req.params; // Проверка дополнительных прав if (!serviceInfo.permissions.includes('read_data')) { return res.status(403).json({ error: 'Insufficient permissions' }); } res.json({ service: serviceName, data: `Data for ${serviceName}`, accessedBy: serviceInfo.serviceName }); }); // Utility для создания токенов (для тестирования) function createServiceToken( serviceId: string, serviceName: string, allowedServices: string[], permissions: string[] ): string { const payload = { sub: serviceId, service_name: serviceName, allowed_services: allowedServices, permissions: permissions, iat: Math.floor(Date.now() / 1000), exp: Math.floor(Date.now() / 1000) + (60 * 60) // 1 hour }; return jwt.sign(payload, 'your-secret-key', { algorithm: 'HS256' }); } // Error handling middleware app.use((error: Error, req: Request, res: Response, next: NextFunction) => { console.error(error); res.status(500).json({ error: 'Internal server error' }); }); app.listen(3000, () => { console.log('TVM Service running on port 3000'); }); ``` #### 3. Безопасность межсервисного взаимодействия **Принципы:** - **Zero Trust** — не доверяй, проверяй - **Least Privilege** — минимальные права доступа - **Defense in Depth** — многоуровневая защита - **Audit Everything** — логирование всех операций **Паттерны безопасности:** - Service Mesh с mTLS - API Gateway с аутентификацией - Token-based аутентификация - Rate limiting и throttling - Circuit breaker для защиты от DoS --- ## Полный каталог уязвимостей информационной безопасности ### OWASP Top 10 (2021) - Детальный анализ #### A01: Broken Access Control (Нарушение контроля доступа) **Описание:** Неправильная реализация ограничений доступа, позволяющая пользователям действовать вне своих предполагаемых привилегий. **Примеры уязвимостей:** - Обход авторизации путем изменения URL - Принудительный просмотр, изменение или удаление данных других пользователей - Повышение привилегий - Метаданные манипуляции (JWT, cookies) - CORS неправильная конфигурация **Методы устранения:** ```java // Правильная реализация контроля доступа @RestController @RequestMapping("/api/users") public class UserController { @GetMapping("/{userId}") @PreAuthorize("hasRole('USER') and #userId == authentication.principal.id") public ResponseEntity getUser(@PathVariable Long userId) { // Проверка прав доступа встроена в аннотацию return ResponseEntity.ok(userService.findById(userId)); } @GetMapping("/admin") @PreAuthorize("hasRole('ADMIN')") public ResponseEntity> getAllUsers() { return ResponseEntity.ok(userService.findAll()); } } // Дополнительная проверка на уровне сервиса @Service public class UserService { public User findById(Long userId) { User currentUser = getCurrentUser(); // Проверка: пользователь может видеть только свои данные if (!currentUser.getId().equals(userId) && !currentUser.hasRole("ADMIN")) { throw new AccessDeniedException("Access denied"); } return userRepository.findById(userId) .orElseThrow(() -> new UserNotFoundException("User not found")); } } ``` **Rust примеры - Контроль доступа:** ```rust // Контроль доступа в Rust use actix_web::{web, HttpRequest, HttpResponse, Error}; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] struct User { id: u64, name: String, role: String, } #[derive(Debug, Serialize, Deserialize)] struct AccessToken { user_id: u64, role: String, permissions: Vec, } // Middleware для проверки доступа pub async fn access_control_middleware( req: HttpRequest, next: actix_web::middleware::Next, ) -> Result { // Извлечение токена let token = extract_token(&req)?; // Валидация токена let access_token = validate_token(token)?; // Проверка прав доступа if !has_permission(&access_token, &req.path()) { return Ok(HttpResponse::Forbidden().json(serde_json::json!({ "error": "Access denied" }))); } // Добавление информации о пользователе в запрос req.extensions_mut().insert(access_token); next.run(req).await } fn extract_token(req: &HttpRequest) -> Result { req.headers() .get("Authorization") .and_then(|h| h.to_str().ok()) .and_then(|s| s.strip_prefix("Bearer ")) .ok_or_else(|| actix_web::error::ErrorUnauthorized("Missing token")) .map(|s| s.to_string()) } fn validate_token(token: &str) -> Result { // Здесь должна быть реальная валидация JWT // Для примера возвращаем mock данные Ok(AccessToken { user_id: 1, role: "USER".to_string(), permissions: vec!["read:own_data".to_string()], }) } fn has_permission(token: &AccessToken, path: &str) -> bool { // Проверка прав доступа на основе пути и роли match path { path if path.startsWith("/api/users/") => { // Пользователь может видеть только свои данные if token.permissions.contains(&"read:own_data".to_string()) { return true; } } path if path.startsWith("/api/admin/") => { // Только админы могут получить доступ к админ панели return token.role == "ADMIN"; } _ => return false, } false } ``` #### A02: Cryptographic Failures (Криптографические сбои) **Описание:** Неправильное использование криптографии или слабые криптографические алгоритмы. **Примеры уязвимостей:** - Передача данных без шифрования - Использование слабых алгоритмов шифрования - Неправильное управление ключами - Использование устаревших алгоритмов (MD5, SHA-1) - Хранение паролей в открытом виде **Методы устранения:** ```java // Правильное шифрование данных @Service public class EncryptionService { private static final String ALGORITHM = "AES/GCM/NoPadding"; private static final int KEY_LENGTH = 256; private static final int IV_LENGTH = 12; private static final int TAG_LENGTH = 16; @Value("${encryption.key}") private String encryptionKey; public String encrypt(String plaintext) { try { // Генерация случайного IV byte[] iv = new byte[IV_LENGTH]; SecureRandom.getInstanceStrong().nextBytes(iv); // Создание ключа SecretKeySpec keySpec = new SecretKeySpec( encryptionKey.getBytes(StandardCharsets.UTF_8), "AES"); // Инициализация шифра Cipher cipher = Cipher.getInstance(ALGORITHM); GCMParameterSpec gcmSpec = new GCMParameterSpec(TAG_LENGTH * 8, iv); cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmSpec); // Шифрование byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8)); // Объединение IV и зашифрованных данных byte[] encryptedData = new byte[IV_LENGTH + ciphertext.length]; System.arraycopy(iv, 0, encryptedData, 0, IV_LENGTH); System.arraycopy(ciphertext, 0, encryptedData, IV_LENGTH, ciphertext.length); return Base64.getEncoder().encodeToString(encryptedData); } catch (Exception e) { throw new EncryptionException("Failed to encrypt data", e); } } public String decrypt(String encryptedData) { try { byte[] encryptedBytes = Base64.getDecoder().decode(encryptedData); // Извлечение IV byte[] iv = new byte[IV_LENGTH]; System.arraycopy(encryptedBytes, 0, iv, 0, IV_LENGTH); // Извлечение зашифрованных данных byte[] ciphertext = new byte[encryptedBytes.length - IV_LENGTH]; System.arraycopy(encryptedBytes, IV_LENGTH, ciphertext, 0, ciphertext.length); // Создание ключа SecretKeySpec keySpec = new SecretKeySpec( encryptionKey.getBytes(StandardCharsets.UTF_8), "AES"); // Инициализация шифра для расшифровки Cipher cipher = Cipher.getInstance(ALGORITHM); GCMParameterSpec gcmSpec = new GCMParameterSpec(TAG_LENGTH * 8, iv); cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmSpec); // Расшифровка byte[] plaintext = cipher.doFinal(ciphertext); return new String(plaintext, StandardCharsets.UTF_8); } catch (Exception e) { throw new EncryptionException("Failed to decrypt data", e); } } } // Правильное хеширование паролей @Service public class PasswordService { private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(12); public String hashPassword(String plainPassword) { return passwordEncoder.encode(plainPassword); } public boolean verifyPassword(String plainPassword, String hashedPassword) { return passwordEncoder.matches(plainPassword, hashedPassword); } // Проверка силы пароля public boolean isPasswordStrong(String password) { if (password.length() < 8) return false; boolean hasUpperCase = password.chars().anyMatch(Character::isUpperCase); boolean hasLowerCase = password.chars().anyMatch(Character::isLowerCase); boolean hasDigit = password.chars().anyMatch(Character::isDigit); boolean hasSpecialChar = password.chars().anyMatch(ch -> "!@#$%^&*()_+-=[]{}|;:,.<>?".contains(String.valueOf(ch))); return hasUpperCase && hasLowerCase && hasDigit && hasSpecialChar; } } ``` #### A03: Injection (Инъекции) **Описание:** Внедрение вредоносного кода через пользовательский ввод. **Типы инъекций:** - SQL Injection - NoSQL Injection - Command Injection - LDAP Injection - XPath Injection **Методы устранения:** ```java // Защита от SQL Injection @Repository public class UserRepository { @Autowired private JdbcTemplate jdbcTemplate; // НЕПРАВИЛЬНО - уязвимо к SQL Injection public List findByUsernameUnsafe(String username) { String sql = "SELECT * FROM users WHERE username = '" + username + "'"; return jdbcTemplate.query(sql, new UserRowMapper()); } // ПРАВИЛЬНО - использование параметризованных запросов public List findByUsernameSafe(String username) { String sql = "SELECT * FROM users WHERE username = ?"; return jdbcTemplate.query(sql, new Object[]{username}, new UserRowMapper()); } // Использование JPA с именованными параметрами @Query("SELECT u FROM User u WHERE u.username = :username") List findByUsername(@Param("username") String username); } // Защита от NoSQL Injection @Service public class UserService { @Autowired private MongoTemplate mongoTemplate; // НЕПРАВИЛЬНО - уязвимо к NoSQL Injection public List findByUsernameUnsafe(String username) { Query query = new Query(); query.addCriteria(Criteria.where("username").is(username)); return mongoTemplate.find(query, User.class); } // ПРАВИЛЬНО - валидация и санитизация ввода public List findByUsernameSafe(String username) { // Валидация ввода if (!isValidUsername(username)) { throw new IllegalArgumentException("Invalid username format"); } // Санитизация ввода String sanitizedUsername = sanitizeInput(username); Query query = new Query(); query.addCriteria(Criteria.where("username").is(sanitizedUsername)); return mongoTemplate.find(query, User.class); } private boolean isValidUsername(String username) { // Проверка на допустимые символы return username.matches("^[a-zA-Z0-9_]{3,20}$"); } private String sanitizeInput(String input) { // Удаление потенциально опасных символов return input.replaceAll("[^a-zA-Z0-9_]", ""); } } // Защита от Command Injection @Service public class SystemService { // НЕПРАВИЛЬНО - уязвимо к Command Injection public String executeCommandUnsafe(String command) { try { Process process = Runtime.getRuntime().exec(command); // обработка результата... } catch (IOException e) { throw new RuntimeException("Command execution failed", e); } } // ПРАВИЛЬНО - использование ProcessBuilder с валидацией public String executeCommandSafe(String command, String... args) { // Валидация команды if (!isAllowedCommand(command)) { throw new IllegalArgumentException("Command not allowed"); } // Валидация аргументов for (String arg : args) { if (!isValidArgument(arg)) { throw new IllegalArgumentException("Invalid argument: " + arg); } } try { ProcessBuilder processBuilder = new ProcessBuilder(command); processBuilder.command().addAll(Arrays.asList(args)); Process process = processBuilder.start(); // обработка результата... } catch (IOException e) { throw new RuntimeException("Command execution failed", e); } } private boolean isAllowedCommand(String command) { Set allowedCommands = Set.of("ls", "ps", "df", "whoami"); return allowedCommands.contains(command); } private boolean isValidArgument(String arg) { // Проверка на допустимые символы return arg.matches("^[a-zA-Z0-9._/-]+$"); } } ``` #### A04: Insecure Design (Небезопасный дизайн) **Описание:** Недостатки в архитектуре и дизайне приложения. **Примеры проблем:** - Отсутствие threat modeling - Неправильная архитектура безопасности - Отсутствие принципа "fail secure" - Недостаточная изоляция компонентов **Методы устранения:** ```java // Безопасный дизайн архитектуры @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // Принцип "fail secure" - по умолчанию все заблокировано .authorizeHttpRequests(authz -> authz .requestMatchers("/api/public/**").permitAll() .requestMatchers("/api/admin/**").hasRole("ADMIN") .anyRequest().authenticated() ) // Защита от CSRF .csrf(csrf -> csrf .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) ) // Защита от clickjacking .headers(headers -> headers .frameOptions().deny() .contentTypeOptions().and() .httpStrictTransportSecurity(hstsConfig -> hstsConfig .maxAgeInSeconds(31536000) .includeSubdomains(true) ) ) // Сессии .sessionManagement(session -> session .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .maximumSessions(1) .maxSessionsPreventsLogin(true) ) // Обработка ошибок .exceptionHandling(exceptions -> exceptions .authenticationEntryPoint(customAuthenticationEntryPoint()) .accessDeniedHandler(customAccessDeniedHandler()) ); return http.build(); } @Bean public AuthenticationEntryPoint customAuthenticationEntryPoint() { return (request, response, authException) -> { response.setStatus(HttpStatus.UNAUTHORIZED.value()); response.setContentType("application/json"); response.getWriter().write("{\"error\":\"Unauthorized\"}"); }; } @Bean public AccessDeniedHandler customAccessDeniedHandler() { return (request, response, accessDeniedException) -> { response.setStatus(HttpStatus.FORBIDDEN.value()); response.setContentType("application/json"); response.getWriter().write("{\"error\":\"Access denied\"}"); }; } } // Threat Modeling в коде @Component public class ThreatModelingService { // Анализ угроз для каждого endpoint public ThreatAnalysis analyzeEndpoint(String endpoint, String method) { ThreatAnalysis analysis = new ThreatAnalysis(); // STRIDE анализ analysis.addThreat(ThreatType.SPOOFING, "User impersonation"); analysis.addThreat(ThreatType.TAMPERING, "Data modification"); analysis.addThreat(ThreatType.REPUDIATION, "Action denial"); analysis.addThreat(ThreatType.INFORMATION_DISCLOSURE, "Data exposure"); analysis.addThreat(ThreatType.DENIAL_OF_SERVICE, "Service unavailability"); analysis.addThreat(ThreatType.ELEVATION_OF_PRIVILEGE, "Unauthorized access"); return analysis; } } ``` #### A05: Security Misconfiguration (Неправильная конфигурация безопасности) **Описание:** Неправильная настройка компонентов безопасности. **Примеры проблем:** - Отсутствие обновлений безопасности - Небезопасные настройки по умолчанию - Открытые ненужные порты - Неправильная конфигурация CORS - Отсутствие заголовков безопасности **Методы устранения:** ```java // Безопасная конфигурация @Configuration public class SecurityConfiguration { @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); // Ограничение источников configuration.setAllowedOriginPatterns(List.of("https://*.example.com")); configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE")); configuration.setAllowedHeaders(List.of("*")); configuration.setAllowCredentials(true); configuration.setMaxAge(3600L); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/api/**", configuration); return source; } @Bean public FilterRegistrationBean securityHeadersFilter() { FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new SecurityHeadersFilter()); registrationBean.addUrlPatterns("/*"); registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE); return registrationBean; } } // Фильтр для добавления заголовков безопасности public class SecurityHeadersFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletResponse httpResponse = (HttpServletResponse) response; // Заголовки безопасности httpResponse.setHeader("X-Content-Type-Options", "nosniff"); httpResponse.setHeader("X-Frame-Options", "DENY"); httpResponse.setHeader("X-XSS-Protection", "1; mode=block"); httpResponse.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains"); httpResponse.setHeader("Referrer-Policy", "strict-origin-when-cross-origin"); httpResponse.setHeader("Content-Security-Policy", "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'"); chain.doFilter(request, response); } } // Проверка конфигурации безопасности @Component public class SecurityConfigurationValidator { @EventListener public void onApplicationReady(ApplicationReadyEvent event) { validateSecurityConfiguration(); } private void validateSecurityConfiguration() { // Проверка переменных окружения validateEnvironmentVariables(); // Проверка конфигурации базы данных validateDatabaseConfiguration(); // Проверка SSL/TLS validateSSLConfiguration(); } private void validateEnvironmentVariables() { String[] requiredVars = { "JWT_SECRET", "ENCRYPTION_KEY", "DB_PASSWORD", "ADMIN_PASSWORD" }; for (String var : requiredVars) { if (System.getenv(var) == null) { throw new SecurityConfigurationException("Required environment variable not set: " + var); } } } private void validateDatabaseConfiguration() { // Проверка подключения к БД с SSL // Проверка прав доступа к БД // Проверка настроек пула соединений } private void validateSSLConfiguration() { // Проверка SSL сертификатов // Проверка TLS версии // Проверка cipher suites } } ``` #### A06: Vulnerable and Outdated Components (Уязвимые и устаревшие компоненты) **Описание:** Использование компонентов с известными уязвимостями. **Методы устранения:** ```java // Автоматическая проверка уязвимостей @Component public class VulnerabilityScanner { @Scheduled(cron = "0 0 2 * * ?") // Каждый день в 2:00 public void scanForVulnerabilities() { scanDependencies(); scanSystemComponents(); generateReport(); } private void scanDependencies() { // Сканирование Maven зависимостей List dependencies = getMavenDependencies(); for (Dependency dependency : dependencies) { List vulnerabilities = checkVulnerabilityDatabase(dependency); if (!vulnerabilities.isEmpty()) { logVulnerabilities(dependency, vulnerabilities); notifySecurityTeam(dependency, vulnerabilities); } } } private void scanSystemComponents() { // Проверка версий Java, Spring Boot, и других компонентов String javaVersion = System.getProperty("java.version"); String springVersion = SpringBootVersion.getVersion(); checkComponentVersions(javaVersion, springVersion); } private void generateReport() { // Генерация отчета об уязвимостях VulnerabilityReport report = new VulnerabilityReport(); report.setScanDate(LocalDateTime.now()); report.setVulnerabilities(foundVulnerabilities); saveReport(report); } } // Конфигурация для автоматических обновлений @Configuration public class DependencyManagementConfig { @Bean public DependencyUpdatesChecker dependencyUpdatesChecker() { return new DependencyUpdatesChecker(); } } @Component public class DependencyUpdatesChecker { @Scheduled(cron = "0 0 1 * * ?") // Каждый день в 1:00 public void checkForUpdates() { List updates = findAvailableUpdates(); for (DependencyUpdate update : updates) { if (update.isSecurityUpdate()) { notifySecurityTeam(update); } } } } ``` #### A07: Identification and Authentication Failures (Сбои идентификации и аутентификации) **Описание:** Неправильная реализация аутентификации и идентификации. **Методы устранения:** ```java // Безопасная аутентификация @Service public class AuthenticationService { @Autowired private PasswordService passwordService; @Autowired private RateLimitingService rateLimitingService; @Autowired private AuditService auditService; public AuthenticationResult authenticate(String username, String password, String ipAddress) { // Проверка rate limiting if (!rateLimitingService.isAllowed(ipAddress)) { auditService.logFailedLogin(username, ipAddress, "Rate limit exceeded"); throw new AuthenticationException("Too many login attempts"); } // Поиск пользователя User user = userService.findByUsername(username); if (user == null) { auditService.logFailedLogin(username, ipAddress, "User not found"); throw new AuthenticationException("Invalid credentials"); } // Проверка блокировки аккаунта if (user.isLocked()) { auditService.logFailedLogin(username, ipAddress, "Account locked"); throw new AuthenticationException("Account is locked"); } // Проверка пароля if (!passwordService.verifyPassword(password, user.getPasswordHash())) { handleFailedLogin(user, ipAddress); throw new AuthenticationException("Invalid credentials"); } // Проверка двухфакторной аутентификации if (user.isTwoFactorEnabled()) { return AuthenticationResult.twoFactorRequired(user.getId()); } // Успешная аутентификация auditService.logSuccessfulLogin(username, ipAddress); userService.resetFailedLoginAttempts(user.getId()); return AuthenticationResult.success(user); } private void handleFailedLogin(User user, String ipAddress) { auditService.logFailedLogin(user.getUsername(), ipAddress, "Invalid password"); int failedAttempts = userService.incrementFailedLoginAttempts(user.getId()); if (failedAttempts >= 5) { userService.lockAccount(user.getId()); auditService.logAccountLocked(user.getUsername(), ipAddress); } } } // Rate Limiting Service @Service public class RateLimitingService { @Autowired private RedisTemplate redisTemplate; public boolean isAllowed(String ipAddress) { String key = "login_attempts:" + ipAddress; // Получение текущего количества попыток String attemptsStr = redisTemplate.opsForValue().get(key); int attempts = attemptsStr != null ? Integer.parseInt(attemptsStr) : 0; // Проверка лимита if (attempts >= 5) { return false; } // Увеличение счетчика redisTemplate.opsForValue().increment(key); redisTemplate.expire(key, Duration.ofMinutes(15)); return true; } } ``` #### A08: Software and Data Integrity Failures (Сбои целостности ПО и данных) **Описание:** Недостаточная проверка целостности данных и кода. **Методы устранения:** ```java // Проверка целостности данных @Service public class DataIntegrityService { public String calculateChecksum(String data) { try { MessageDigest digest = MessageDigest.getInstance("SHA-256"); byte[] hash = digest.digest(data.getBytes(StandardCharsets.UTF_8)); return Base64.getEncoder().encodeToString(hash); } catch (NoSuchAlgorithmException e) { throw new RuntimeException("SHA-256 algorithm not available", e); } } public boolean verifyDataIntegrity(String data, String expectedChecksum) { String actualChecksum = calculateChecksum(data); return actualChecksum.equals(expectedChecksum); } public void validateFileIntegrity(String filePath, String expectedChecksum) { try { String fileContent = Files.readString(Paths.get(filePath)); if (!verifyDataIntegrity(fileContent, expectedChecksum)) { throw new DataIntegrityException("File integrity check failed"); } } catch (IOException e) { throw new DataIntegrityException("Failed to read file", e); } } } // Проверка целостности кода @Component public class CodeIntegrityChecker { @EventListener public void onApplicationStart(ApplicationReadyEvent event) { validateCodeIntegrity(); } private void validateCodeIntegrity() { // Проверка цифровых подписей validateDigitalSignatures(); // Проверка контрольных сумм validateChecksums(); // Проверка целостности зависимостей validateDependencies(); } private void validateDigitalSignatures() { // Проверка подписей JAR файлов // Проверка подписей DLL/SO файлов } private void validateChecksums() { // Проверка контрольных сумм критических файлов } private void validateDependencies() { // Проверка целостности Maven зависимостей } } ``` #### A09: Security Logging and Monitoring Failures (Сбои логирования и мониторинга безопасности) **Описание:** Недостаточное логирование и мониторинг событий безопасности. **Методы устранения:** ```java // Комплексная система логирования безопасности @Component public class SecurityAuditService { @Autowired private AuditRepository auditRepository; @Autowired private AlertService alertService; public void logSecurityEvent(SecurityEvent event) { // Логирование события AuditLog auditLog = AuditLog.builder() .eventType(event.getType()) .userId(event.getUserId()) .ipAddress(event.getIpAddress()) .userAgent(event.getUserAgent()) .timestamp(LocalDateTime.now()) .details(event.getDetails()) .severity(event.getSeverity()) .build(); auditRepository.save(auditLog); // Отправка алерта при критических событиях if (event.getSeverity() == SecuritySeverity.CRITICAL) { alertService.sendSecurityAlert(event); } // Проверка на подозрительную активность checkForSuspiciousActivity(event); } private void checkForSuspiciousActivity(SecurityEvent event) { // Проверка на множественные неудачные попытки входа if (event.getType() == SecurityEventType.FAILED_LOGIN) { long failedAttempts = auditRepository.countFailedLogins( event.getUserId(), LocalDateTime.now().minusHours(1) ); if (failedAttempts > 10) { alertService.sendBruteForceAlert(event); } } // Проверка на необычные IP адреса if (isUnusualIP(event.getIpAddress())) { alertService.sendUnusualActivityAlert(event); } } private boolean isUnusualIP(String ipAddress) { // Проверка на известные VPN/Proxy сервисы // Проверка на подозрительные географические локации return false; // Упрощенная реализация } } // Система мониторинга безопасности @Component public class SecurityMonitoringService { @Autowired private MetricsService metricsService; @Scheduled(fixedRate = 60000) // Каждую минуту public void monitorSecurityMetrics() { // Мониторинг количества неудачных попыток входа long failedLogins = metricsService.getFailedLoginCount(); if (failedLogins > 100) { alertService.sendHighFailedLoginAlert(failedLogins); } // Мониторинг количества активных сессий long activeSessions = metricsService.getActiveSessionCount(); if (activeSessions > 10000) { alertService.sendHighSessionCountAlert(activeSessions); } // Мониторинг использования ресурсов double cpuUsage = metricsService.getCpuUsage(); if (cpuUsage > 90) { alertService.sendHighCpuUsageAlert(cpuUsage); } } } ``` #### A10: Server-Side Request Forgery (SSRF) (Подделка запросов на стороне сервера) **Описание:** Принуждение сервера к выполнению запросов к внутренним ресурсам. **Методы устранения:** ```java // Защита от SSRF @Service public class SSRFProtectionService { private final Set allowedHosts = Set.of( "api.example.com", "external-service.com" ); private final Set blockedIPs = Set.of( "127.0.0.1", "0.0.0.0", "localhost", "::1" ); public String makeSafeRequest(String url) { // Валидация URL validateUrl(url); // Проверка разрешенных хостов String host = extractHost(url); if (!allowedHosts.contains(host)) { throw new SSRFException("Host not allowed: " + host); } // Проверка на заблокированные IP String ip = resolveIP(host); if (blockedIPs.contains(ip)) { throw new SSRFException("IP address blocked: " + ip); } // Выполнение безопасного запроса return executeSafeRequest(url); } private void validateUrl(String url) { try { URI uri = new URI(url); // Проверка схемы if (!uri.getScheme().equals("https")) { throw new SSRFException("Only HTTPS URLs are allowed"); } // Проверка порта if (uri.getPort() != -1 && uri.getPort() != 443) { throw new SSRFException("Non-standard port not allowed"); } } catch (URISyntaxException e) { throw new SSRFException("Invalid URL format", e); } } private String extractHost(String url) { try { URI uri = new URI(url); return uri.getHost(); } catch (URISyntaxException e) { throw new SSRFException("Invalid URL format", e); } } private String resolveIP(String host) { try { InetAddress address = InetAddress.getByName(host); return address.getHostAddress(); } catch (UnknownHostException e) { throw new SSRFException("Cannot resolve host: " + host, e); } } private String executeSafeRequest(String url) { // Выполнение запроса с ограничениями RestTemplate restTemplate = new RestTemplate(); // Настройка таймаутов HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); factory.setConnectTimeout(5000); factory.setReadTimeout(10000); restTemplate.setRequestFactory(factory); try { ResponseEntity response = restTemplate.getForEntity(url, String.class); return response.getBody(); } catch (Exception e) { throw new SSRFException("Request failed", e); } } } ``` ### Дополнительные уязвимости #### Cross-Site Scripting (XSS) **Методы устранения:** ```java // Защита от XSS @Component public class XSSProtectionService { public String sanitizeInput(String input) { if (input == null) return null; // HTML экранирование return input .replace("&", "&") .replace("<", "<") .replace(">", ">") .replace("\"", """) .replace("'", "'") .replace("/", "/"); } public boolean containsXSS(String input) { // Проверка на подозрительные паттерны String[] xssPatterns = { "", ">") .replace("\"", """) .replace("'", "'"); } } ``` #### Cross-Site Request Forgery (CSRF) **Методы устранения:** ```java // Защита от CSRF @Configuration public class CSRFProtectionConfig { @Bean public CsrfTokenRepository csrfTokenRepository() { CookieCsrfTokenRepository repository = CookieCsrfTokenRepository.withHttpOnlyFalse(); repository.setCookiePath("/"); repository.setCookieName("XSRF-TOKEN"); return repository; } } // Проверка CSRF токена @Component public class CSRFValidationService { public boolean validateCSRFToken(HttpServletRequest request) { String tokenFromRequest = request.getHeader("X-XSRF-TOKEN"); String tokenFromCookie = getCookieValue(request, "XSRF-TOKEN"); if (tokenFromRequest == null || tokenFromCookie == null) { return false; } return tokenFromRequest.equals(tokenFromCookie); } private String getCookieValue(HttpServletRequest request, String cookieName) { Cookie[] cookies = request.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { if (cookie.getName().equals(cookieName)) { return cookie.getValue(); } } } return null; } } ``` --- ## Обфускация и защита кода ### Принципы защиты исходного кода #### 1. Обфускация кода (Code Obfuscation) **Обфускация** — процесс преобразования исходного кода в трудночитаемую форму для защиты интеллектуальной собственности и усложнения реверс-инжиниринга. **Цели обфускации:** - Защита алгоритмов и бизнес-логики - Усложнение реверс-инжиниринга - Защита от кражи интеллектуальной собственности - Предотвращение модификации кода **Методы обфускации:** ```java // Исходный код public class PaymentProcessor { private static final String API_KEY = "sk_live_123456789"; private static final String SECRET_KEY = "secret_abc123"; public PaymentResult processPayment(PaymentRequest request) { if (request.getAmount() > 10000) { return validateHighAmountPayment(request); } return processStandardPayment(request); } private PaymentResult validateHighAmountPayment(PaymentRequest request) { // Сложная логика валидации boolean isValid = performAdvancedValidation(request); if (isValid) { return executePayment(request); } return PaymentResult.failed("Validation failed"); } } // Обфускированный код public class a { private static final String b = "sk_live_123456789"; private static final String c = "secret_abc123"; public d e(f g) { if (g.h() > 10000) { return i(g); } return j(g); } private d i(f g) { boolean h = k(g); if (h) { return l(g); } return d.m("Validation failed"); } } ``` **Rust примеры - Обфускация:** ```rust // Исходный код pub struct PaymentProcessor { api_key: String, secret_key: String, } impl PaymentProcessor { pub fn new(api_key: String, secret_key: String) -> Self { Self { api_key, secret_key } } pub fn process_payment(&self, request: PaymentRequest) -> PaymentResult { if request.amount > 10000 { return self.validate_high_amount_payment(request); } self.process_standard_payment(request) } fn validate_high_amount_payment(&self, request: PaymentRequest) -> PaymentResult { let is_valid = self.perform_advanced_validation(&request); if is_valid { self.execute_payment(request) } else { PaymentResult::failed("Validation failed") } } } // Обфускированный код (с использованием макросов) macro_rules! obfuscate_string { ($s:expr) => { base64::decode($s).unwrap_or_else(|_| $s.as_bytes().to_vec()) }; } pub struct a { b: Vec, c: Vec, } impl a { pub fn d(e: Vec, f: Vec) -> Self { Self { b: e, c: f } } pub fn g(&self, h: i) -> j { if h.k > 10000 { return self.l(h); } self.m(h) } fn l(&self, h: i) -> j { let n = self.o(&h); if n { self.p(h) } else { j::q("Validation failed") } } } ``` **Python примеры - Обфускация:** ```python # Исходный код class PaymentProcessor: def __init__(self, api_key, secret_key): self.api_key = api_key self.secret_key = secret_key def process_payment(self, request): if request.amount > 10000: return self.validate_high_amount_payment(request) return self.process_standard_payment(request) def validate_high_amount_payment(self, request): is_valid = self.perform_advanced_validation(request) if is_valid: return self.execute_payment(request) return PaymentResult.failed("Validation failed") # Обфускированный код import base64 import zlib class a: def __init__(self, b, c): self.b = b self.c = c def d(self, e): if e.f > 10000: return self.g(e) return self.h(e) def g(self, e): i = self.j(e) if i: return self.k(e) return l.m("Validation failed") # Дополнительная обфускация строк def obfuscate_string(s): return base64.b64encode(zlib.compress(s.encode())).decode() # Использование API_KEY = obfuscate_string("sk_live_123456789") SECRET_KEY = obfuscate_string("secret_abc123") ``` **Node.js примеры - Обфускация:** ```typescript // Исходный код class PaymentProcessor { private apiKey: string; private secretKey: string; constructor(apiKey: string, secretKey: string) { this.apiKey = apiKey; this.secretKey = secretKey; } processPayment(request: PaymentRequest): PaymentResult { if (request.amount > 10000) { return this.validateHighAmountPayment(request); } return this.processStandardPayment(request); } private validateHighAmountPayment(request: PaymentRequest): PaymentResult { const isValid = this.performAdvancedValidation(request); if (isValid) { return this.executePayment(request); } return PaymentResult.failed("Validation failed"); } } // Обфускированный код class a { private b: string; private c: string; constructor(d: string, e: string) { this.b = d; this.c = e; } f(g: h): i { if (g.j > 10000) { return this.k(g); } return this.l(g); } private k(g: h): i { const m = this.n(g); if (m) { return this.o(g); } return i.p("Validation failed"); } } // Webpack конфигурация для обфускации module.exports = { mode: 'production', optimization: { minimize: true, minimizer: [ new TerserPlugin({ terserOptions: { mangle: { properties: { regex: /^_/ } }, compress: { drop_console: true, drop_debugger: true, pure_funcs: ['console.log'] } } }) ] } }; ``` #### 2. Минификация (Minification) **Минификация** — процесс удаления ненужных символов из кода без изменения его функциональности. **Методы минификации:** ```javascript // Исходный JavaScript код function calculateTotal(items) { let total = 0; for (let i = 0; i < items.length; i++) { if (items[i].price > 0) { total += items[i].price * items[i].quantity; } } return total; } // Минифицированный код function calculateTotal(items){let total=0;for(let i=0;i0){total+=items[i].price*items[i].quantity}}return total} // CSS минификация /* Исходный CSS */ .header { background-color: #ffffff; padding: 20px; margin-bottom: 10px; } /* Минифицированный CSS */ .header{background-color:#fff;padding:20px;margin-bottom:10px} ``` #### 3. Защита от реверс-инжиниринга **Методы защиты:** ```java // Анти-отладка public class AntiDebugProtection { public static boolean isDebuggerPresent() { try { // Проверка наличия отладчика System.getProperty("java.vm.info"); return System.getProperty("java.vm.info").contains("debug"); } catch (Exception e) { return true; // Предполагаем наличие отладчика при ошибке } } public static void checkDebugger() { if (isDebuggerPresent()) { System.exit(1); // Завершение при обнаружении отладчика } } // Проверка целостности кода public static boolean verifyCodeIntegrity() { try { String expectedHash = "a1b2c3d4e5f6"; String actualHash = calculateClassHash(); return expectedHash.equals(actualHash); } catch (Exception e) { return false; } } private static String calculateClassHash() { // Расчет хеша класса для проверки целостности return "calculated_hash"; } } // Защита от модификации @Component public class CodeProtectionService { @PostConstruct public void initializeProtection() { // Проверка целостности при запуске if (!verifyCodeIntegrity()) { throw new SecurityException("Code integrity check failed"); } // Проверка на отладчик checkDebugger(); // Запуск фоновой проверки startBackgroundProtection(); } @Scheduled(fixedRate = 30000) // Каждые 30 секунд public void backgroundProtection() { if (!verifyCodeIntegrity()) { System.exit(1); } if (isDebuggerPresent()) { System.exit(1); } } } ``` #### 4. Source Maps и их безопасность **Проблемы Source Maps:** ```javascript // webpack.config.js - НЕБЕЗОПАСНО module.exports = { devtool: 'source-map', // Раскрывает весь исходный код // БЕЗОПАСНО - только для разработки devtool: process.env.NODE_ENV === 'development' ? 'source-map' : false, // БЕЗОПАСНО - скрытые source maps devtool: 'hidden-source-map', // БЕЗОПАСНО - только для внутреннего использования devtool: 'nosources-source-map' }; // Безопасная конфигурация module.exports = { mode: 'production', devtool: false, // Отключение source maps в продакшене optimization: { minimize: true, minimizer: [ new TerserPlugin({ terserOptions: { sourceMap: false, // Отключение source maps mangle: true, compress: { drop_console: true, drop_debugger: true } } }) ] }, // Условное включение source maps только для разработки ...(process.env.NODE_ENV === 'development' && { devtool: 'eval-source-map' }) }; ``` #### 5. Защита конфигурационных файлов ```java // Защита конфигурации @Configuration @EnableEncryption public class SecureConfiguration { @Value("${encrypted.database.password}") private String encryptedDbPassword; @Value("${encrypted.api.key}") private String encryptedApiKey; @Bean public DataSource dataSource() { HikariConfig config = new HikariConfig(); config.setJdbcUrl("jdbc:postgresql://localhost:5432/mydb"); config.setUsername("user"); config.setPassword(decrypt(encryptedDbPassword)); // Расшифровка пароля return new HikariDataSource(config); } @Bean public RestTemplate restTemplate() { RestTemplate template = new RestTemplate(); template.getInterceptors().add(new ApiKeyInterceptor(decrypt(encryptedApiKey))); return template; } private String decrypt(String encryptedValue) { // Логика расшифровки return encryptionService.decrypt(encryptedValue); } } // Шифрование конфигурации @Service public class ConfigurationEncryptionService { public String encryptConfiguration(String value) { try { Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); SecretKeySpec keySpec = new SecretKeySpec( getEncryptionKey(), "AES"); cipher.init(Cipher.ENCRYPT_MODE, keySpec); byte[] encrypted = cipher.doFinal(value.getBytes()); return Base64.getEncoder().encodeToString(encrypted); } catch (Exception e) { throw new ConfigurationException("Failed to encrypt configuration", e); } } private byte[] getEncryptionKey() { // Получение ключа шифрования из безопасного хранилища return keyManagementService.getEncryptionKey(); } } ``` #### 6. Защита от анализа трафика ```java // Обфускация сетевого трафика @Service public class NetworkObfuscationService { public String obfuscateRequest(String originalRequest) { // Обфускация параметров запроса String obfuscated = base64Encode(originalRequest); obfuscated = addRandomPadding(obfuscated); obfuscated = xorWithKey(obfuscated, getObfuscationKey()); return obfuscated; } public String deobfuscateResponse(String obfuscatedResponse) { // Деобфускация ответа String deobfuscated = xorWithKey(obfuscatedResponse, getObfuscationKey()); deobfuscated = removeRandomPadding(deobfuscated); deobfuscated = base64Decode(deobfuscated); return deobfuscated; } private String addRandomPadding(String data) { // Добавление случайных данных для усложнения анализа Random random = new Random(); int paddingLength = random.nextInt(100) + 50; StringBuilder padding = new StringBuilder(); for (int i = 0; i < paddingLength; i++) { padding.append((char) (random.nextInt(26) + 'a')); } return padding.toString() + data + padding.toString(); } private String removeRandomPadding(String data) { // Удаление случайных данных // Логика удаления padding return data.substring(50, data.length() - 50); } } ``` ### Инструменты обфускации #### Java - **ProGuard** - обфускация и минификация - **Allatori** - коммерческая обфускация - **DashO** - профессиональная обфускация #### JavaScript/TypeScript - **Terser** - минификация и обфускация - **UglifyJS** - минификация JavaScript - **Webpack** - бандлинг и обфускация #### Python - **PyArmor** - обфускация Python кода - **Nuitka** - компиляция в нативный код - **cx_Freeze** - создание исполняемых файлов #### Rust - **rustc** с флагами оптимизации - **strip** - удаление отладочной информации - **upx** - сжатие исполняемых файлов --- ## Security by Design ### Принципы Security by Design #### 1. Secure by Default - Безопасные настройки по умолчанию - Минимальные права доступа - Защита от случайных ошибок #### 2. Fail Secure - При отказе система переходит в безопасное состояние - Блокировка доступа при ошибках - Логирование всех событий безопасности #### 3. Security as Code - Безопасность как часть кода - Автоматизированные проверки безопасности - Версионирование политик безопасности ### Моделирование угроз #### STRIDE Model - **S**poofing (Подмена) - **T**ampering (Изменение) - **R**epudiation (Отказ) - **I**nformation Disclosure (Раскрытие информации) - **D**enial of Service (Отказ в обслуживании) - **E**levation of Privilege (Повышение привилегий) #### Пример Threat Model: ```yaml # threat-model.yml application: "E-commerce Platform" components: - name: "User Authentication" threats: - type: "Spoofing" description: "User impersonation" mitigations: - "Strong password policy" - "Multi-factor authentication" - name: "Payment Processing" threats: - type: "Tampering" description: "Payment data modification" mitigations: - "Data encryption" - "Digital signatures" ``` ### Архитектура безопасности #### 1. Zero Trust Architecture **Принцип:** "Никогда не доверяй, всегда проверяй" ```java @Component public class ZeroTrustFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; // проверяем каждую аутентификацию if (!isAuthenticated(httpRequest)) { throw new AuthenticationException("Authentication required"); } // проверяем каждую авторизацию if (!isAuthorized(httpRequest)) { throw new AuthorizationException("Access denied"); } // проверяем устройство if (!isDeviceTrusted(httpRequest)) { throw new SecurityException("Untrusted device"); } chain.doFilter(request, response); } } ``` #### 2. Microsegmentation **Принцип:** Разделение сети на мелкие сегменты ```yaml # network-policy.yml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: order-service-policy spec: podSelector: matchLabels: app: order-service policyTypes: - Ingress - Egress ingress: - from: - podSelector: matchLabels: app: api-gateway ports: - protocol: TCP port: 8080 egress: - to: - podSelector: matchLabels: app: payment-service ports: - protocol: TCP port: 8080 ``` --- ## Аутентификация и авторизация ### Аутентификация #### 1. Password-based Authentication ```java @Service public class AuthenticationService { @Autowired private PasswordEncoder passwordEncoder; @Autowired private UserRepository userRepository; public AuthenticationResult authenticate(String username, String password) { User user = userRepository.findByUsername(username); if (user == null) { return AuthenticationResult.failure("User not found"); } if (!passwordEncoder.matches(password, user.getPasswordHash())) { return AuthenticationResult.failure("Invalid password"); } if (!user.isActive()) { return AuthenticationResult.failure("User account is disabled"); } return AuthenticationResult.success(user); } } ``` #### 2. Multi-Factor Authentication (MFA) ```java @Service public class MFAService { @Autowired private TOTPGenerator totpGenerator; @Autowired private SMSService smsService; public void enableMFA(Long userId, String phoneNumber) { String secret = totpGenerator.generateSecret(); userRepository.updateMFASecret(userId, secret); userRepository.updatePhoneNumber(userId, phoneNumber); } public boolean verifyMFA(Long userId, String code) { User user = userRepository.findById(userId); String secret = user.getMFASecret(); return totpGenerator.verifyCode(secret, code); } public void sendSMS(Long userId, String code) { User user = userRepository.findById(userId); smsService.sendSMS(user.getPhoneNumber(), "Your verification code: " + code); } } ``` #### 3. OAuth 2.0 / OpenID Connect ```java @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .oauth2Login(oauth2 -> oauth2 .userInfoEndpoint(userInfo -> userInfo .userService(customOAuth2UserService) ) ) .authorizeHttpRequests(authz -> authz .requestMatchers("/public/**").permitAll() .requestMatchers("/admin/**").hasRole("ADMIN") .anyRequest().authenticated() ); return http.build(); } } ``` ### Авторизация #### 1. Role-Based Access Control (RBAC) ```java @Entity public class User { @Id private Long id; @ManyToMany(fetch = FetchType.EAGER) @JoinTable( name = "user_roles", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id") ) private Set roles = new HashSet<>(); } @Entity public class Role { @Id private Long id; private String name; @ManyToMany(fetch = FetchType.EAGER) @JoinTable( name = "role_permissions", joinColumns = @JoinColumn(name = "role_id"), inverseJoinColumns = @JoinColumn(name = "permission_id") ) private Set permissions = new HashSet<>(); } ``` #### 2. Attribute-Based Access Control (ABAC) ```java @Component public class ABACPolicyEngine { public boolean evaluate(Policy policy, AccessRequest request) { // проверяем субъект if (!policy.getSubject().matches(request.getSubject())) { return false; } // проверяем ресурс if (!policy.getResource().matches(request.getResource())) { return false; } // проверяем действие if (!policy.getAction().matches(request.getAction())) { return false; } // проверяем контекст if (!policy.getContext().matches(request.getContext())) { return false; } return true; } } // Пример политики Policy policy = Policy.builder() .subject("role:manager") .resource("department:finance") .action("read") .context("time:business_hours") .build(); ``` #### 3. JWT Tokens ```java @Service public class JWTService { private final String secretKey = "mySecretKey"; private final int jwtExpiration = 86400000; // 24 hours public String generateToken(UserDetails userDetails) { Map claims = new HashMap<>(); claims.put("roles", userDetails.getAuthorities()); claims.put("userId", userDetails.getUsername()); return createToken(claims, userDetails.getUsername()); } private String createToken(Map claims, String subject) { return Jwts.builder() .setClaims(claims) .setSubject(subject) .setIssuedAt(new Date(System.currentTimeMillis())) .setExpiration(new Date(System.currentTimeMillis() + jwtExpiration)) .signWith(SignatureAlgorithm.HS512, secretKey) .compact(); } public Boolean validateToken(String token, UserDetails userDetails) { final String username = extractUsername(token); return (username.equals(userDetails.getUsername()) && !isTokenExpired(token)); } } ``` --- ## Шифрование ### Типы шифрования #### 1. Symmetric Encryption **Технический пример - Advanced Encryption Service:** ```java @Service public class SymmetricEncryptionService { private final SecretKey secretKey; private final String algorithm = "AES/GCM/NoPadding"; private final int GCM_IV_LENGTH = 12; private final int GCM_TAG_LENGTH = 16; @Value("${encryption.key}") private String base64Key; public SymmetricEncryptionService() throws Exception { // Генерируем ключ из конфигурации или создаем новый if (base64Key != null && !base64Key.isEmpty()) { byte[] keyBytes = Base64.getDecoder().decode(base64Key); this.secretKey = new SecretKeySpec(keyBytes, "AES"); } else { KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); keyGenerator.init(256); this.secretKey = keyGenerator.generateKey(); } } public EncryptedData encrypt(String plainText) throws Exception { if (plainText == null || plainText.isEmpty()) { throw new IllegalArgumentException("Plain text cannot be null or empty"); } // Генерируем случайный IV byte[] iv = new byte[GCM_IV_LENGTH]; SecureRandom.getInstanceStrong().nextBytes(iv); // Настраиваем шифр Cipher cipher = Cipher.getInstance(algorithm); GCMParameterSpec parameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv); cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec); // Шифруем данные byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8)); // Объединяем IV и зашифрованные данные byte[] encryptedWithIv = new byte[GCM_IV_LENGTH + encryptedBytes.length]; System.arraycopy(iv, 0, encryptedWithIv, 0, GCM_IV_LENGTH); System.arraycopy(encryptedBytes, 0, encryptedWithIv, GCM_IV_LENGTH, encryptedBytes.length); return new EncryptedData( Base64.getEncoder().encodeToString(encryptedWithIv), System.currentTimeMillis() ); } public String decrypt(EncryptedData encryptedData) throws Exception { if (encryptedData == null || encryptedData.getData() == null) { throw new IllegalArgumentException("Encrypted data cannot be null"); } byte[] encryptedWithIv = Base64.getDecoder().decode(encryptedData.getData()); if (encryptedWithIv.length < GCM_IV_LENGTH) { throw new IllegalArgumentException("Invalid encrypted data length"); } // Извлекаем IV byte[] iv = new byte[GCM_IV_LENGTH]; System.arraycopy(encryptedWithIv, 0, iv, 0, GCM_IV_LENGTH); // Извлекаем зашифрованные данные byte[] encryptedBytes = new byte[encryptedWithIv.length - GCM_IV_LENGTH]; System.arraycopy(encryptedWithIv, GCM_IV_LENGTH, encryptedBytes, 0, encryptedBytes.length); // Настраиваем шифр для расшифровки Cipher cipher = Cipher.getInstance(algorithm); GCMParameterSpec parameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv); cipher.init(Cipher.DECRYPT_MODE, secretKey, parameterSpec); // Расшифровываем данные byte[] decryptedBytes = cipher.doFinal(encryptedBytes); return new String(decryptedBytes, StandardCharsets.UTF_8); } public String encryptSensitiveField(String value) throws Exception { if (value == null) { return null; } return encrypt(value).getData(); } public String decryptSensitiveField(String encryptedValue) throws Exception { if (encryptedValue == null) { return null; } return decrypt(new EncryptedData(encryptedValue, 0L)); } } // Encrypted Data Wrapper public class EncryptedData { private final String data; private final long timestamp; public EncryptedData(String data, long timestamp) { this.data = data; this.timestamp = timestamp; } public String getData() { return data; } public long getTimestamp() { return timestamp; } } // Field-level Encryption @Entity public class User { @Id private Long id; private String name; @Convert(converter = EncryptedStringConverter.class) private String email; @Convert(converter = EncryptedStringConverter.class) private String phoneNumber; @Convert(converter = EncryptedStringConverter.class) private String ssn; // Getters and setters } // Custom Converter for JPA @Converter public class EncryptedStringConverter implements AttributeConverter { @Autowired private SymmetricEncryptionService encryptionService; @Override public String convertToDatabaseColumn(String attribute) { if (attribute == null) { return null; } try { return encryptionService.encryptSensitiveField(attribute); } catch (Exception e) { throw new RuntimeException("Failed to encrypt field", e); } } @Override public String convertToEntityAttribute(String dbData) { if (dbData == null) { return null; } try { return encryptionService.decryptSensitiveField(dbData); } catch (Exception e) { throw new RuntimeException("Failed to decrypt field", e); } } } // Advanced Hashing Service @Service public class HashingService { private final int BCRYPT_ROUNDS = 12; private final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA256"; private final int PBKDF2_ITERATIONS = 100000; private final int PBKDF2_KEY_LENGTH = 256; public String hashPassword(String password) { if (password == null || password.isEmpty()) { throw new IllegalArgumentException("Password cannot be null or empty"); } return BCrypt.hashpw(password, BCrypt.gensalt(BCRYPT_ROUNDS)); } public boolean verifyPassword(String password, String hash) { if (password == null || hash == null) { return false; } return BCrypt.checkpw(password, hash); } public String generatePBKDF2Hash(String password, String salt) throws Exception { if (password == null || salt == null) { throw new IllegalArgumentException("Password and salt cannot be null"); } PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt.getBytes(), PBKDF2_ITERATIONS, PBKDF2_KEY_LENGTH); SecretKeyFactory skf = SecretKeyFactory.getInstance(PBKDF2_ALGORITHM); byte[] hash = skf.generateSecret(spec).getEncoded(); return Base64.getEncoder().encodeToString(hash); } public String generateSalt() { SecureRandom random = new SecureRandom(); byte[] salt = new byte[16]; random.nextBytes(salt); return Base64.getEncoder().encodeToString(salt); } public String generateHash(String input, String algorithm) throws Exception { if (input == null) { throw new IllegalArgumentException("Input cannot be null"); } MessageDigest digest = MessageDigest.getInstance(algorithm); byte[] hash = digest.digest(input.getBytes(StandardCharsets.UTF_8)); return Base64.getEncoder().encodeToString(hash); } public String generateHMAC(String data, String key, String algorithm) throws Exception { if (data == null || key == null) { throw new IllegalArgumentException("Data and key cannot be null"); } Mac mac = Mac.getInstance(algorithm); SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm); mac.init(secretKeySpec); byte[] hmacBytes = mac.doFinal(data.getBytes(StandardCharsets.UTF_8)); return Base64.getEncoder().encodeToString(hmacBytes); } } // Key Management Service @Service public class KeyManagementService { @Value("${encryption.key.rotation.enabled:true}") private boolean keyRotationEnabled; @Value("${encryption.key.rotation.interval:30}") private int rotationIntervalDays; private final Map keyVersions = new ConcurrentHashMap<>(); private final AtomicInteger currentKeyVersion = new AtomicInteger(1); @PostConstruct public void initializeKeys() throws Exception { // Создаем начальный ключ SecretKey initialKey = generateAESKey(); keyVersions.put("v1", initialKey); if (keyRotationEnabled) { scheduleKeyRotation(); } } @Scheduled(cron = "0 0 2 * * ?") // Каждый день в 2:00 public void rotateKeys() throws Exception { if (!keyRotationEnabled) { return; } log.info("Starting key rotation process"); // Генерируем новый ключ int newVersion = currentKeyVersion.incrementAndGet(); SecretKey newKey = generateAESKey(); keyVersions.put("v" + newVersion, newKey); // Перешифровываем критически важные данные reencryptCriticalData(newKey); // Удаляем старые ключи (оставляем последние 3 версии) cleanupOldKeys(); log.info("Key rotation completed. New version: v{}", newVersion); } public SecretKey getCurrentKey() { return keyVersions.get("v" + currentKeyVersion.get()); } public SecretKey getKeyByVersion(int version) { return keyVersions.get("v" + version); } private SecretKey generateAESKey() throws Exception { KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); keyGenerator.init(256); return keyGenerator.generateKey(); } private void reencryptCriticalData(SecretKey newKey) { // Логика перешифровки критически важных данных // Это может включать перешифровку данных в БД } private void cleanupOldKeys() { int currentVersion = currentKeyVersion.get(); int keepVersions = 3; for (int i = 1; i <= currentVersion - keepVersions; i++) { keyVersions.remove("v" + i); } } private void scheduleKeyRotation() { // Дополнительная логика планирования ротации ключей } } ``` #### 2. Asymmetric Encryption ```java @Service public class AsymmetricEncryptionService { private final KeyPair keyPair; public AsymmetricEncryptionService() throws Exception { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); keyPairGenerator.initialize(2048); this.keyPair = keyPairGenerator.generateKeyPair(); } public String encrypt(String plainText, PublicKey publicKey) throws Exception { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] encryptedBytes = cipher.doFinal(plainText.getBytes()); return Base64.getEncoder().encodeToString(encryptedBytes); } public String decrypt(String encryptedText, PrivateKey privateKey) throws Exception { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedText)); return new String(decryptedBytes); } } ``` #### 3. Hashing ```java @Service public class HashingService { public String hashPassword(String password) { return BCrypt.hashpw(password, BCrypt.gensalt(12)); } public boolean verifyPassword(String password, String hash) { return BCrypt.checkpw(password, hash); } public String generateHash(String input) throws Exception { MessageDigest digest = MessageDigest.getInstance("SHA-256"); byte[] hash = digest.digest(input.getBytes()); return Base64.getEncoder().encodeToString(hash); } } ``` ### Управление ключами #### 1. Key Rotation ```java @Service public class KeyRotationService { @Scheduled(cron = "0 0 0 1 * ?") // каждый месяц public void rotateKeys() { // генерируем новые ключи KeyPair newKeyPair = generateNewKeyPair(); // обновляем ключи в системе updateSystemKeys(newKeyPair); // перешифровываем существующие данные reencryptExistingData(newKeyPair); // удаляем старые ключи deleteOldKeys(); } } ``` #### 2. Hardware Security Module (HSM) ```java @Service public class HSMService { private final HSMClient hsmClient; public String encryptWithHSM(String data) { return hsmClient.encrypt(data); } public String decryptWithHSM(String encryptedData) { return hsmClient.decrypt(encryptedData); } public String signWithHSM(String data) { return hsmClient.sign(data); } } ``` --- ## Безопасность API ### Лучшие практики безопасности API #### 1. Input Validation ```java @RestController @Validated public class UserController { @PostMapping("/users") public ResponseEntity createUser(@Valid @RequestBody CreateUserRequest request) { // валидация выполняется автоматически через @Valid User user = userService.createUser(request); return ResponseEntity.ok(user); } } public class CreateUserRequest { @NotBlank(message = "Username is required") @Size(min = 3, max = 50, message = "Username must be between 3 and 50 characters") private String username; @NotBlank(message = "Email is required") @Email(message = "Email must be valid") private String email; @NotBlank(message = "Password is required") @Size(min = 8, message = "Password must be at least 8 characters") @Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,}$", message = "Password must contain at least one uppercase letter, one lowercase letter, one number and one special character") private String password; } ``` #### 2. Rate Limiting ```java @Component public class RateLimitingFilter implements Filter { private final Map rateLimiters = new ConcurrentHashMap<>(); @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; String clientId = getClientId(httpRequest); RateLimiter rateLimiter = rateLimiters.computeIfAbsent(clientId, k -> RateLimiter.create(10.0)); // 10 запросов в секунду if (!rateLimiter.tryAcquire()) { HttpServletResponse httpResponse = (HttpServletResponse) response; httpResponse.setStatus(429); // Too Many Requests httpResponse.getWriter().write("Rate limit exceeded"); return; } chain.doFilter(request, response); } } ``` #### 3. API Versioning ```java @RestController @RequestMapping("/api/v1/users") public class UserControllerV1 { @GetMapping("/{id}") public UserV1 getUser(@PathVariable Long id) { return userService.getUserV1(id); } } @RestController @RequestMapping("/api/v2/users") public class UserControllerV2 { @GetMapping("/{id}") public UserV2 getUser(@PathVariable Long id) { return userService.getUserV2(id); } } ``` ### Безопасность API Gateway ```yaml # api-gateway-security.yml apiVersion: networking.istio.io/v1alpha3 kind: AuthorizationPolicy metadata: name: api-gateway-policy spec: selector: matchLabels: app: api-gateway rules: - from: - source: principals: ["cluster.local/ns/default/sa/api-gateway"] to: - operation: methods: ["GET", "POST"] paths: ["/api/v1/*"] - from: - source: principals: ["cluster.local/ns/default/sa/admin-service"] to: - operation: methods: ["*"] paths: ["/admin/*"] ``` --- ## Безопасность данных ### Классификация данных #### 1. Data Sensitivity Levels - **Public** — общедоступные данные - **Internal** — внутренние данные - **Confidential** — конфиденциальные данные - **Restricted** — ограниченные данные ```java @Entity public class User { @Id private Long id; @Column(name = "username") @DataClassification(level = DataClassification.Level.INTERNAL) private String username; @Column(name = "email") @DataClassification(level = DataClassification.Level.CONFIDENTIAL) private String email; @Column(name = "ssn") @DataClassification(level = DataClassification.Level.RESTRICTED) @Encrypted private String ssn; } ``` #### 2. Data Masking ```java @Service public class DataMaskingService { public User maskUserData(User user, UserRole requesterRole) { User maskedUser = new User(); maskedUser.setId(user.getId()); switch (requesterRole) { case ADMIN: // админы видят все данные maskedUser.setEmail(user.getEmail()); maskedUser.setSsn(user.getSsn()); break; case MANAGER: // менеджеры видят частично замаскированные данные maskedUser.setEmail(maskEmail(user.getEmail())); maskedUser.setSsn(maskSSN(user.getSsn())); break; case USER: // обычные пользователи видят только базовую информацию maskedUser.setEmail(maskEmail(user.getEmail())); maskedUser.setSsn("***-**-****"); break; } return maskedUser; } private String maskEmail(String email) { String[] parts = email.split("@"); String username = parts[0]; String domain = parts[1]; if (username.length() <= 2) { return "*@" + domain; } return username.substring(0, 2) + "*".repeat(username.length() - 2) + "@" + domain; } private String maskSSN(String ssn) { return "***-**-" + ssn.substring(ssn.length() - 4); } } ``` ### Шифрование данных #### 1. Encryption at Rest ```java @Entity public class PaymentCard { @Id private Long id; @Column(name = "card_number") @Convert(converter = EncryptedStringConverter.class) private String cardNumber; @Column(name = "cvv") @Convert(converter = EncryptedStringConverter.class) private String cvv; } @Converter public class EncryptedStringConverter implements AttributeConverter { @Autowired private EncryptionService encryptionService; @Override public String convertToDatabaseColumn(String attribute) { return encryptionService.encrypt(attribute); } @Override public String convertToEntityAttribute(String dbData) { return encryptionService.decrypt(dbData); } } ``` #### 2. Encryption in Transit ```java @Configuration public class SSLConfig { @Bean public RestTemplate restTemplate() throws Exception { SSLContext sslContext = SSLContextBuilder.create() .loadTrustMaterial(null, (certificate, authType) -> true) .build(); HttpClient httpClient = HttpClients.custom() .setSSLContext(sslContext) .build(); HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient); return new RestTemplate(factory); } } ``` --- ## Соответствие требованиям ### GDPR (Общий регламент по защите данных) #### 1. Data Subject Rights ```java @Service public class GDPRService { public void handleDataSubjectRequest(DataSubjectRequest request) { switch (request.getType()) { case ACCESS: provideDataAccess(request.getSubjectId()); break; case RECTIFICATION: rectifyData(request.getSubjectId(), request.getData()); break; case ERASURE: eraseData(request.getSubjectId()); break; case PORTABILITY: provideDataPortability(request.getSubjectId()); break; } } private void eraseData(Long subjectId) { // удаляем персональные данные userRepository.deletePersonalData(subjectId); // логируем удаление auditService.logDataErasure(subjectId); // уведомляем заинтересованные системы notificationService.notifyDataErasure(subjectId); } } ``` #### 2. Consent Management ```java @Entity public class Consent { @Id private Long id; private Long userId; private String purpose; private ConsentStatus status; private LocalDateTime givenAt; private LocalDateTime withdrawnAt; public boolean isValid() { return status == ConsentStatus.GIVEN && withdrawnAt == null; } } @Service public class ConsentService { public void giveConsent(Long userId, String purpose) { Consent consent = new Consent(); consent.setUserId(userId); consent.setPurpose(purpose); consent.setStatus(ConsentStatus.GIVEN); consent.setGivenAt(LocalDateTime.now()); consentRepository.save(consent); } public void withdrawConsent(Long userId, String purpose) { Consent consent = consentRepository.findByUserIdAndPurpose(userId, purpose); if (consent != null) { consent.setStatus(ConsentStatus.WITHDRAWN); consent.setWithdrawnAt(LocalDateTime.now()); consentRepository.save(consent); } } } ``` ### PCI DSS (Стандарт безопасности данных индустрии платежных карт) #### 1. Card Data Protection ```java @Service public class PCIService { public String tokenizeCard(String cardNumber) { // генерируем токен вместо хранения номера карты String token = UUID.randomUUID().toString(); // сохраняем токен в безопасном хранилище secureStorage.storeToken(token, cardNumber); return token; } public String detokenizeCard(String token) { // получаем номер карты по токену return secureStorage.getCardByToken(token); } public boolean validateCard(String cardNumber) { // проверяем номер карты по алгоритму Луна return luhnAlgorithm.validate(cardNumber); } } ``` #### 2. Secure Payment Processing ```java @Service public class PaymentService { @Transactional public PaymentResult processPayment(PaymentRequest request) { // валидируем данные карты if (!validateCardData(request.getCardData())) { return PaymentResult.failure("Invalid card data"); } // токенизируем данные карты String token = tokenizeCard(request.getCardData().getNumber()); // обрабатываем платеж PaymentResult result = paymentProcessor.processPayment(request); // логируем транзакцию auditService.logPaymentTransaction(request, result); return result; } } ``` ### SOX (Закон Сарбейнса-Оксли) #### 1. Financial Data Controls ```java @Service public class FinancialControlService { public void validateFinancialTransaction(FinancialTransaction transaction) { // проверяем авторизацию if (!isAuthorized(transaction.getAmount())) { throw new AuthorizationException("Transaction amount exceeds authorization limit"); } // проверяем дублирование if (isDuplicateTransaction(transaction)) { throw new DuplicateTransactionException("Duplicate transaction detected"); } // проверяем целостность данных if (!validateDataIntegrity(transaction)) { throw new DataIntegrityException("Data integrity check failed"); } } public void auditFinancialData() { // аудит финансовых данных List transactions = getTransactionsForAudit(); for (FinancialTransaction transaction : transactions) { validateTransaction(transaction); logAuditTrail(transaction); } } } ``` --- ## Практические задания ### Задание 1: Security Implementation 1. Реализуйте аутентификацию с JWT 2. Настройте авторизацию с RBAC 3. Добавьте валидацию входных данных ### Задание 2: Data Protection 1. Реализуйте шифрование данных 2. Настройте маскирование данных 3. Добавьте аудит доступа к данным ### Задание 3: Compliance 1. Реализуйте GDPR compliance 2. Настройте PCI DSS для платежей 3. Добавьте SOX controls --- ## Дополнительные ресурсы ### Стандарты и фреймворки - **OWASP** — Open Web Application Security Project - **NIST** — National Institute of Standards and Technology - **ISO 27001** — Information Security Management - **SOC 2** — Service Organization Control ### Инструменты - **Security Scanning**: OWASP ZAP, Burp Suite, Nessus - **Code Analysis**: SonarQube, Checkmarx, Veracode - **Secrets Management**: HashiCorp Vault, AWS Secrets Manager - **Identity Management**: Keycloak, Auth0, Okta --- ## Контрольные вопросы 1. Что такое CIA Triad и как он применяется? 2. Какие принципы Security by Design вы знаете? 3. Как работает OAuth 2.0 и OpenID Connect? 4. Какие типы шифрования существуют? 5. Как обеспечить безопасность API? 6. Что такое GDPR и как его соблюдать? 7. Какие требования PCI DSS вы знаете? 8. Как реализовать Zero Trust Architecture?