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
This commit is contained in:
Alexander Abakumov committed 2025-09-09 22:08:07 +03:00
commit 15e744da49
107 files changed
+61762

No files matched your search

@@ -0,0 +1,723 @@
# Уязвимости и межсервисное взаимодействие
## Навигация
- [🏠 Главная страница курса](../../../README.md)
- [📚 Модуль 6](../README.md)
---
## Типы уязвимостей в микросервисной архитектуре
### 1. Уязвимости межсервисного взаимодействия
**Проблемы:**
- Отсутствие аутентификации между сервисами
- Передача чувствительных данных в открытом виде
- Отсутствие валидации токенов
- Man-in-the-middle атаки
- Replay атаки
**Решения:**
- Mutual TLS (mTLS)
- Service-to-Service токены
- API Gateway с аутентификацией
- Token Validation Middleware (TVM)
### 2. TVM (Token Validation Middleware)
**TVM** — промежуточное ПО для валидации токенов между микросервисами.
**Принципы работы:**
1. Сервис получает токен от клиента
2. TVM валидирует токен
3. TVM извлекает информацию о пользователе/сервисе
4. TVM передает валидные данные в целевой сервис
**Технический пример - TVM Implementation:**
```java
@Component
public class TokenValidationMiddleware {
@Autowired
private JwtTokenService jwtTokenService;
@Autowired
private ServiceRegistry serviceRegistry;
public ServiceTokenValidationResult validateServiceToken(String token, String targetService) {
try {
// Валидация токена
Claims claims = jwtTokenService.validateToken(token);
// Проверка прав доступа к сервису
if (!hasAccessToService(claims, targetService)) {
return ServiceTokenValidationResult.denied("No access to service: " + targetService);
}
// Проверка срока действия токена
if (isTokenExpired(claims)) {
return ServiceTokenValidationResult.denied("Token expired");
}
// Извлечение информации о сервисе
ServiceInfo serviceInfo = extractServiceInfo(claims);
return ServiceTokenValidationResult.success(serviceInfo);
} catch (JwtException e) {
return ServiceTokenValidationResult.denied("Invalid token: " + e.getMessage());
}
}
private boolean hasAccessToService(Claims claims, String targetService) {
List<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:**
```rust
// Token Validation Middleware для Actix Web
use actix_web::{web, HttpRequest, HttpResponse, Error, middleware::Next};
use jsonwebtoken::{decode, DecodingKey, Validation, Algorithm};
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
#[derive(Debug, Serialize, Deserialize)]
struct ServiceClaims {
sub: String, // service_id
service_name: String,
allowed_services: Vec<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 "));
match token {
Some(token) => {
// Валидация токена
let middleware = TokenValidationMiddleware::new("your-secret-key");
let target_service = req.path().split('/').nth(1).unwrap_or("unknown");
match middleware.validate_service_token(token, target_service) {
Ok(service_info) => {
// Добавление информации о сервисе в контекст запроса
req.extensions_mut().insert(service_info);
next.run(req).await
}
Err(e) => Ok(HttpResponse::Unauthorized()
.json(serde_json::json!({
"error": "Token validation failed",
"message": e
})))
}
}
None => Ok(HttpResponse::Unauthorized()
.json(serde_json::json!({
"error": "Missing authorization token"
})))
}
}
```
**Python примеры - TVM с FastAPI:**
```python
# Token Validation Middleware для FastAPI
from fastapi import FastAPI, HTTPException, Depends, Request
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from jose import JWTError, jwt
from datetime import datetime, timedelta
from typing import Optional, List
from pydantic import BaseModel
class ServiceClaims(BaseModel):
sub: str
service_name: str
allowed_services: List[str]
permissions: List[str]
iat: int
exp: int
class ServiceInfo(BaseModel):
service_id: str
service_name: str
permissions: List[str]
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) -> ServiceInfo:
try:
# Декодирование токена
payload = jwt.decode(token, self.secret_key, algorithms=[self.algorithm])
# Проверка срока действия
if datetime.utcnow().timestamp() > payload.get("exp", 0):
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}"
)
return ServiceInfo(
service_id=payload.get("sub"),
service_name=payload.get("service_name"),
permissions=payload.get("permissions", [])
)
except JWTError as e:
raise HTTPException(status_code=401, detail=f"Invalid token: {str(e)}")
# Dependency для FastAPI
security = HTTPBearer()
middleware = TokenValidationMiddleware("your-secret-key")
async def get_service_info(
credentials: HTTPAuthorizationCredentials = Depends(security),
request: Request = None
) -> ServiceInfo:
token = credentials.credentials
target_service = request.url.path.split('/')[1] if request else "unknown"
return middleware.validate_service_token(token, target_service)
# Использование в FastAPI
app = FastAPI()
@app.get("/api/orders")
async def get_orders(service_info: ServiceInfo = Depends(get_service_info)):
# Проверка прав доступа
if "read:orders" not in service_info.permissions:
raise HTTPException(status_code=403, detail="Insufficient permissions")
return {"message": "Orders retrieved", "service": service_info.service_name}
```
**Node.js примеры - TVM с Express:**
```typescript
// Token Validation Middleware для Express
import express, { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';
import { Request as JWTRequest } from 'express-jwt';
interface ServiceClaims {
sub: string;
service_name: string;
allowed_services: string[];
permissions: string[];
iat: number;
exp: number;
}
interface ServiceInfo {
service_id: string;
service_name: string;
permissions: string[];
}
class TokenValidationMiddleware {
private secretKey: string;
private algorithm: string = 'HS256';
constructor(secretKey: string) {
this.secretKey = secretKey;
}
validateServiceToken(token: string, targetService: string): ServiceInfo {
try {
// Декодирование токена
const payload = jwt.verify(token, this.secretKey, {
algorithms: [this.algorithm]
}) as ServiceClaims;
// Проверка срока действия
if (Date.now() / 1000 > payload.exp) {
throw new Error('Token expired');
}
// Проверка прав доступа к сервису
if (!payload.allowed_services.includes(targetService)) {
throw new Error(`No access to service: ${targetService}`);
}
return {
service_id: payload.sub,
service_name: payload.service_name,
permissions: payload.permissions
};
} catch (error) {
throw new Error(`Token validation failed: ${error.message}`);
}
}
}
// Middleware для Express
const middleware = new TokenValidationMiddleware('your-secret-key');
export 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 authorization token' });
}
const token = authHeader.substring(7);
const targetService = req.path.split('/')[2] || 'unknown';
const serviceInfo = middleware.validateServiceToken(token, targetService);
// Добавление информации о сервисе в контекст запроса
(req as any).serviceInfo = serviceInfo;
next();
} catch (error) {
res.status(401).json({
error: 'Token validation failed',
message: error.message
});
}
};
// Использование в Express
app.use('/api', tokenValidationMiddleware);
app.get('/api/orders', (req: Request, res: Response) => {
const serviceInfo = (req as any).serviceInfo;
// Проверка прав доступа
if (!serviceInfo.permissions.includes('read:orders')) {
return res.status(403).json({ error: 'Insufficient permissions' });
}
res.json({
message: 'Orders retrieved',
service: serviceInfo.service_name
});
});
```
### 3. Mutual TLS (mTLS)
**mTLS** обеспечивает взаимную аутентификацию между сервисами.
**Java пример - Spring Boot с mTLS:**
```java
@Configuration
@EnableWebSecurity
public class MTlsSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.anyRequest().authenticated()
)
.x509(x509 -> x509
.subjectPrincipalRegex("CN=(.*?)(?:,|$)")
.userDetailsService(userDetailsService())
)
.build();
}
@Bean
public UserDetailsService userDetailsService() {
return username -> {
// Валидация сертификата клиента
if (isValidServiceCertificate(username)) {
return User.builder()
.username(username)
.password("")
.authorities("ROLE_SERVICE")
.build();
}
throw new UsernameNotFoundException("Invalid service certificate");
};
}
private boolean isValidServiceCertificate(String subject) {
// Логика валидации сертификата
return subject.startsWith("service-");
}
}
```
### 4. Service Mesh Security
**Istio Security Configuration:**
```yaml
# PeerAuthentication для mTLS
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: production
spec:
mtls:
mode: STRICT
# AuthorizationPolicy для контроля доступа
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: service-access
namespace: production
spec:
rules:
- from:
- source:
principals: ["cluster.local/ns/production/sa/order-service"]
to:
- operation:
methods: ["GET", "POST"]
paths: ["/api/orders/*"]
```
### 5. API Gateway Security
**Kong Gateway Configuration:**
```yaml
# Kong API Gateway с JWT аутентификацией
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: jwt-auth
config:
key_claim_name: iss
secret_is_base64: false
run_on_preflight: true
---
apiVersion: configuration.konghq.com/v1
kind: KongIngress
metadata:
name: api-ingress
upstream:
healthchecks:
active:
healthy:
interval: 30
successes: 3
unhealthy:
interval: 10
http_failures: 3
```
### 6. Security Headers для микросервисов
**Java пример - Security Headers:**
```java
@Component
public class SecurityHeadersFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse httpResponse = (HttpServletResponse) response;
// 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");
httpResponse.setHeader("Content-Security-Policy", "default-src 'self'");
httpResponse.setHeader("Referrer-Policy", "strict-origin-when-cross-origin");
httpResponse.setHeader("Permissions-Policy", "geolocation=(), microphone=(), camera=()");
chain.doFilter(request, response);
}
}
```
### 7. Rate Limiting для межсервисного взаимодействия
**Redis-based Rate Limiting:**
```java
@Service
public class InterServiceRateLimitingService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
public boolean isAllowed(String serviceId, String targetService, int maxRequests, Duration window) {
String key = String.format("rate_limit:%s:%s", serviceId, targetService);
// Sliding window rate limiting
long now = System.currentTimeMillis();
long windowStart = now - window.toMillis();
// Удаление старых записей
redisTemplate.opsForZSet().removeRangeByScore(key, 0, windowStart);
// Подсчет текущих запросов
Long currentCount = redisTemplate.opsForZSet().count(key, windowStart, now);
if (currentCount >= maxRequests) {
return false;
}
// Добавление нового запроса
redisTemplate.opsForZSet().add(key, UUID.randomUUID().toString(), now);
redisTemplate.expire(key, window);
return true;
}
}
```
### 8. Audit Logging для межсервисного взаимодействия
**Structured Audit Logging:**
```java
@Component
public class InterServiceAuditLogger {
private static final Logger auditLogger = LoggerFactory.getLogger("AUDIT");
public void logServiceCall(String sourceService, String targetService,
String operation, boolean success, String details) {
Map<String, Object> auditData = Map.of(
"timestamp", Instant.now().toString(),
"source_service", sourceService,
"target_service", targetService,
"operation", operation,
"success", success,
"details", details,
"correlation_id", MDC.get("correlationId")
);
auditLogger.info("Inter-service call: {}", auditData);
}
}
```
### 9. Circuit Breaker для безопасности
**Resilience4j Circuit Breaker:**
```java
@Component
public class SecureServiceClient {
private final CircuitBreaker circuitBreaker;
private final Retry retry;
public SecureServiceClient() {
this.circuitBreaker = CircuitBreaker.ofDefaults("secure-service");
this.retry = Retry.ofDefaults("secure-service");
}
@CircuitBreaker(name = "secure-service")
@Retry(name = "secure-service")
public ServiceResponse callSecureService(String serviceUrl, String token) {
try {
// Вызов защищенного сервиса
return restTemplate.exchange(
serviceUrl,
HttpMethod.GET,
createSecureRequest(token),
ServiceResponse.class
).getBody();
} catch (Exception e) {
// Логирование безопасности
securityLogger.warn("Secure service call failed: {}", e.getMessage());
throw e;
}
}
private HttpEntity<?> createSecureRequest(String token) {
HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth(token);
headers.set("X-Service-Name", "order-service");
headers.set("X-Request-ID", UUID.randomUUID().toString());
return new HttpEntity<>(headers);
}
}
```
### 10. Security Monitoring и Alerting
**Security Metrics:**
```java
@Component
public class SecurityMetrics {
private final MeterRegistry meterRegistry;
private final Counter authenticationFailures;
private final Counter authorizationFailures;
private final Timer serviceCallDuration;
public SecurityMetrics(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.authenticationFailures = Counter.builder("security.auth.failures")
.description("Authentication failures")
.register(meterRegistry);
this.authorizationFailures = Counter.builder("security.authz.failures")
.description("Authorization failures")
.register(meterRegistry);
this.serviceCallDuration = Timer.builder("security.service.call.duration")
.description("Secure service call duration")
.register(meterRegistry);
}
public void recordAuthenticationFailure(String reason) {
authenticationFailures.increment(Tags.of("reason", reason));
}
public void recordAuthorizationFailure(String resource) {
authorizationFailures.increment(Tags.of("resource", resource));
}
public Timer.Sample startServiceCallTimer() {
return Timer.start(meterRegistry);
}
}
```
## Заключение
Безопасность межсервисного взаимодействия требует комплексного подхода:
1. **Аутентификация** - проверка подлинности сервисов
2. **Авторизация** - контроль доступа к ресурсам
3. **Шифрование** - защита данных в транзите
4. **Мониторинг** - отслеживание подозрительной активности
5. **Аудит** - логирование всех операций
6. **Rate Limiting** - защита от злоупотреблений
7. **Circuit Breaker** - устойчивость к сбоям
TVM и mTLS являются ключевыми технологиями для обеспечения безопасности в микросервисной архитектуре.
@@ -0,0 +1,766 @@
# Шифрование и управление ключами
## Навигация
- [🏠 Главная страница курса](../../../README.md)
- [📚 Модуль 6](../README.md)
---
## Типы шифрования
### 1. Symmetric Encryption (Симметричное шифрование)
**Симметричное шифрование** использует один ключ для шифрования и расшифровки данных.
**Преимущества:**
- Быстрое выполнение
- Подходит для больших объемов данных
- Простота реализации
**Недостатки:**
- Проблема распределения ключей
- Сложность масштабирования
**Технический пример - Advanced Encryption Service:**
```java
@Service
public class SymmetricEncryptionService {
private final SecretKey secretKey;
private final String algorithm = "AES/GCM/NoPadding";
private final int GCM_IV_LENGTH = 12;
private final int GCM_TAG_LENGTH = 16;
@Value("${encryption.key}")
private String base64Key;
public SymmetricEncryptionService() throws Exception {
// Генерируем ключ из конфигурации или создаем новый
if (base64Key != null && !base64Key.isEmpty()) {
byte[] keyBytes = Base64.getDecoder().decode(base64Key);
this.secretKey = new SecretKeySpec(keyBytes, "AES");
} else {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(256);
this.secretKey = keyGenerator.generateKey();
}
}
public EncryptedData encrypt(String plainText) throws Exception {
if (plainText == null || plainText.isEmpty()) {
throw new IllegalArgumentException("Plain text cannot be null or empty");
}
// Генерируем случайный IV
byte[] iv = new byte[GCM_IV_LENGTH];
SecureRandom.getInstanceStrong().nextBytes(iv);
// Настраиваем шифр
Cipher cipher = Cipher.getInstance(algorithm);
GCMParameterSpec parameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);
// Шифруем данные
byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
// Объединяем IV и зашифрованные данные
byte[] encryptedWithIv = new byte[GCM_IV_LENGTH + encryptedBytes.length];
System.arraycopy(iv, 0, encryptedWithIv, 0, GCM_IV_LENGTH);
System.arraycopy(encryptedBytes, 0, encryptedWithIv, GCM_IV_LENGTH, encryptedBytes.length);
return new EncryptedData(
Base64.getEncoder().encodeToString(encryptedWithIv),
System.currentTimeMillis()
);
}
public String decrypt(EncryptedData encryptedData) throws Exception {
if (encryptedData == null || encryptedData.getData() == null) {
throw new IllegalArgumentException("Encrypted data cannot be null");
}
byte[] encryptedWithIv = Base64.getDecoder().decode(encryptedData.getData());
if (encryptedWithIv.length < GCM_IV_LENGTH) {
throw new IllegalArgumentException("Invalid encrypted data length");
}
// Извлекаем IV
byte[] iv = new byte[GCM_IV_LENGTH];
System.arraycopy(encryptedWithIv, 0, iv, 0, GCM_IV_LENGTH);
// Извлекаем зашифрованные данные
byte[] encryptedBytes = new byte[encryptedWithIv.length - GCM_IV_LENGTH];
System.arraycopy(encryptedWithIv, GCM_IV_LENGTH, encryptedBytes, 0, encryptedBytes.length);
// Настраиваем шифр для расшифровки
Cipher cipher = Cipher.getInstance(algorithm);
GCMParameterSpec parameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv);
cipher.init(Cipher.DECRYPT_MODE, secretKey, parameterSpec);
// Расшифровываем данные
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
return new String(decryptedBytes, StandardCharsets.UTF_8);
}
public String encryptSensitiveField(String value) throws Exception {
if (value == null) {
return null;
}
return encrypt(value).getData();
}
public String decryptSensitiveField(String encryptedValue) throws Exception {
if (encryptedValue == null) {
return null;
}
return decrypt(new EncryptedData(encryptedValue, 0L));
}
}
// Encrypted Data Wrapper
public class EncryptedData {
private final String data;
private final long timestamp;
public EncryptedData(String data, long timestamp) {
this.data = data;
this.timestamp = timestamp;
}
public String getData() {
return data;
}
public long getTimestamp() {
return timestamp;
}
}
// Field-level Encryption
@Entity
public class User {
@Id
private Long id;
private String name;
@Convert(converter = EncryptedStringConverter.class)
private String email;
@Convert(converter = EncryptedStringConverter.class)
private String phoneNumber;
@Convert(converter = EncryptedStringConverter.class)
private String ssn;
// Getters and setters
}
// Custom Converter for JPA
@Converter
public class EncryptedStringConverter implements AttributeConverter<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);
}
}
}
```
**Rust примеры - Симметричное шифрование:**
```rust
use aes_gcm::{Aes256Gcm, Key, Nonce};
use aes_gcm::aead::{Aead, NewAead};
use rand::Rng;
pub struct SymmetricEncryptionService {
cipher: Aes256Gcm,
}
impl SymmetricEncryptionService {
pub fn new(key: &[u8]) -> Result<Self, Box<dyn std::error::Error>> {
let key = Key::from_slice(key);
let cipher = Aes256Gcm::new(key);
Ok(Self { cipher })
}
pub fn encrypt(&self, plaintext: &str) -> Result<EncryptedData, Box<dyn std::error::Error>> {
let nonce = self.generate_nonce();
let ciphertext = self.cipher.encrypt(&nonce, plaintext.as_bytes())?;
Ok(EncryptedData {
data: base64::encode(ciphertext),
nonce: base64::encode(nonce),
timestamp: std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)?
.as_secs(),
})
}
pub fn decrypt(&self, encrypted_data: &EncryptedData) -> Result<String, Box<dyn std::error::Error>> {
let nonce = base64::decode(&encrypted_data.nonce)?;
let ciphertext = base64::decode(&encrypted_data.data)?;
let plaintext = self.cipher.decrypt(&nonce.into(), ciphertext.as_ref())?;
Ok(String::from_utf8(plaintext)?)
}
fn generate_nonce(&self) -> Nonce {
let mut nonce = [0u8; 12];
rand::thread_rng().fill(&mut nonce);
nonce.into()
}
}
#[derive(Debug, Clone)]
pub struct EncryptedData {
pub data: String,
pub nonce: String,
pub timestamp: u64,
}
```
**Python примеры - Симметричное шифрование:**
```python
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
import base64
import os
class SymmetricEncryptionService:
def __init__(self, password: str):
# Генерируем ключ из пароля
salt = os.urandom(16)
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=100000,
)
key = base64.urlsafe_b64encode(kdf.derive(password.encode()))
self.cipher = Fernet(key)
def encrypt(self, plaintext: str) -> EncryptedData:
if not plaintext:
raise ValueError("Plaintext cannot be empty")
encrypted_data = self.cipher.encrypt(plaintext.encode())
return EncryptedData(
data=base64.b64encode(encrypted_data).decode(),
timestamp=int(time.time())
)
def decrypt(self, encrypted_data: EncryptedData) -> str:
if not encrypted_data.data:
raise ValueError("Encrypted data cannot be empty")
encrypted_bytes = base64.b64decode(encrypted_data.data)
decrypted_bytes = self.cipher.decrypt(encrypted_bytes)
return decrypted_bytes.decode()
@dataclass
class EncryptedData:
data: str
timestamp: int
```
**Node.js примеры - Симметричное шифрование:**
```typescript
import crypto from 'crypto';
interface EncryptedData {
data: string;
iv: string;
timestamp: number;
}
class SymmetricEncryptionService {
private algorithm = 'aes-256-gcm';
private keyLength = 32;
private ivLength = 16;
private tagLength = 16;
constructor(private key: Buffer) {
if (key.length !== this.keyLength) {
throw new Error(`Key must be ${this.keyLength} bytes long`);
}
}
encrypt(plaintext: string): EncryptedData {
if (!plaintext) {
throw new Error('Plaintext cannot be empty');
}
const iv = crypto.randomBytes(this.ivLength);
const cipher = crypto.createCipher(this.algorithm, this.key);
cipher.setAAD(iv);
let encrypted = cipher.update(plaintext, 'utf8', 'hex');
encrypted += cipher.final('hex');
const tag = cipher.getAuthTag();
return {
data: encrypted,
iv: iv.toString('hex'),
timestamp: Date.now()
};
}
decrypt(encryptedData: EncryptedData): string {
if (!encryptedData.data || !encryptedData.iv) {
throw new Error('Invalid encrypted data');
}
const iv = Buffer.from(encryptedData.iv, 'hex');
const decipher = crypto.createDecipher(this.algorithm, this.key);
decipher.setAAD(iv);
let decrypted = decipher.update(encryptedData.data, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
}
```
### 2. Asymmetric Encryption (Асимметричное шифрование)
**Асимметричное шифрование** использует пару ключей: публичный для шифрования и приватный для расшифровки.
**Преимущества:**
- Безопасное распределение ключей
- Цифровые подписи
- Масштабируемость
**Недостатки:**
- Медленнее симметричного шифрования
- Сложность реализации
```java
@Service
public class AsymmetricEncryptionService {
private final KeyPair keyPair;
public AsymmetricEncryptionService() throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
this.keyPair = keyPairGenerator.generateKeyPair();
}
public String encrypt(String plainText, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());
return Base64.getEncoder().encodeToString(encryptedBytes);
}
public String decrypt(String encryptedText, PrivateKey privateKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
return new String(decryptedBytes);
}
public String sign(String data, PrivateKey privateKey) throws Exception {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(data.getBytes());
byte[] signatureBytes = signature.sign();
return Base64.getEncoder().encodeToString(signatureBytes);
}
public boolean verify(String data, String signature, PublicKey publicKey) throws Exception {
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initVerify(publicKey);
sig.update(data.getBytes());
return sig.verify(Base64.getDecoder().decode(signature));
}
}
```
### 3. Hashing (Хеширование)
**Хеширование** — одностороннее преобразование данных в фиксированную длину.
**Применения:**
- Хранение паролей
- Проверка целостности данных
- Цифровые подписи
```java
@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);
}
}
```
## Управление ключами
### 1. Key Rotation (Ротация ключей)
**Ротация ключей** — регулярная смена ключей шифрования для повышения безопасности.
```java
@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);
}
}
}
```
### 2. Hardware Security Module (HSM)
**HSM** — аппаратный модуль безопасности для безопасного хранения и управления ключами.
```java
@Service
public class HSMService {
private final HSMClient hsmClient;
public String encryptWithHSM(String data) {
return hsmClient.encrypt(data);
}
public String decryptWithHSM(String encryptedData) {
return hsmClient.decrypt(encryptedData);
}
public String signWithHSM(String data) {
return hsmClient.sign(data);
}
public boolean verifyWithHSM(String data, String signature) {
return hsmClient.verify(data, signature);
}
public String generateKeyInHSM(String keyId) {
return hsmClient.generateKey(keyId);
}
public void deleteKeyFromHSM(String keyId) {
hsmClient.deleteKey(keyId);
}
}
```
### 3. Key Vault Integration
**Интеграция с хранилищем ключей** для централизованного управления ключами.
```java
@Service
public class KeyVaultService {
@Value("${azure.keyvault.url}")
private String keyVaultUrl;
@Value("${azure.keyvault.client-id}")
private String clientId;
@Value("${azure.keyvault.client-secret}")
private String clientSecret;
private KeyVaultClient keyVaultClient;
@PostConstruct
public void initialize() {
// Инициализация клиента Key Vault
this.keyVaultClient = new KeyVaultClient(keyVaultUrl, clientId, clientSecret);
}
public String getSecret(String secretName) {
return keyVaultClient.getSecret(secretName);
}
public void setSecret(String secretName, String secretValue) {
keyVaultClient.setSecret(secretName, secretValue);
}
public void deleteSecret(String secretName) {
keyVaultClient.deleteSecret(secretName);
}
public String getKey(String keyName) {
return keyVaultClient.getKey(keyName);
}
public void createKey(String keyName, String keyType) {
keyVaultClient.createKey(keyName, keyType);
}
}
```
## Безопасность ключей
### 1. Key Storage (Хранение ключей)
**Принципы безопасного хранения ключей:**
- Никогда не храните ключи в коде
- Используйте переменные окружения
- Шифруйте ключи при хранении
- Разделяйте ключи по окружениям
```java
@Configuration
public class KeyStorageConfig {
@Bean
public SecretKey encryptionKey() {
String keyString = System.getenv("ENCRYPTION_KEY");
if (keyString == null) {
throw new IllegalStateException("ENCRYPTION_KEY environment variable not set");
}
byte[] keyBytes = Base64.getDecoder().decode(keyString);
return new SecretKeySpec(keyBytes, "AES");
}
@Bean
public String jwtSecret() {
String secret = System.getenv("JWT_SECRET");
if (secret == null) {
throw new IllegalStateException("JWT_SECRET environment variable not set");
}
return secret;
}
}
```
### 2. Key Access Control (Контроль доступа к ключам)
```java
@Service
public class KeyAccessControlService {
@Autowired
private AuditService auditService;
public SecretKey getKeyWithAccessControl(String keyId, String userId, String operation) {
// Проверяем права доступа
if (!hasKeyAccess(userId, keyId, operation)) {
auditService.logUnauthorizedKeyAccess(userId, keyId, operation);
throw new AccessDeniedException("Access denied to key: " + keyId);
}
// Логируем доступ к ключу
auditService.logKeyAccess(userId, keyId, operation);
// Возвращаем ключ
return keyManagementService.getKey(keyId);
}
private boolean hasKeyAccess(String userId, String keyId, String operation) {
// Логика проверки прав доступа к ключу
return userService.hasPermission(userId, "key:" + keyId + ":" + operation);
}
}
```
### 3. Key Monitoring (Мониторинг ключей)
```java
@Service
public class KeyMonitoringService {
@Autowired
private MetricsService metricsService;
@Autowired
private AlertService alertService;
public void monitorKeyUsage(String keyId, String operation) {
// Увеличиваем счетчик использования ключа
metricsService.incrementCounter("key.usage",
Tags.of("key_id", keyId, "operation", operation));
// Проверяем на подозрительную активность
if (isSuspiciousActivity(keyId, operation)) {
alertService.sendKeySecurityAlert(keyId, operation);
}
}
private boolean isSuspiciousActivity(String keyId, String operation) {
// Проверка на необычное использование ключа
long usageCount = metricsService.getCounterValue("key.usage",
Tags.of("key_id", keyId, "operation", operation));
return usageCount > 1000; // Подозрительно много использований
}
}
```
## Заключение
Шифрование и управление ключами являются критически важными компонентами безопасности:
1. **Выбор алгоритма** — AES для симметричного, RSA/ECC для асимметричного
2. **Управление ключами** — ротация, безопасное хранение, контроль доступа
3. **Мониторинг** — отслеживание использования и подозрительной активности
4. **Соответствие стандартам** — PCI DSS, GDPR, SOX
Правильная реализация этих компонентов обеспечивает защиту данных на всех уровнях приложения.
@@ -0,0 +1,555 @@
# Обфускация и защита кода
## Навигация
- [🏠 Главная страница курса](../../../README.md)
- [📚 Модуль 6](../README.md)
---
## Принципы защиты исходного кода
### 1. Обфускация кода (Code Obfuscation)
**Обфускация** — процесс преобразования исходного кода в трудночитаемую форму для защиты интеллектуальной собственности и усложнения реверс-инжиниринга.
**Цели обфускации:**
- Защита алгоритмов и бизнес-логики
- Усложнение реверс-инжиниринга
- Защита от кражи интеллектуальной собственности
- Предотвращение модификации кода
**Методы обфускации:**
```java
// Исходный код
public class PaymentProcessor {
private static final String API_KEY = "sk_live_123456789";
private static final String SECRET_KEY = "secret_abc123";
public PaymentResult processPayment(PaymentRequest request) {
if (request.getAmount() > 10000) {
return validateHighAmountPayment(request);
}
return processStandardPayment(request);
}
private PaymentResult validateHighAmountPayment(PaymentRequest request) {
// Сложная логика валидации
boolean isValid = performAdvancedValidation(request);
if (isValid) {
return executePayment(request);
}
return PaymentResult.failed("Validation failed");
}
}
// Обфускированный код
public class a {
private static final String b = "sk_live_123456789";
private static final String c = "secret_abc123";
public d e(f g) {
if (g.h() > 10000) {
return i(g);
}
return j(g);
}
private d i(f g) {
boolean h = k(g);
if (h) {
return l(g);
}
return d.m("Validation failed");
}
}
```
**Rust примеры - Обфускация:**
```rust
// Исходный код
pub struct PaymentProcessor {
api_key: String,
secret_key: String,
}
impl PaymentProcessor {
pub fn new(api_key: String, secret_key: String) -> Self {
Self { api_key, secret_key }
}
pub fn process_payment(&self, request: PaymentRequest) -> PaymentResult {
if request.amount > 10000 {
return self.validate_high_amount_payment(request);
}
self.process_standard_payment(request)
}
fn validate_high_amount_payment(&self, request: PaymentRequest) -> PaymentResult {
let is_valid = self.perform_advanced_validation(&request);
if is_valid {
self.execute_payment(request)
} else {
PaymentResult::failed("Validation failed")
}
}
}
// Обфускированный код (с использованием макросов)
macro_rules! obfuscate_string {
($s:expr) => {
base64::decode($s).unwrap_or_else(|_| $s.as_bytes().to_vec())
};
}
pub struct a {
b: Vec<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 примеры - Обфускация:**
```python
# Исходный код
class PaymentProcessor:
def __init__(self, api_key, secret_key):
self.api_key = api_key
self.secret_key = secret_key
def process_payment(self, request):
if request.amount > 10000:
return self.validate_high_amount_payment(request)
return self.process_standard_payment(request)
def validate_high_amount_payment(self, request):
is_valid = self.perform_advanced_validation(request)
if is_valid:
return self.execute_payment(request)
return PaymentResult.failed("Validation failed")
# Обфускированный код
import base64
import zlib
class a:
def __init__(self, b, c):
self.b = b
self.c = c
def d(self, e):
if e.f > 10000:
return self.g(e)
return self.h(e)
def g(self, e):
i = self.j(e)
if i:
return self.k(e)
return l.m("Validation failed")
# Дополнительная обфускация строк
def obfuscate_string(s):
return base64.b64encode(zlib.compress(s.encode())).decode()
# Использование
API_KEY = obfuscate_string("sk_live_123456789")
SECRET_KEY = obfuscate_string("secret_abc123")
```
**Node.js примеры - Обфускация:**
```typescript
// Исходный код
class PaymentProcessor {
private apiKey: string;
private secretKey: string;
constructor(apiKey: string, secretKey: string) {
this.apiKey = apiKey;
this.secretKey = secretKey;
}
processPayment(request: PaymentRequest): PaymentResult {
if (request.amount > 10000) {
return this.validateHighAmountPayment(request);
}
return this.processStandardPayment(request);
}
private validateHighAmountPayment(request: PaymentRequest): PaymentResult {
const isValid = this.performAdvancedValidation(request);
if (isValid) {
return this.executePayment(request);
}
return PaymentResult.failed("Validation failed");
}
}
// Обфускированный код
class a {
private b: string;
private c: string;
constructor(d: string, e: string) {
this.b = d;
this.c = e;
}
f(g: h): i {
if (g.j > 10000) {
return this.k(g);
}
return this.l(g);
}
private k(g: h): i {
const m = this.n(g);
if (m) {
return this.o(g);
}
return i.p("Validation failed");
}
}
// Webpack конфигурация для обфускации
module.exports = {
mode: 'production',
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
mangle: {
properties: {
regex: /^_/
}
},
compress: {
drop_console: true,
drop_debugger: true,
pure_funcs: ['console.log']
}
}
})
]
}
};
```
### 2. Минификация (Minification)
**Минификация** — процесс удаления ненужных символов из кода без изменения его функциональности.
**Методы минификации:**
```javascript
// Исходный JavaScript код
function calculateTotal(items) {
let total = 0;
for (let i = 0; i < items.length; i++) {
if (items[i].price > 0) {
total += items[i].price * items[i].quantity;
}
}
return total;
}
// Минифицированный код
function calculateTotal(items){let total=0;for(let i=0;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. Защита от реверс-инжиниринга
**Методы защиты:**
```java
// Анти-отладка
public class AntiDebugProtection {
public static boolean isDebuggerPresent() {
try {
// Проверка наличия отладчика
System.getProperty("java.vm.info");
return System.getProperty("java.vm.info").contains("debug");
} catch (Exception e) {
return true; // Предполагаем наличие отладчика при ошибке
}
}
public static void checkDebugger() {
if (isDebuggerPresent()) {
System.exit(1); // Завершение при обнаружении отладчика
}
}
// Проверка целостности кода
public static boolean verifyCodeIntegrity() {
try {
String expectedHash = "a1b2c3d4e5f6";
String actualHash = calculateClassHash();
return expectedHash.equals(actualHash);
} catch (Exception e) {
return false;
}
}
private static String calculateClassHash() {
// Расчет хеша класса для проверки целостности
return "calculated_hash";
}
}
// Защита от модификации
@Component
public class CodeProtectionService {
@PostConstruct
public void initializeProtection() {
// Проверка целостности при запуске
if (!verifyCodeIntegrity()) {
throw new SecurityException("Code integrity check failed");
}
// Проверка на отладчик
checkDebugger();
// Запуск фоновой проверки
startBackgroundProtection();
}
@Scheduled(fixedRate = 30000) // Каждые 30 секунд
public void backgroundProtection() {
if (!verifyCodeIntegrity()) {
System.exit(1);
}
if (isDebuggerPresent()) {
System.exit(1);
}
}
}
```
### 4. Source Maps и их безопасность
**Проблемы Source Maps:**
```javascript
// webpack.config.js - НЕБЕЗОПАСНО
module.exports = {
devtool: 'source-map', // Раскрывает весь исходный код
// БЕЗОПАСНО - только для разработки
devtool: process.env.NODE_ENV === 'development' ? 'source-map' : false,
// БЕЗОПАСНО - скрытые source maps
devtool: 'hidden-source-map',
// БЕЗОПАСНО - только для внутреннего использования
devtool: 'nosources-source-map'
};
// Безопасная конфигурация
module.exports = {
mode: 'production',
devtool: false, // Отключение source maps в продакшене
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
sourceMap: false, // Отключение source maps
mangle: true,
compress: {
drop_console: true,
drop_debugger: true
}
}
})
]
},
// Условное включение source maps только для разработки
...(process.env.NODE_ENV === 'development' && {
devtool: 'eval-source-map'
})
};
```
### 5. Защита конфигурационных файлов
```java
// Защита конфигурации
@Configuration
@EnableEncryption
public class SecureConfiguration {
@Value("${encrypted.database.password}")
private String encryptedDbPassword;
@Value("${encrypted.api.key}")
private String encryptedApiKey;
@Bean
public DataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:postgresql://localhost:5432/mydb");
config.setUsername("user");
config.setPassword(decrypt(encryptedDbPassword)); // Расшифровка пароля
return new HikariDataSource(config);
}
@Bean
public RestTemplate restTemplate() {
RestTemplate template = new RestTemplate();
template.getInterceptors().add(new ApiKeyInterceptor(decrypt(encryptedApiKey)));
return template;
}
private String decrypt(String encryptedValue) {
// Логика расшифровки
return encryptionService.decrypt(encryptedValue);
}
}
// Шифрование конфигурации
@Service
public class ConfigurationEncryptionService {
public String encryptConfiguration(String value) {
try {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec keySpec = new SecretKeySpec(
getEncryptionKey(), "AES");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] encrypted = cipher.doFinal(value.getBytes());
return Base64.getEncoder().encodeToString(encrypted);
} catch (Exception e) {
throw new ConfigurationException("Failed to encrypt configuration", e);
}
}
private byte[] getEncryptionKey() {
// Получение ключа шифрования из безопасного хранилища
return keyManagementService.getEncryptionKey();
}
}
```
### 6. Защита от анализа трафика
```java
// Обфускация сетевого трафика
@Service
public class NetworkObfuscationService {
public String obfuscateRequest(String originalRequest) {
// Обфускация параметров запроса
String obfuscated = base64Encode(originalRequest);
obfuscated = addRandomPadding(obfuscated);
obfuscated = xorWithKey(obfuscated, getObfuscationKey());
return obfuscated;
}
public String deobfuscateResponse(String obfuscatedResponse) {
// Деобфускация ответа
String deobfuscated = xorWithKey(obfuscatedResponse, getObfuscationKey());
deobfuscated = removeRandomPadding(deobfuscated);
deobfuscated = base64Decode(deobfuscated);
return deobfuscated;
}
private String addRandomPadding(String data) {
// Добавление случайных данных для усложнения анализа
Random random = new Random();
int paddingLength = random.nextInt(100) + 50;
StringBuilder padding = new StringBuilder();
for (int i = 0; i < paddingLength; i++) {
padding.append((char) (random.nextInt(26) + 'a'));
}
return padding.toString() + data + padding.toString();
}
private String removeRandomPadding(String data) {
// Удаление случайных данных
// Логика удаления padding
return data.substring(50, data.length() - 50);
}
}
```
## Инструменты обфускации
### Java
- **ProGuard** - обфускация и минификация
- **Allatori** - коммерческая обфускация
- **DashO** - профессиональная обфускация
### JavaScript/TypeScript
- **Terser** - минификация и обфускация
- **UglifyJS** - минификация JavaScript
- **Webpack** - бандлинг и обфускация
### Python
- **PyArmor** - обфускация Python кода
- **Nuitka** - компиляция в нативный код
- **cx_Freeze** - создание исполняемых файлов
### Rust
- **rustc** с флагами оптимизации
- **strip** - удаление отладочной информации
- **upx** - сжатие исполняемых файлов
## Заключение
Обфускация и защита кода являются важными мерами безопасности:
1. **Обфускация** — усложнение понимания кода
2. **Минификация** — уменьшение размера и удаление отладочной информации
3. **Анти-отладка** — защита от анализа во время выполнения
4. **Защита конфигурации** — шифрование чувствительных настроек
5. **Обфускация трафика** — усложнение анализа сетевого взаимодействия
Правильное применение этих техник значительно повышает безопасность приложения и защищает интеллектуальную собственность.
@@ -0,0 +1,745 @@
# Security by Design
## Навигация
- [🏠 Главная страница курса](../../../README.md)
- [📚 Модуль 6](../README.md)
---
## Принципы Security by Design
### 1. Secure by Default
- Безопасные настройки по умолчанию
- Минимальные права доступа
- Защита от случайных ошибок
### 2. Fail Secure
- При отказе система переходит в безопасное состояние
- Блокировка доступа при ошибках
- Логирование всех событий безопасности
### 3. Security as Code
- Безопасность как часть кода
- Автоматизированные проверки безопасности
- Версионирование политик безопасности
## Моделирование угроз
### STRIDE Model
- **S**poofing (Подмена)
- **T**ampering (Изменение)
- **R**epudiation (Отказ)
- **I**nformation Disclosure (Раскрытие информации)
- **D**enial of Service (Отказ в обслуживании)
- **E**levation of Privilege (Повышение привилегий)
### Пример Threat Model:
```yaml
# threat-model.yml
application: "E-commerce Platform"
components:
- name: "User Authentication"
threats:
- type: "Spoofing"
description: "User impersonation"
mitigations:
- "Strong password policy"
- "Multi-factor authentication"
- name: "Payment Processing"
threats:
- type: "Tampering"
description: "Payment data modification"
mitigations:
- "Data encryption"
- "Digital signatures"
```
## Архитектура безопасности
### 1. Zero Trust Architecture
**Принцип:** "Никогда не доверяй, всегда проверяй"
```java
@Component
public class ZeroTrustFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
// проверяем каждую аутентификацию
if (!isAuthenticated(httpRequest)) {
throw new AuthenticationException("Authentication required");
}
// проверяем каждую авторизацию
if (!isAuthorized(httpRequest)) {
throw new AuthorizationException("Access denied");
}
// проверяем устройство
if (!isDeviceTrusted(httpRequest)) {
throw new SecurityException("Untrusted device");
}
chain.doFilter(request, response);
}
}
```
### 2. Microsegmentation
**Принцип:** Разделение сети на мелкие сегменты
```yaml
# network-policy.yml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: order-service-policy
spec:
podSelector:
matchLabels:
app: order-service
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: api-gateway
ports:
- protocol: TCP
port: 8080
egress:
- to:
- podSelector:
matchLabels:
app: payment-service
ports:
- protocol: TCP
port: 8080
```
## Аутентификация и авторизация
### Аутентификация
#### 1. Password-based Authentication
```java
@Service
public class AuthenticationService {
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private UserRepository userRepository;
public AuthenticationResult authenticate(String username, String password) {
User user = userRepository.findByUsername(username);
if (user == null) {
return AuthenticationResult.failure("User not found");
}
if (!passwordEncoder.matches(password, user.getPasswordHash())) {
return AuthenticationResult.failure("Invalid password");
}
if (!user.isActive()) {
return AuthenticationResult.failure("User account is disabled");
}
return AuthenticationResult.success(user);
}
}
```
#### 2. Multi-Factor Authentication (MFA)
```java
@Service
public class MFAService {
@Autowired
private TOTPGenerator totpGenerator;
@Autowired
private SMSService smsService;
public void enableMFA(Long userId, String phoneNumber) {
String secret = totpGenerator.generateSecret();
userRepository.updateMFASecret(userId, secret);
userRepository.updatePhoneNumber(userId, phoneNumber);
}
public boolean verifyMFA(Long userId, String code) {
User user = userRepository.findById(userId);
String secret = user.getMFASecret();
return totpGenerator.verifyCode(secret, code);
}
public void sendSMS(Long userId, String code) {
User user = userRepository.findById(userId);
smsService.sendSMS(user.getPhoneNumber(), "Your verification code: " + code);
}
}
```
#### 3. OAuth 2.0 / OpenID Connect
```java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.oauth2Login(oauth2 -> oauth2
.userInfoEndpoint(userInfo -> userInfo
.userService(customOAuth2UserService)
)
)
.authorizeHttpRequests(authz -> authz
.requestMatchers("/public/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
);
return http.build();
}
}
```
### Авторизация
#### 1. Role-Based Access Control (RBAC)
```java
@Entity
public class User {
@Id
private Long id;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
name = "user_roles",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id")
)
private Set<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)
```java
@Component
public class ABACPolicyEngine {
public boolean evaluate(Policy policy, AccessRequest request) {
// проверяем субъект
if (!policy.getSubject().matches(request.getSubject())) {
return false;
}
// проверяем ресурс
if (!policy.getResource().matches(request.getResource())) {
return false;
}
// проверяем действие
if (!policy.getAction().matches(request.getAction())) {
return false;
}
// проверяем контекст
if (!policy.getContext().matches(request.getContext())) {
return false;
}
return true;
}
}
// Пример политики
Policy policy = Policy.builder()
.subject("role:manager")
.resource("department:finance")
.action("read")
.context("time:business_hours")
.build();
```
#### 3. JWT Tokens
```java
@Service
public class JWTService {
private final String secretKey = "mySecretKey";
private final int jwtExpiration = 86400000; // 24 hours
public String generateToken(UserDetails userDetails) {
Map<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
```java
@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
```java
@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
```java
@RestController
@RequestMapping("/api/v1/users")
public class UserControllerV1 {
@GetMapping("/{id}")
public UserV1 getUser(@PathVariable Long id) {
return userService.getUserV1(id);
}
}
@RestController
@RequestMapping("/api/v2/users")
public class UserControllerV2 {
@GetMapping("/{id}")
public UserV2 getUser(@PathVariable Long id) {
return userService.getUserV2(id);
}
}
```
### Безопасность API Gateway
```yaml
# api-gateway-security.yml
apiVersion: networking.istio.io/v1alpha3
kind: AuthorizationPolicy
metadata:
name: api-gateway-policy
spec:
selector:
matchLabels:
app: api-gateway
rules:
- from:
- source:
principals: ["cluster.local/ns/default/sa/api-gateway"]
to:
- operation:
methods: ["GET", "POST"]
paths: ["/api/v1/*"]
- from:
- source:
principals: ["cluster.local/ns/default/sa/admin-service"]
to:
- operation:
methods: ["*"]
paths: ["/admin/*"]
```
## Безопасность данных
### Классификация данных
#### 1. Data Sensitivity Levels
- **Public** — общедоступные данные
- **Internal** — внутренние данные
- **Confidential** — конфиденциальные данные
- **Restricted** — ограниченные данные
```java
@Entity
public class User {
@Id
private Long id;
@Column(name = "username")
@DataClassification(level = DataClassification.Level.INTERNAL)
private String username;
@Column(name = "email")
@DataClassification(level = DataClassification.Level.CONFIDENTIAL)
private String email;
@Column(name = "ssn")
@DataClassification(level = DataClassification.Level.RESTRICTED)
@Encrypted
private String ssn;
}
```
#### 2. Data Masking
```java
@Service
public class DataMaskingService {
public User maskUserData(User user, UserRole requesterRole) {
User maskedUser = new User();
maskedUser.setId(user.getId());
switch (requesterRole) {
case ADMIN:
// админы видят все данные
maskedUser.setEmail(user.getEmail());
maskedUser.setSsn(user.getSsn());
break;
case MANAGER:
// менеджеры видят частично замаскированные данные
maskedUser.setEmail(maskEmail(user.getEmail()));
maskedUser.setSsn(maskSSN(user.getSsn()));
break;
case USER:
// обычные пользователи видят только базовую информацию
maskedUser.setEmail(maskEmail(user.getEmail()));
maskedUser.setSsn("***-**-****");
break;
}
return maskedUser;
}
private String maskEmail(String email) {
String[] parts = email.split("@");
String username = parts[0];
String domain = parts[1];
if (username.length() <= 2) {
return "*@" + domain;
}
return username.substring(0, 2) + "*".repeat(username.length() - 2) + "@" + domain;
}
private String maskSSN(String ssn) {
return "***-**-" + ssn.substring(ssn.length() - 4);
}
}
```
### Шифрование данных
#### 1. Encryption at Rest
```java
@Entity
public class PaymentCard {
@Id
private Long id;
@Column(name = "card_number")
@Convert(converter = EncryptedStringConverter.class)
private String cardNumber;
@Column(name = "cvv")
@Convert(converter = EncryptedStringConverter.class)
private String cvv;
}
@Converter
public class EncryptedStringConverter implements AttributeConverter<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
```java
@Configuration
public class SSLConfig {
@Bean
public RestTemplate restTemplate() throws Exception {
SSLContext sslContext = SSLContextBuilder.create()
.loadTrustMaterial(null, (certificate, authType) -> true)
.build();
HttpClient httpClient = HttpClients.custom()
.setSSLContext(sslContext)
.build();
HttpComponentsClientHttpRequestFactory factory =
new HttpComponentsClientHttpRequestFactory(httpClient);
return new RestTemplate(factory);
}
}
```
## Соответствие требованиям
### GDPR (Общий регламент по защите данных)
#### 1. Data Subject Rights
```java
@Service
public class GDPRService {
public void handleDataSubjectRequest(DataSubjectRequest request) {
switch (request.getType()) {
case ACCESS:
provideDataAccess(request.getSubjectId());
break;
case RECTIFICATION:
rectifyData(request.getSubjectId(), request.getData());
break;
case ERASURE:
eraseData(request.getSubjectId());
break;
case PORTABILITY:
provideDataPortability(request.getSubjectId());
break;
}
}
private void eraseData(Long subjectId) {
// удаляем персональные данные
userRepository.deletePersonalData(subjectId);
// логируем удаление
auditService.logDataErasure(subjectId);
// уведомляем заинтересованные системы
notificationService.notifyDataErasure(subjectId);
}
}
```
#### 2. Consent Management
```java
@Entity
public class Consent {
@Id
private Long id;
private Long userId;
private String purpose;
private ConsentStatus status;
private LocalDateTime givenAt;
private LocalDateTime withdrawnAt;
public boolean isValid() {
return status == ConsentStatus.GIVEN && withdrawnAt == null;
}
}
@Service
public class ConsentService {
public void giveConsent(Long userId, String purpose) {
Consent consent = new Consent();
consent.setUserId(userId);
consent.setPurpose(purpose);
consent.setStatus(ConsentStatus.GIVEN);
consent.setGivenAt(LocalDateTime.now());
consentRepository.save(consent);
}
public void withdrawConsent(Long userId, String purpose) {
Consent consent = consentRepository.findByUserIdAndPurpose(userId, purpose);
if (consent != null) {
consent.setStatus(ConsentStatus.WITHDRAWN);
consent.setWithdrawnAt(LocalDateTime.now());
consentRepository.save(consent);
}
}
}
```
### PCI DSS (Стандарт безопасности данных индустрии платежных карт)
#### 1. Card Data Protection
```java
@Service
public class PCIService {
public String tokenizeCard(String cardNumber) {
// генерируем токен вместо хранения номера карты
String token = UUID.randomUUID().toString();
// сохраняем токен в безопасном хранилище
secureStorage.storeToken(token, cardNumber);
return token;
}
public String detokenizeCard(String token) {
// получаем номер карты по токену
return secureStorage.getCardByToken(token);
}
public boolean validateCard(String cardNumber) {
// проверяем номер карты по алгоритму Луна
return luhnAlgorithm.validate(cardNumber);
}
}
```
#### 2. Secure Payment Processing
```java
@Service
public class PaymentService {
@Transactional
public PaymentResult processPayment(PaymentRequest request) {
// валидируем данные карты
if (!validateCardData(request.getCardData())) {
return PaymentResult.failure("Invalid card data");
}
// токенизируем данные карты
String token = tokenizeCard(request.getCardData().getNumber());
// обрабатываем платеж
PaymentResult result = paymentProcessor.processPayment(request);
// логируем транзакцию
auditService.logPaymentTransaction(request, result);
return result;
}
}
```
### SOX (Закон Сарбейнса-Оксли)
#### 1. Financial Data Controls
```java
@Service
public class FinancialControlService {
public void validateFinancialTransaction(FinancialTransaction transaction) {
// проверяем авторизацию
if (!isAuthorized(transaction.getAmount())) {
throw new AuthorizationException("Transaction amount exceeds authorization limit");
}
// проверяем дублирование
if (isDuplicateTransaction(transaction)) {
throw new DuplicateTransactionException("Duplicate transaction detected");
}
// проверяем целостность данных
if (!validateDataIntegrity(transaction)) {
throw new DataIntegrityException("Data integrity check failed");
}
}
public void auditFinancialData() {
// аудит финансовых данных
List<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
Интеграция этих принципов в процесс разработки обеспечивает надежную защиту приложения от угроз безопасности.
@@ -0,0 +1,24 @@
# Практические задания
## Навигация
- [🏠 Главная страница курса](../../../README.md)
- [📚 Модуль 6](../README.md)
---
### Задание 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
---