Этот документ описывает меры безопасности, применяемые в TravelMaster Platform, и наше соответствие стандартам защиты данных.
- Security Overview
- Аутентификация и авторизация
- Защита данных
- Compliance
- Security Best Practices
- Incident Response
- Vulnerability Reporting
TravelMaster Platform реализует многоуровневую защиту безопасности:
- Аутентификация: JWT + OAuth 2.0
- Авторизация: RBAC (Role-Based Access Control)
- Шифрование в transit: TLS 1.3
- Шифрование at rest: AES-256
- Network security: Kubernetes Network Policies
- Audit logging: Все действия с персональными данными логируются
Мы используем JWT (JSON Web Tokens) для stateless аутентификации.
{
"header": {
"alg": "RS256",
"typ": "JWT"
},
"payload": {
"sub": "user-id",
"email": "user@example.com",
"roles": ["TRAVELER"],
"iat": 1635724800,
"exp": 1635811200
}
}- Login: User → credentials → JWT token (15 min expiry)
- Access: Client → JWT in Authorization header → Protected resource
- Refresh: Refresh token (30 days) → New JWT token
- Logout: Token revocation (Redis blacklist)
# Request example
curl -H "Authorization: Bearer eyJhbGciOiJS..." \
https://api.travelmaster.com/api/bookings- Backend: Signed with RS256 (private key)
- Client: Stored in httpOnly secure cookies or localStorage
- Revocation: Redis blacklist for logged out tokens
Поддержка социальной аутентификации:
- GitHub
- Facebook (планируется)
- Apple (планируется)
# Configuration
spring:
security:
oauth2:
client:
registration:
google:
client-id: ${GOOGLE_CLIENT_ID}
client-secret: ${GOOGLE_CLIENT_SECRET}
scope: openid,profile,email- TRAVELER — обычный пользователь
- AGENT — турагент с расширенными правами
- ADMIN — администратор системы
| Resource | TRAVELER | AGENT | ADMIN |
|---|---|---|---|
| View trips | ✅ | ✅ | ✅ |
| Create booking | ✅ | ✅ | ✅ |
| Cancel any booking | ❌ | ✅ | ✅ |
| Manage users | ❌ | ❌ | ✅ |
| View analytics | ❌ | ✅ | ✅ |
| System config | ❌ | ❌ | ✅ |
@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/users")
public List<UserDto> getAllUsers() {
return userService.getAllUsers();
}
@PreAuthorize("hasAnyRole('AGENT', 'ADMIN')")
@GetMapping("/analytics")
public AnalyticsDto getAnalytics() {
return analyticsService.getAnalytics();
}TLS 1.3 для всех соединений:
- Client ↔ Gateway: TLS 1.3
- Service ↔ Service: mTLS (mutual TLS) в Kubernetes
- Service ↔ Database: TLS/SSL
# Kubernetes ingress with TLS
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: travelmaster-ingress
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
tls:
- hosts:
- api.travelmaster.com
secretName: travelmaster-tlsШифрование чувствительных полей:
@Entity
public class User {
@Id
private Long id;
// Открытые данные
private String email;
// Зашифрованные поля
@Convert(converter = EncryptedStringConverter.class)
private String passportNumber;
@Convert(converter = EncryptedStringConverter.class)
private String phoneNumber;
}- Kubernetes Secrets: Для credentials и API keys
- External Secrets Operator: Интеграция с Vault (планируется)
- Environment variables: Никогда не хардкодим секреты
# Kubernetes Secret
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
data:
username: dXNlcm5hbWU= # base64 encoded
password: cGFzc3dvcmQ= # base64 encodedPCI DSS compliance: Платёжные данные не хранятся в нашей БД.
Вместо хранения карточных данных:
- Client отправляет данные карты → Payment Gateway
- Payment Gateway → Возвращает токен
- Мы храним только токен
@Entity
public class PaymentMethod {
@Id
private Long id;
private String tokenizedCardNumber; // "tok_1234567890"
private String lastFourDigits; // "4242"
private String cardBrand; // "VISA"
// НЕТ полного номера карты!
}@Slf4j
public class UserService {
public void processPayment(PaymentRequest request) {
// ❌ ПЛОХО
log.info("Processing payment for card: {}", request.getCardNumber());
// ✅ ХОРОШО
log.info("Processing payment for card ending in: {}",
maskCardNumber(request.getCardNumber()));
}
private String maskCardNumber(String cardNumber) {
return "**** **** **** " + cardNumber.substring(cardNumber.length() - 4);
}
}Требования:
- Согласие на обработку персональных данных
- Право на доступ к своим данным
- Право на удаление данных (забвение)
- Защита при хранении и передаче
- Уведомление при утечке
Реализация:
@Entity
public class UserConsent {
@Id
private Long id;
@ManyToOne
private User user;
private ConsentType type; // PERSONAL_DATA, MARKETING, etc.
private boolean granted;
private LocalDateTime grantedAt;
private String ipAddress;
}@GetMapping("/me/export")
public ResponseEntity<byte[]> exportMyData() {
User user = getCurrentUser();
PersonalDataExport export = dataExportService.exportUserData(user);
return ResponseEntity.ok()
.header("Content-Disposition", "attachment; filename=my-data.json")
.body(export.toJson());
}@DeleteMapping("/me")
public ResponseEntity<Void> deleteMyAccount() {
User user = getCurrentUser();
// Анонимизация вместо удаления (для сохранения целостности)
userService.anonymizeUser(user);
return ResponseEntity.noContent().build();
}
public void anonymizeUser(User user) {
user.setEmail("deleted-" + user.getId() + "@anonymized.com");
user.setFirstName("DELETED");
user.setLastName("USER");
user.setPhoneNumber(null);
user.setPassportNumber(null);
user.setDeleted(true);
user.setDeletedAt(LocalDateTime.now());
}Все операции с персональными данными логируются:
@Entity
public class AuditLog {
@Id
private Long id;
private Long userId;
private String action; // "READ", "UPDATE", "DELETE"
private String entity; // "USER", "BOOKING"
private String details;
private String ipAddress;
private LocalDateTime timestamp;
}Требования:
- Не хранить полные номера карт
- Не хранить CVV/CVC
- Токенизация платёжных данных
- Шифрование при передаче
- Ограниченный доступ к платёжным данным
- Регулярные security audits
Реализация:
public PaymentToken tokenizeCard(CardDetails card) {
// Отправка в payment gateway
TokenResponse response = paymentGateway.tokenize(card);
// Сохраняем только токен
PaymentMethod method = new PaymentMethod();
method.setToken(response.getToken());
method.setLastFourDigits(card.getNumber().substring(12));
method.setCardBrand(detectCardBrand(card.getNumber()));
return paymentMethodRepository.save(method);
}@PreAuthorize("hasRole('PAYMENT_ADMIN')")
@GetMapping("/payments/sensitive")
public List<PaymentDto> getSensitivePaymentData() {
// Только специальные администраторы
}Все платёжные операции логируются:
@Aspect
@Component
public class PaymentAuditAspect {
@After("@annotation(AuditPayment)")
public void auditPayment(JoinPoint joinPoint) {
// Log payment operation
auditService.logPaymentOperation(
joinPoint.getSignature().getName(),
joinPoint.getArgs()
);
}
}Хотя TravelMaster — российская платформа, мы также соблюдаем GDPR для европейских пользователей:
- Right to Access: API для экспорта данных
- Right to Erasure: Анонимизация/удаление
- Right to Rectification: Возможность исправления данных
- Data Portability: Экспорт в машиночитаемом формате (JSON)
- Privacy by Design: Безопасность с момента проектирования
// ✅ Всегда проверяем ownership
@GetMapping("/bookings/{id}")
public BookingDto getBooking(@PathVariable Long id) {
Booking booking = bookingService.findById(id);
if (!booking.getUserId().equals(getCurrentUserId())) {
throw new AccessDeniedException("Not your booking");
}
return bookingMapper.toDto(booking);
}// ✅ Используем современные алгоритмы
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(12); // Strong cost factor
}// ✅ Используем PreparedStatement / JPA
@Query("SELECT u FROM User u WHERE u.email = :email")
User findByEmail(@Param("email") String email);
// ❌ НИКОГДА не делайте так
// String sql = "SELECT * FROM users WHERE email = '" + email + "'";- Design reviews перед реализацией
- Threat modeling для новых фич
- Security testing в CI/CD
# ✅ Production configuration
spring:
devtools:
enabled: false
management:
endpoints:
web:
exposure:
include: health,metrics,prometheus
# НЕ expose все endpoints// ✅ Spring автоматически экранирует
@GetMapping("/users/{id}")
public String getUserProfile(@PathVariable Long id, Model model) {
User user = userService.findById(id);
model.addAttribute("user", user);
return "user-profile"; // Thymeleaf автоматически экранирует
}# Gateway configuration
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter:
replenishRate: 10
burstCapacity: 20@Configuration
public class CorsConfig {
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(List.of("https://app.travelmaster.com"));
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
config.setAllowedHeaders(List.of("*"));
config.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
}@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
.authorizeHttpRequests()
.anyRequest().authenticated();
return http.build();
}
}# Регулярные проверки зависимостей
mvn org.owasp:dependency-check-maven:check
# Автоматические обновления через Dependabot
# .github/dependabot.yml# ❌ НИКОГДА не коммитьте секреты
git secrets --scan
# ✅ Используйте переменные окружения
export DATABASE_PASSWORD="..."
# ✅ Kubernetes Secrets
kubectl create secret generic db-creds --from-literal=password=...- Мониторинг security logs
- Alerts от security tools
- User reports
- Изоляция скомпрометированных систем
- Блокировка атакующих IP
- Revoke скомпрометированных tokens
- Устранение уязвимости
- Патчинг систем
- Смена credentials
- Восстановление сервисов
- Верификация integrity
- Мониторинг на повторные атаки
- Post-mortem analysis
- Документирование урока
- Обновление security policies
- Security Team: security@travelmaster.com
- On-call Engineer: +7-XXX-XXX-XXXX
- Management: escalation@travelmaster.com
Если вы обнаружили уязвимость:
- НЕ публикуйте её публично
- Отправьте отчёт: security@travelmaster.com
- Дайте нам 90 дней на исправление
- Получите благодарность в Hall of Fame
Мы планируем запустить Bug Bounty программу с вознаграждениями за найденные уязвимости.
Subject: [SECURITY] Brief description
Description:
Detailed description of the vulnerability
Steps to Reproduce:
1. Step one
2. Step two
3. ...
Impact:
What can an attacker do?
Suggested Fix:
(optional)
Your Contact:
Email for follow-up
- Все входные данные валидируются
- Используется parameterized queries (не string concatenation)
- Passwords хэшируются (bcrypt/argon2)
- Секреты не хардкодятся
- HTTPS для всех соединений
- JWT tokens имеют expiration
- Authorization проверяется на каждом endpoint
- Чувствительные данные маскируются в логах
- Error messages не раскрывают внутреннюю информацию
- Dependencies регулярно обновляются
- Security testing в CI/CD
Version: 1.0
Last Updated: 31 октября 2025
Next Review: Январь 2026
Security is everyone's responsibility! 🔒