Legionisto cyberbezpieczenstwa! Architekt Vitruvius wie, ze kazda prowincja Imperium potrzebuje solidnych fortyfikacji. Tak jak mury obronne chroniły Rzym przed najeźdźcami, tak SSL/TLS i zabezpieczenia HTTP chronią nasze aplikacje NestJS przed atakami z sieci. Czas poznać sztukę budowania cyfrowych murów obronnych!
SSL (Secure Sockets Layer) i jego następca TLS (Transport Layer Security) to protokoły kryptograficzne zapewniające bezpieczną komunikację w sieci. HTTPS to HTTP działający przez warstwę SSL/TLS - szyfruje dane przesyłane między klientem a serwerem.
Pierwszym krokiem w budowie murów obronnych jest pozyskanie certyfikatów. W środowisku deweloperskim możemy wygenerować certyfikaty samopodpisane, a na produkcji korzystamy z Let's Encrypt lub komercyjnych dostawców.
1// scripts/generate-dev-cert.ts
2import { execSync } from 'child_process';
3import * as fs from 'fs';
4import * as path from 'path';
5
6const certsDir = path.join(__dirname, '..', 'certs');
7
8// Tworzenie katalogu na certyfikaty
9if (!fs.existsSync(certsDir)) {
10 fs.mkdirSync(certsDir, { recursive: true });
11}
12
13// Generowanie klucza prywatnego i certyfikatu
14execSync(`openssl req -x509 -newkey rsa:4096 \
15 -keyout ${certsDir}/key.pem \
16 -out ${certsDir}/cert.pem \
17 -days 365 -nodes \
18 -subj "/C=PL/ST=Roma/L=Roma/O=Imperium/CN=localhost"`);
19
20console.log('Certyfikaty deweloperskie wygenerowane w katalogu certs/');1// src/main.ts - uruchomienie serwera z HTTPS
2import { NestFactory } from '@nestjs/core';
3import { AppModule } from './app.module';
4import * as fs from 'fs';
5import * as path from 'path';
6
7async function bootstrap() {
8 const isProduction = process.env.NODE_ENV === 'production';
9
10 // Opcje HTTPS - certyfikaty SSL
11 const httpsOptions = isProduction
12 ? {
13 key: fs.readFileSync(process.env.SSL_KEY_PATH),
14 cert: fs.readFileSync(process.env.SSL_CERT_PATH),
15 ca: fs.readFileSync(process.env.SSL_CA_PATH), // Chain certyfikatow
16 }
17 : {
18 key: fs.readFileSync(path.join(__dirname, '..', 'certs', 'key.pem')),
19 cert: fs.readFileSync(path.join(__dirname, '..', 'certs', 'cert.pem')),
20 };
21
22 const app = await NestFactory.create(AppModule, { httpsOptions });
23
24 // Wymuszenie przekierowania HTTP -> HTTPS
25 if (isProduction) {
26 app.use((req, res, next) => {
27 if (req.headers['x-forwarded-proto'] !== 'https') {
28 return res.redirect(301, `https://${req.headers.host}${req.url}`);
29 }
30 next();
31 });
32 }
33
34 await app.listen(process.env.PORT || 3000);
35}
36bootstrap();Helmet.js to jak hełm centuriona - chroni głowę (nagłówki HTTP) przed najczęstszymi atakami. Ustawia odpowiednie nagłówki bezpieczeństwa automatycznie.
1// src/main.ts - konfiguracja Helmet
2import helmet from 'helmet';
3
4async function bootstrap() {
5 const app = await NestFactory.create(AppModule);
6
7 // Podstawowa konfiguracja Helmet
8 app.use(helmet());
9
10 // Zaawansowana konfiguracja Helmet
11 app.use(helmet({
12 // Content-Security-Policy - kontroluje skad ladowane sa zasoby
13 contentSecurityPolicy: {
14 directives: {
15 defaultSrc: ["'self'"],
16 scriptSrc: ["'self'", "'unsafe-inline'"],
17 styleSrc: ["'self'", "'unsafe-inline'", 'https://fonts.googleapis.com'],
18 fontSrc: ["'self'", 'https://fonts.gstatic.com'],
19 imgSrc: ["'self'", 'data:', 'https:'],
20 connectSrc: ["'self'", process.env.API_URL],
21 frameSrc: ["'none'"],
22 objectSrc: ["'none'"],
23 },
24 },
25 // Strict-Transport-Security - wymusza HTTPS
26 hsts: {
27 maxAge: 31536000, // 1 rok
28 includeSubDomains: true,
29 preload: true,
30 },
31 // X-Frame-Options - zapobiega clickjacking
32 frameguard: { action: 'deny' },
33 // X-Content-Type-Options - zapobiega MIME sniffing
34 noSniff: true,
35 // Referrer-Policy
36 referrerPolicy: { policy: 'strict-origin-when-cross-origin' },
37 }));
38}CORS (Cross-Origin Resource Sharing) kontroluje, które domeny mogą komunikować się z naszym API. To jak lista zaufanych ambasadorów Imperium.
1// src/main.ts - produkcyjna konfiguracja CORS
2import { CorsOptions } from '@nestjs/common/interfaces/external/cors-options.interface';
3
4const corsOptions: CorsOptions = {
5 origin: (origin, callback) => {
6 const allowedOrigins = process.env.CORS_ORIGINS?.split(',') || [];
7
8 // Pozwol na requesty bez origin (mobile, Postman)
9 if (!origin) return callback(null, true);
10
11 if (allowedOrigins.includes(origin)) {
12 callback(null, true);
13 } else {
14 callback(new Error(`Origin ${origin} nie jest dozwolony przez CORS`));
15 }
16 },
17 methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
18 allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'],
19 exposedHeaders: ['X-Total-Count', 'X-Page-Count'],
20 credentials: true,
21 maxAge: 86400, // Cache preflight na 24h
22};
23
24app.enableCors(corsOptions);Rate limiting to jak strażnicy przy bramach miasta - kontrolują, ile osób może wejść w danym czasie, zapobiegając szturmowi (atakom DDoS).
1// src/app.module.ts - konfiguracja ThrottlerModule
2import { Module } from '@nestjs/common';
3import { ThrottlerModule, ThrottlerGuard } from '@nestjs/throttler';
4import { APP_GUARD } from '@nestjs/core';
5
6@Module({
7 imports: [
8 ThrottlerModule.forRoot([
9 {
10 name: 'short', // Krotkoterminowy limit
11 ttl: 1000, // 1 sekunda
12 limit: 3, // Max 3 requesty na sekunde
13 },
14 {
15 name: 'medium', // Sredni limit
16 ttl: 10000, // 10 sekund
17 limit: 20, // Max 20 requestow na 10 sekund
18 },
19 {
20 name: 'long', // Dlugoterminowy limit
21 ttl: 60000, // 1 minuta
22 limit: 100, // Max 100 requestow na minute
23 },
24 ]),
25 ],
26 providers: [
27 {
28 provide: APP_GUARD,
29 useClass: ThrottlerGuard,
30 },
31 ],
32})
33export class AppModule {}
34
35// Wylaczenie rate limitingu dla konkretnych endpointow
36import { SkipThrottle, Throttle } from '@nestjs/throttler';
37
38@Controller('legions')
39export class LegionsController {
40 @SkipThrottle() // Bez limitu dla health check
41 @Get('health')
42 healthCheck() {
43 return { status: 'ok' };
44 }
45
46 @Throttle({ short: { ttl: 1000, limit: 1 } }) // Surowszy limit
47 @Post('login')
48 login() {
49 // Logowanie z ograniczeniem 1 req/s
50 }
51}CSRF (Cross-Site Request Forgery) to atak, w którym złośliwa strona wykonuje żądania w imieniu zalogowanego użytkownika. Chronimy się przed nim za pomocą tokenów CSRF.
1// src/main.ts - ochrona CSRF z csurf
2import * as csurf from 'csurf';
3
4async function bootstrap() {
5 const app = await NestFactory.create(AppModule);
6
7 // CSRF protection (dla aplikacji z sesja/cookies)
8 app.use(csurf({
9 cookie: {
10 httpOnly: true,
11 secure: process.env.NODE_ENV === 'production',
12 sameSite: 'strict',
13 },
14 }));
15
16 // Middleware ustawiajacy CSRF token w odpowiedzi
17 app.use((req, res, next) => {
18 res.cookie('XSRF-TOKEN', req.csrfToken(), {
19 httpOnly: false, // Frontend musi moc odczytac
20 secure: process.env.NODE_ENV === 'production',
21 sameSite: 'strict',
22 });
23 next();
24 });
25}1// src/security/security.module.ts
2import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
3import { ThrottlerModule } from '@nestjs/throttler';
4import helmet from 'helmet';
5
6@Module({
7 imports: [
8 ThrottlerModule.forRoot([
9 { name: 'short', ttl: 1000, limit: 3 },
10 { name: 'long', ttl: 60000, limit: 100 },
11 ]),
12 ],
13})
14export class SecurityModule implements NestModule {
15 configure(consumer: MiddlewareConsumer) {
16 consumer
17 .apply(
18 helmet(),
19 helmet.contentSecurityPolicy({
20 directives: {
21 defaultSrc: ["'self'"],
22 scriptSrc: ["'self'"],
23 },
24 }),
25 )
26 .forRoutes('*');
27 }
28}Bezpieczenstwo to nie jednorazowe zadanie, a ciagły proces - tak jak obrona murów Imperium wymagała stałej czujności strażników! Każda warstwa zabezpieczeń (SSL, Helmet, CORS, Rate Limiting, CSRF) dodaje kolejny mur obronny wokół Twojej aplikacji.