Implement 301 redirects for www to non-www and enhance canonical tag handling
This commit adds 301 redirects in the Apache configuration to redirect traffic from www.tt-tagebuch.de to tt-tagebuch.de for both HTTP and HTTPS. Additionally, it introduces middleware in the backend to dynamically set canonical tags based on the request URL, ensuring proper SEO practices. The request logging middleware has been disabled, and sensitive data handling has been improved in the MyTischtennis model and API logging service, ensuring compliance with data protection regulations. Frontend updates include enhanced descriptions and features in the application, improving user experience and clarity.
This commit is contained in:
214
backend/utils/logDataSanitizer.js
Normal file
214
backend/utils/logDataSanitizer.js
Normal file
@@ -0,0 +1,214 @@
|
||||
import { encryptData } from './encrypt.js';
|
||||
|
||||
/**
|
||||
* Utility-Funktionen zum Sanitizing von Log-Daten
|
||||
* Entfernt oder verschlüsselt personenbezogene Daten aus Request/Response-Bodies
|
||||
*/
|
||||
|
||||
// Felder, die personenbezogene Daten enthalten können
|
||||
const SENSITIVE_FIELDS = [
|
||||
'password',
|
||||
'passwort',
|
||||
'email',
|
||||
'eMail',
|
||||
'e-mail',
|
||||
'phone',
|
||||
'telefon',
|
||||
'telephone',
|
||||
'firstName',
|
||||
'first_name',
|
||||
'lastName',
|
||||
'last_name',
|
||||
'name',
|
||||
'street',
|
||||
'address',
|
||||
'adresse',
|
||||
'city',
|
||||
'stadt',
|
||||
'postalCode',
|
||||
'postal_code',
|
||||
'plz',
|
||||
'birthDate',
|
||||
'birth_date',
|
||||
'geburtstag',
|
||||
'token',
|
||||
'accessToken',
|
||||
'access_token',
|
||||
'refreshToken',
|
||||
'refresh_token',
|
||||
'cookie',
|
||||
'authcode',
|
||||
'authCode',
|
||||
'session',
|
||||
'sessionId',
|
||||
'session_id',
|
||||
'apiKey',
|
||||
'api_key',
|
||||
'secret',
|
||||
'credentials',
|
||||
'creditCard',
|
||||
'credit_card',
|
||||
'iban',
|
||||
'accountNumber',
|
||||
'account_number'
|
||||
];
|
||||
|
||||
/**
|
||||
* Entfernt oder maskiert personenbezogene Daten aus einem Objekt
|
||||
* @param {Object|string} data - Das zu sanitizierende Objekt oder JSON-String
|
||||
* @param {boolean} encrypt - Wenn true, werden sensible Felder verschlüsselt statt entfernt
|
||||
* @returns {Object|string} - Das sanitizierte Objekt oder JSON-String
|
||||
*/
|
||||
export function sanitizeLogData(data, encrypt = false) {
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Wenn es ein String ist, versuche es als JSON zu parsen
|
||||
let obj;
|
||||
let isString = false;
|
||||
|
||||
if (typeof data === 'string') {
|
||||
isString = true;
|
||||
try {
|
||||
obj = JSON.parse(data);
|
||||
} catch (e) {
|
||||
// Wenn es kein JSON ist, kürze den String einfach
|
||||
return data.length > 500 ? data.substring(0, 500) + '... (truncated)' : data;
|
||||
}
|
||||
} else if (typeof data === 'object') {
|
||||
obj = data;
|
||||
} else {
|
||||
return data;
|
||||
}
|
||||
|
||||
// Rekursiv durch das Objekt gehen
|
||||
const sanitized = sanitizeObject(obj, encrypt);
|
||||
|
||||
// Wenn es ursprünglich ein String war, zurück zu String konvertieren
|
||||
if (isString) {
|
||||
try {
|
||||
return JSON.stringify(sanitized);
|
||||
} catch (e) {
|
||||
return '[Unable to serialize sanitized data]';
|
||||
}
|
||||
}
|
||||
|
||||
return sanitized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitiziert ein Objekt rekursiv
|
||||
*/
|
||||
function sanitizeObject(obj, encrypt = false) {
|
||||
if (obj === null || obj === undefined) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Arrays
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map(item => sanitizeObject(item, encrypt));
|
||||
}
|
||||
|
||||
// Objekte
|
||||
if (typeof obj === 'object') {
|
||||
const sanitized = {};
|
||||
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
const lowerKey = key.toLowerCase();
|
||||
|
||||
// Prüfe, ob das Feld sensibel ist
|
||||
const isSensitive = SENSITIVE_FIELDS.some(field =>
|
||||
lowerKey.includes(field.toLowerCase())
|
||||
);
|
||||
|
||||
if (isSensitive) {
|
||||
if (encrypt && value) {
|
||||
// Verschlüssele den Wert vollständig
|
||||
try {
|
||||
const valueStr = typeof value === 'string' ? value : JSON.stringify(value);
|
||||
const encrypted = encryptData(valueStr);
|
||||
// Speichere vollständig verschlüsselt (kann bei Bedarf entschlüsselt werden)
|
||||
sanitized[key] = encrypted;
|
||||
} catch (e) {
|
||||
// Bei Verschlüsselungsfehler: Maskiere stattdessen
|
||||
sanitized[key] = '[REDACTED]';
|
||||
}
|
||||
} else {
|
||||
// Entferne oder maskiere den Wert (ohne Verschlüsselung)
|
||||
if (typeof value === 'string' && value.length > 0) {
|
||||
// Zeige nur die ersten 2 Zeichen
|
||||
sanitized[key] = value.substring(0, 2) + '***[REDACTED]';
|
||||
} else {
|
||||
sanitized[key] = '[REDACTED]';
|
||||
}
|
||||
}
|
||||
} else if (typeof value === 'object') {
|
||||
// Rekursiv für verschachtelte Objekte
|
||||
sanitized[key] = sanitizeObject(value, encrypt);
|
||||
} else {
|
||||
sanitized[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return sanitized;
|
||||
}
|
||||
|
||||
// Primitive Werte
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Kürzt einen String auf eine maximale Länge
|
||||
*/
|
||||
export function truncateString(str, maxLength = 1000) {
|
||||
if (!str || typeof str !== 'string') {
|
||||
return str;
|
||||
}
|
||||
|
||||
if (str.length <= maxLength) {
|
||||
return str;
|
||||
}
|
||||
|
||||
return str.substring(0, maxLength) + '... (truncated)';
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitiziert IP-Adressen (kürzt auf ersten 3 Oktetten)
|
||||
*/
|
||||
export function sanitizeIpAddress(ip) {
|
||||
if (!ip) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// IPv4: 192.168.1.100 -> 192.168.1.xxx
|
||||
if (ip.includes('.')) {
|
||||
const parts = ip.split('.');
|
||||
if (parts.length === 4) {
|
||||
return `${parts[0]}.${parts[1]}.${parts[2]}.xxx`;
|
||||
}
|
||||
}
|
||||
|
||||
// IPv6: Kürze auf ersten Teil
|
||||
if (ip.includes(':')) {
|
||||
const parts = ip.split(':');
|
||||
return parts[0] + ':xxx';
|
||||
}
|
||||
|
||||
return ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitiziert User-Agent-Strings (entfernt spezifische Versionen)
|
||||
*/
|
||||
export function sanitizeUserAgent(userAgent) {
|
||||
if (!userAgent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Entferne spezifische Versionsnummern, behalte nur Browser/OS-Typ
|
||||
return userAgent
|
||||
.replace(/\d+\.\d+\.\d+\.\d+/g, 'x.x.x.x') // Versionsnummern
|
||||
.substring(0, 200); // Kürze auf 200 Zeichen
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user