Files
Alexander Abakumov 15e744da49 Initial commit: Complete Software Architecture course with 11 modules
- Added comprehensive course structure with 11 modules
- Included theoretical content, practical examples, and tasks
- Multi-language code examples (Java, Rust, Node.js, Python)
- Detailed analysis of architectural approaches and trade-offs
- Complete caching strategies documentation
- Architecture examples from real-world systems (Twitter, Netflix, Uber)
- Structured navigation and learning path
- Ready for educational use
2025-09-09 22:08:07 +03:00

129 KiB
Raw Permalink Blame History

Модуль 6: Безопасность и соответствие требованиям

Содержание модуля

  1. Основы безопасности
  2. Уязвимости и межсервисное взаимодействие
  3. Полный каталог уязвимостей информационной безопасности
  4. Обфускация и защита кода
  5. Security by Design
  6. Аутентификация и авторизация
  7. Шифрование
  8. Безопасность 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:

@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<User> 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<String, Object> claims = new HashMap<>();
        claims.put("roles", userDetails.getAuthorities());
        claims.put("username", userDetails.getUsername());
        
        return createToken(claims, userDetails.getUsername());
    }
    
    private String createToken(Map<String, Object> 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> T getClaimFromToken(String token, Function<Claims, T> 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:

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<void> {
    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<String, RateLimiter> 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
// Плохо: слабое шифрование
@Value("${app.encryption.key:123456}")
private String encryptionKey;

// Хорошо: сильное шифрование
@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder(12);
}
A03: Injection
// Плохо: 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
// Плохо: небезопасный дизайн
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
# Плохо: небезопасная конфигурация
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:

@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<String> 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<String> permissions;
    private Date issuedAt;
    private Date expiresAt;
}

Rust примеры - TVM с Actix Web:

// 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<String>,
    permissions: Vec<String>,
    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<String>,
}

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<ServiceInfo, String> {
        // Декодирование токена
        let token_data = decode::<ServiceClaims>(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<HttpResponse, Error> {
    // Извлечение токена из заголовка
    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<ServiceInfo>,
) -> Result<HttpResponse, Error> {
    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:

# 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:

// 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 неправильная конфигурация

Методы устранения:

// Правильная реализация контроля доступа
@RestController
@RequestMapping("/api/users")
public class UserController {
    
    @GetMapping("/{userId}")
    @PreAuthorize("hasRole('USER') and #userId == authentication.principal.id")
    public ResponseEntity<User> getUser(@PathVariable Long userId) {
        // Проверка прав доступа встроена в аннотацию
        return ResponseEntity.ok(userService.findById(userId));
    }
    
    @GetMapping("/admin")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<List<User>> 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
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<String>,
}

// Middleware для проверки доступа
pub async fn access_control_middleware(
    req: HttpRequest,
    next: actix_web::middleware::Next,
) -> Result<HttpResponse, Error> {
    // Извлечение токена
    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<String, Error> {
    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<AccessToken, Error> {
    // Здесь должна быть реальная валидация 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)
  • Хранение паролей в открытом виде

Методы устранения:

// Правильное шифрование данных
@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

Методы устранения:

// Защита от SQL Injection
@Repository
public class UserRepository {
    
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    // НЕПРАВИЛЬНО - уязвимо к SQL Injection
    public List<User> findByUsernameUnsafe(String username) {
        String sql = "SELECT * FROM users WHERE username = '" + username + "'";
        return jdbcTemplate.query(sql, new UserRowMapper());
    }
    
    // ПРАВИЛЬНО - использование параметризованных запросов
    public List<User> 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<User> findByUsername(@Param("username") String username);
}

// Защита от NoSQL Injection
@Service
public class UserService {
    
    @Autowired
    private MongoTemplate mongoTemplate;
    
    // НЕПРАВИЛЬНО - уязвимо к NoSQL Injection
    public List<User> findByUsernameUnsafe(String username) {
        Query query = new Query();
        query.addCriteria(Criteria.where("username").is(username));
        return mongoTemplate.find(query, User.class);
    }
    
    // ПРАВИЛЬНО - валидация и санитизация ввода
    public List<User> 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<String> 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"
  • Недостаточная изоляция компонентов

Методы устранения:

// Безопасный дизайн архитектуры
@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
  • Отсутствие заголовков безопасности

Методы устранения:

// Безопасная конфигурация
@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> securityHeadersFilter() {
        FilterRegistrationBean<SecurityHeadersFilter> 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 (Уязвимые и устаревшие компоненты)

Описание: Использование компонентов с известными уязвимостями.

Методы устранения:

// Автоматическая проверка уязвимостей
@Component
public class VulnerabilityScanner {
    
    @Scheduled(cron = "0 0 2 * * ?") // Каждый день в 2:00
    public void scanForVulnerabilities() {
        scanDependencies();
        scanSystemComponents();
        generateReport();
    }
    
    private void scanDependencies() {
        // Сканирование Maven зависимостей
        List<Dependency> dependencies = getMavenDependencies();
        
        for (Dependency dependency : dependencies) {
            List<Vulnerability> 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<DependencyUpdate> updates = findAvailableUpdates();
        
        for (DependencyUpdate update : updates) {
            if (update.isSecurityUpdate()) {
                notifySecurityTeam(update);
            }
        }
    }
}

A07: Identification and Authentication Failures (Сбои идентификации и аутентификации)

Описание: Неправильная реализация аутентификации и идентификации.

Методы устранения:

// Безопасная аутентификация
@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<String, String> 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 (Сбои целостности ПО и данных)

Описание: Недостаточная проверка целостности данных и кода.

Методы устранения:

// Проверка целостности данных
@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 (Сбои логирования и мониторинга безопасности)

Описание: Недостаточное логирование и мониторинг событий безопасности.

Методы устранения:

// Комплексная система логирования безопасности
@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) (Подделка запросов на стороне сервера)

Описание: Принуждение сервера к выполнению запросов к внутренним ресурсам.

Методы устранения:

// Защита от SSRF
@Service
public class SSRFProtectionService {
    
    private final Set<String> allowedHosts = Set.of(
        "api.example.com", "external-service.com"
    );
    
    private final Set<String> 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<String> response = restTemplate.getForEntity(url, String.class);
            return response.getBody();
        } catch (Exception e) {
            throw new SSRFException("Request failed", e);
        }
    }
}

Дополнительные уязвимости

Cross-Site Scripting (XSS)

Методы устранения:

// Защита от XSS
@Component
public class XSSProtectionService {
    
    public String sanitizeInput(String input) {
        if (input == null) return null;
        
        // HTML экранирование
        return input
            .replace("&", "&amp;")
            .replace("<", "&lt;")
            .replace(">", "&gt;")
            .replace("\"", "&quot;")
            .replace("'", "&#x27;")
            .replace("/", "&#x2F;");
    }
    
    public boolean containsXSS(String input) {
        // Проверка на подозрительные паттерны
        String[] xssPatterns = {
            "<script", "javascript:", "onload=", "onerror=", "onclick="
        };
        
        String lowerInput = input.toLowerCase();
        for (String pattern : xssPatterns) {
            if (lowerInput.contains(pattern)) {
                return true;
            }
        }
        
        return false;
    }
}

// Фильтр для защиты от XSS
@Component
public class XSSFilter implements Filter {
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        
        XSSRequestWrapper wrappedRequest = new XSSRequestWrapper((HttpServletRequest) request);
        chain.doFilter(wrappedRequest, response);
    }
}

public class XSSRequestWrapper extends HttpServletRequestWrapper {
    
    public XSSRequestWrapper(HttpServletRequest request) {
        super(request);
    }
    
    @Override
    public String getParameter(String parameter) {
        String value = super.getParameter(parameter);
        return sanitizeInput(value);
    }
    
    @Override
    public String[] getParameterValues(String parameter) {
        String[] values = super.getParameterValues(parameter);
        if (values != null) {
            for (int i = 0; i < values.length; i++) {
                values[i] = sanitizeInput(values[i]);
            }
        }
        return values;
    }
    
    private String sanitizeInput(String input) {
        if (input == null) return null;
        
        return input
            .replace("&", "&amp;")
            .replace("<", "&lt;")
            .replace(">", "&gt;")
            .replace("\"", "&quot;")
            .replace("'", "&#x27;");
    }
}

Cross-Site Request Forgery (CSRF)

Методы устранения:

// Защита от 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)

Обфускация — процесс преобразования исходного кода в трудночитаемую форму для защиты интеллектуальной собственности и усложнения реверс-инжиниринга.

Цели обфускации:

  • Защита алгоритмов и бизнес-логики
  • Усложнение реверс-инжиниринга
  • Защита от кражи интеллектуальной собственности
  • Предотвращение модификации кода

Методы обфускации:

// Исходный код
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 примеры - Обфускация:

// Исходный код
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<u8>,
    c: Vec<u8>,
}

impl a {
    pub fn d(e: Vec<u8>, f: Vec<u8>) -> 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 примеры - Обфускация:

# Исходный код
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 примеры - Обфускация:

// Исходный код
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 код
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;i<items.length;i++){if(items[i].price>0){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. Защита от реверс-инжиниринга

Методы защиты:

// Анти-отладка
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:

// 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. Защита конфигурационных файлов

// Защита конфигурации
@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. Защита от анализа трафика

// Обфускация сетевого трафика
@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

  • Spoofing (Подмена)
  • Tampering (Изменение)
  • Repudiation (Отказ)
  • Information Disclosure (Раскрытие информации)
  • Denial of Service (Отказ в обслуживании)
  • Elevation of Privilege (Повышение привилегий)

Пример Threat Model:

# 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

Принцип: "Никогда не доверяй, всегда проверяй"

@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

Принцип: Разделение сети на мелкие сегменты

# 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

@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)

@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

@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)

@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<Role> 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<Permission> permissions = new HashSet<>();
}

2. Attribute-Based Access Control (ABAC)

@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

@Service
public class JWTService {
    private final String secretKey = "mySecretKey";
    private final int jwtExpiration = 86400000; // 24 hours
    
    public String generateToken(UserDetails userDetails) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("roles", userDetails.getAuthorities());
        claims.put("userId", userDetails.getUsername());
        
        return createToken(claims, userDetails.getUsername());
    }
    
    private String createToken(Map<String, Object> 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:

@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<String, String> {
    
    @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<String, SecretKey> 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

@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

@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

@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)

@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

@RestController
@Validated
public class UserController {
    @PostMapping("/users")
    public ResponseEntity<User> 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

@Component
public class RateLimitingFilter implements Filter {
    private final Map<String, RateLimiter> 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

@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

# 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 — ограниченные данные
@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

@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

@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<String, String> {
    @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

@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

@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);
    }
}
@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

@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

@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

@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<FinancialTransaction> 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?