feat: Website-Rework mit verbessertem Design, Sicherheit und Deployment
- Neue About/Skills-Sektion hinzugefügt - Verbesserte UI/UX für alle Komponenten - Enhanced Contact Form mit Validierung - Verbesserte Security Headers und Middleware - Sichere Deployment-Skripte (safe-deploy.sh) - Zero-Downtime Deployment Support - Verbesserte Docker-Sicherheit - Umfassende Sicherheits-Dokumentation - Performance-Optimierungen - Accessibility-Verbesserungen
This commit is contained in:
@@ -40,11 +40,16 @@ export async function POST(request: NextRequest) {
|
||||
const adminAuth = process.env.ADMIN_BASIC_AUTH || 'admin:default_password_change_me';
|
||||
const [, expectedPassword] = adminAuth.split(':');
|
||||
|
||||
// Secure password comparison
|
||||
if (password === expectedPassword) {
|
||||
// Secure password comparison using constant-time comparison
|
||||
const crypto = await import('crypto');
|
||||
const passwordBuffer = Buffer.from(password, 'utf8');
|
||||
const expectedBuffer = Buffer.from(expectedPassword, 'utf8');
|
||||
|
||||
// Use constant-time comparison to prevent timing attacks
|
||||
if (passwordBuffer.length === expectedBuffer.length &&
|
||||
crypto.timingSafeEqual(passwordBuffer, expectedBuffer)) {
|
||||
// Generate cryptographically secure session token
|
||||
const timestamp = Date.now();
|
||||
const crypto = await import('crypto');
|
||||
const randomBytes = crypto.randomBytes(32);
|
||||
const randomString = randomBytes.toString('hex');
|
||||
|
||||
@@ -56,9 +61,9 @@ export async function POST(request: NextRequest) {
|
||||
userAgent: request.headers.get('user-agent') || 'unknown'
|
||||
};
|
||||
|
||||
// Encrypt session data
|
||||
// Encode session data (base64 is sufficient for this use case)
|
||||
const sessionJson = JSON.stringify(sessionData);
|
||||
const sessionToken = btoa(sessionJson);
|
||||
const sessionToken = Buffer.from(sessionJson).toString('base64');
|
||||
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
|
||||
@@ -3,18 +3,47 @@ import nodemailer from "nodemailer";
|
||||
import SMTPTransport from "nodemailer/lib/smtp-transport";
|
||||
import Mail from "nodemailer/lib/mailer";
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import { checkRateLimit, getRateLimitHeaders } from '@/lib/auth';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
// Sanitize input to prevent XSS
|
||||
function sanitizeInput(input: string, maxLength: number = 10000): string {
|
||||
return input
|
||||
.slice(0, maxLength)
|
||||
.replace(/[<>]/g, '') // Remove potential HTML tags
|
||||
.trim();
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
// Rate limiting
|
||||
const ip = request.headers.get('x-forwarded-for') || request.headers.get('x-real-ip') || 'unknown';
|
||||
if (!checkRateLimit(ip, 5, 60000)) { // 5 emails per minute per IP
|
||||
return NextResponse.json(
|
||||
{ error: 'Zu viele Anfragen. Bitte versuchen Sie es später erneut.' },
|
||||
{
|
||||
status: 429,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...getRateLimitHeaders(ip, 5, 60000)
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const body = (await request.json()) as {
|
||||
email: string;
|
||||
name: string;
|
||||
subject: string;
|
||||
message: string;
|
||||
};
|
||||
const { email, name, subject, message } = body;
|
||||
|
||||
// Sanitize and validate input
|
||||
const email = sanitizeInput(body.email || '', 255);
|
||||
const name = sanitizeInput(body.name || '', 100);
|
||||
const subject = sanitizeInput(body.subject || '', 200);
|
||||
const message = sanitizeInput(body.message || '', 5000);
|
||||
|
||||
console.log('📧 Email request received:', { email, name, subject, messageLength: message.length });
|
||||
|
||||
@@ -46,6 +75,14 @@ export async function POST(request: NextRequest) {
|
||||
);
|
||||
}
|
||||
|
||||
// Validate field lengths
|
||||
if (name.length > 100 || subject.length > 200 || message.length > 5000) {
|
||||
return NextResponse.json(
|
||||
{ error: "Eingabe zu lang" },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
const user = process.env.MY_EMAIL ?? "";
|
||||
const pass = process.env.MY_PASSWORD ?? "";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user