Express.js jest jednym z najpopularniejszych frameworków backendowych w ekosystemie Node.js. Choć jest bardzo elastyczny i łatwy w użyciu, odpowiednie przygotowanie aplikacji do produkcji wymaga kilku kluczowych kroków związanych z optymalizacją, bezpieczeństwem i wdrożeniem. W tym artykule omówimy najlepsze praktyki w tych trzech obszarach.
Bezpieczeństwo Aplikacji
Wprowadzenie do Najlepszych Praktyk Bezpieczeństwa
Zabezpieczenie aplikacji internetowej to kluczowy aspekt, szczególnie gdy dane użytkowników są przechowywane i przetwarzane. Kilka podstawowych, ale bardzo ważnych najlepszych praktyk to:
- Unikaj ujawniania informacji o błędach – W środowisku produkcyjnym wyłącz szczegółowe komunikaty o błędach.
- Używaj HTTPS – Wszystkie połączenia powinny być szyfrowane.
- Zabezpiecz hasła – Hasła użytkowników muszą być haszowane przy użyciu silnych algorytmów (np. bcrypt).
Używanie Helmet.js do Ochrony Nagłówków
Helmet.js to middleware, który dodaje kilka nagłówków zabezpieczeń do aplikacji Express.js, zwiększając ochronę przed atakami, takimi jak XSS (Cross-Site Scripting) czy kliknięcia typu clickjacking.
Zainstaluj helmet:
npm install helmet
Następnie dodaj go do swojej aplikacji:
const express = require('express');
const helmet = require('helmet');
const app = express();
app.use(helmet());
// Przykładowa trasa
app.get('/', (req, res) => {
res.send('Bezpieczna aplikacja Express.js!');
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Serwer działa na porcie ${PORT}`);
});
Helmet domyślnie dodaje wiele różnych nagłówków HTTP, które zabezpieczają aplikację przed różnymi typami ataków.
Ochrona przed Atakami SQL Injection i XSS
Ochrona przed SQL Injection
W przypadku, gdy korzystasz z relacyjnej bazy danych, ochrona przed SQL Injection jest kluczowa. Najlepszą praktyką jest używanie zapytań przygotowanych (ang. prepared statements), które automatycznie oczyszczają dane wejściowe, minimalizując ryzyko.
Przykład z użyciem Sequelize:
const { Sequelize, DataTypes } = require('sequelize');
const sequelize = new Sequelize('database', 'username', 'password', {
dialect: 'mysql',
});
// Zamiast interpolacji używaj zapytań przygotowanych:
sequelize.query('SELECT * FROM users WHERE id = ?', {
replacements: [userId],
type: Sequelize.QueryTypes.SELECT,
});
Ochrona przed XSS
Ataki XSS są próbami wstrzyknięcia złośliwego kodu JavaScript do Twojej aplikacji. Do ochrony przed XSS możemy użyć biblioteki express-validator oraz DOMPurify:
npm install express-validator dompurify jsdom
express-validator waliduje dane, a DOMPurify oczyszcza wejścia użytkownika:
const { body, validationResult } = require('express-validator');
const createDOMPurify = require('dompurify');
const { JSDOM } = require('jsdom');
const window = new JSDOM('').window;
const DOMPurify = createDOMPurify(window);
app.post('/submit', [
body('content').not().isEmpty().withMessage('Treść nie może być pusta')
], (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// Oczyszczanie treści użytkownika
const sanitizedContent = DOMPurify.sanitize(req.body.content);
res.send(`Treść oczyszczona: ${sanitizedContent}`);
});
Optymalizacja
Zarządzanie Błędami i Logowanie z Morganem
Morgan to middleware do logowania zapytań HTTP, który może pomóc w monitorowaniu ruchu w aplikacji.
Zainstaluj Morgan:
npm install morgan
Dodaj do aplikacji:
const morgan = require('morgan');
app.use(morgan('combined')); // Możesz użyć różnych formatów, np. 'tiny' dla mniejszych logów
Morgan pozwala na przechwytywanie wszystkich zapytań do aplikacji, co jest nieocenione w rozwiązywaniu problemów i monitorowaniu aplikacji produkcyjnej.
Cache’owanie Odpowiedzi i Kompresja
Cache’owanie
Cache’owanie odpowiedzi HTTP może znacznie zwiększyć wydajność aplikacji. Można to osiągnąć za pomocą nagłówków Cache-Control:
app.get('/data', (req, res) => {
res.set('Cache-Control', 'public, max-age=300');
res.json({ message: 'Cache\'owana odpowiedź!' });
});
Kompresja
Aby zmniejszyć rozmiar odpowiedzi i przyspieszyć ich przesyłanie, możesz użyć compression:
npm install compression
Dodaj compression do aplikacji:
const compression = require('compression');
app.use(compression());
Kompresja treści HTML, CSS, JS oraz innych zasobów znacznie przyspiesza czas odpowiedzi aplikacji.
Deployment
Przygotowanie Aplikacji do Wdrożenia
Przed wdrożeniem aplikacji należy upewnić się, że jest odpowiednio skonfigurowana do działania w środowisku produkcyjnym. Oto kilka kluczowych kroków:
Zmienna środowiskowa NODE_ENV: Ustaw
NODE_ENVnaproduction, aby wyłączyć zbędne logowanie i inne funkcje pomocnicze.Obsługa błędów: Utwórz middleware do obsługi błędów w aplikacji:
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ message: 'Coś poszło nie tak!' });
});
Wdrożenie na Platformie Chmurowej
Wdrożenie aplikacji można wykonać na kilku popularnych platformach, takich jak Heroku, AWS, czy DigitalOcean.
Wdrożenie na Heroku
Heroku jest jednym z najłatwiejszych rozwiązań do wdrożenia aplikacji Express.js:
Zainstaluj Heroku CLI: Pobierz i zainstaluj Heroku CLI.
Stwórz plik
Procfile: Heroku wymaga plikuProcfile, który informuje, jak uruchomić aplikację:
web: node index.js
- Deploy: Po skonfigurowaniu repozytorium Git, możesz wdrożyć aplikację za pomocą komend:
heroku login
git init
git add .
git commit -m "Wdrożenie aplikacji"
heroku create
git push heroku master
Wdrożenie na AWS
W przypadku AWS możesz użyć Elastic Beanstalk do wdrożenia aplikacji Express.js. Elastic Beanstalk automatyzuje wiele zadań związanych z konfiguracją środowiska.
Wdrożenie na DigitalOcean
Na DigitalOcean możesz skorzystać z dropletów, które są instancjami VPS. Zainstalowanie Node.js, MongoDB oraz skonfigurowanie nginx do przekierowywania zapytań to typowe zadania wdrożeniowe na DigitalOcean.
Konfiguracja Pliku .env i Zarządzanie Zmiennymi Środowiskowymi
Do zarządzania wrażliwymi informacjami, takimi jak klucze API czy dane do bazy danych, używamy plików .env. Aby obsługiwać zmienne środowiskowe, zainstaluj dotenv:
npm install dotenv
Stwórz plik .env:
PORT=3000
DB_CONNECTION=mongodb://localhost:27017/myapp
JWT_SECRET=myverysecretkey
Dodaj kod do aplikacji, aby odczytać zmienne środowiskowe:
require('dotenv').config();
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Serwer działa na porcie ${PORT}`);
});
Pamiętaj, aby nigdy nie commitować pliku .env do repozytorium — dodaj go do .gitignore.
Podsumowanie
Optymalizacja, bezpieczeństwo i wdrożenie aplikacji Express.js to kluczowe etapy, które decydują o sukcesie aplikacji w środowisku produkcyjnym. W tym artykule:
- Bezpieczeństwo Aplikacji: Omówiliśmy najlepsze praktyki bezpieczeństwa, użycie helmet.js oraz ochronę przed SQL Injection i XSS.
- Optymalizacja: Wprowadziliśmy Morgan do logowania, compression do zmniejszenia rozmiaru odpowiedzi oraz omówiliśmy cache’owanie.
- Deployment: Przedstawiliśmy proces przygotowania do wdrożenia i opcji wdrożenia na platformach takich jak Heroku, AWS, i DigitalOcean, a także zarządzanie zmiennymi środowiskowymi za pomocą dotenv.
Stosując te techniki, Twoja aplikacja będzie bardziej bezpieczna, wydajna i gotowa na wdrożenie do środowiska produkcyjnego.