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

22 KiB

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

Безопасность 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);
        }
    }
}

Заключение

Security by Design обеспечивает встроенную безопасность на всех уровнях приложения:

  1. Принципы безопасности — Secure by Default, Fail Secure, Security as Code
  2. Моделирование угроз — STRIDE модель для выявления рисков
  3. Архитектура безопасности — Zero Trust, Microsegmentation
  4. Аутентификация и авторизация — MFA, RBAC, ABAC, JWT
  5. Безопасность API — Валидация, Rate Limiting, Versioning
  6. Безопасность данных — Классификация, Маскирование, Шифрование
  7. Соответствие требованиям — GDPR, PCI DSS, SOX

Интеграция этих принципов в процесс разработки обеспечивает надежную защиту приложения от угроз безопасности.