Update Apache SSL configuration and enhance security features across multiple files. Changed X-Frame-Options to SAMEORIGIN for better security, added optional Content Security Policy headers for testing, and improved password handling with HaveIBeenPwned checks during user registration and password reset. Implemented passkey login functionality in the authentication flow, including UI updates for user experience. Enhanced image upload processing with size limits and validation, and added rate limiting for various API endpoints to prevent abuse.
Some checks failed
Code Analysis (JS/Vue) / analyze (push) Failing after 51s
Some checks failed
Code Analysis (JS/Vue) / analyze (push) Failing after 51s
This commit is contained in:
@@ -1,9 +1,16 @@
|
||||
import crypto from 'crypto'
|
||||
|
||||
// Verschlüsselungskonfiguration
|
||||
const ALGORITHM = 'aes-256-cbc'
|
||||
const IV_LENGTH = 16
|
||||
// v1 (legacy): aes-256-cbc (ohne Authentizitätsschutz)
|
||||
const LEGACY_ALGORITHM = 'aes-256-cbc'
|
||||
const LEGACY_IV_LENGTH = 16
|
||||
|
||||
// v2 (default): aes-256-gcm (AEAD, state-of-the-art)
|
||||
const ALGORITHM = 'aes-256-gcm'
|
||||
const IV_LENGTH = 12
|
||||
const AUTH_TAG_LENGTH = 16
|
||||
const SALT_LENGTH = 32
|
||||
const VERSION_PREFIX = 'v2:'
|
||||
|
||||
/**
|
||||
* Generiert einen Schlüssel aus einem Passwort und Salt
|
||||
@@ -12,35 +19,87 @@ function deriveKey(password, salt) {
|
||||
return crypto.pbkdf2Sync(password, salt, 100000, 32, 'sha512')
|
||||
}
|
||||
|
||||
function encryptV2GCM(text, password) {
|
||||
// Salt generieren
|
||||
const salt = crypto.randomBytes(SALT_LENGTH)
|
||||
|
||||
// Schlüssel ableiten
|
||||
const key = deriveKey(password, salt)
|
||||
|
||||
// IV generieren (12 bytes ist Best Practice für GCM)
|
||||
const iv = crypto.randomBytes(IV_LENGTH)
|
||||
|
||||
// Cipher erstellen
|
||||
const cipher = crypto.createCipheriv(ALGORITHM, key, iv)
|
||||
|
||||
// Verschlüsseln
|
||||
const encrypted = Buffer.concat([
|
||||
cipher.update(text, 'utf8'),
|
||||
cipher.final()
|
||||
])
|
||||
|
||||
// Auth-Tag holen
|
||||
const tag = cipher.getAuthTag()
|
||||
|
||||
// Salt + IV + Tag + Ciphertext kombinieren
|
||||
const combined = Buffer.concat([salt, iv, tag, encrypted])
|
||||
|
||||
return `${VERSION_PREFIX}${combined.toString('base64')}`
|
||||
}
|
||||
|
||||
function decryptLegacyCBC(encryptedData, password) {
|
||||
// Base64 dekodieren
|
||||
const combined = Buffer.from(encryptedData, 'base64')
|
||||
|
||||
// Komponenten extrahieren (v1: salt(32) + iv(16) + ciphertext)
|
||||
const salt = combined.subarray(0, SALT_LENGTH)
|
||||
const iv = combined.subarray(SALT_LENGTH, SALT_LENGTH + LEGACY_IV_LENGTH)
|
||||
const encrypted = combined.subarray(SALT_LENGTH + LEGACY_IV_LENGTH)
|
||||
|
||||
// Schlüssel ableiten
|
||||
const key = deriveKey(password, salt)
|
||||
|
||||
// Decipher erstellen
|
||||
const decipher = crypto.createDecipheriv(LEGACY_ALGORITHM, key, iv)
|
||||
|
||||
// Entschlüsseln
|
||||
const decrypted = Buffer.concat([
|
||||
decipher.update(encrypted),
|
||||
decipher.final()
|
||||
])
|
||||
|
||||
return decrypted.toString('utf8')
|
||||
}
|
||||
|
||||
function decryptV2GCM(encryptedData, password) {
|
||||
const b64 = encryptedData.slice(VERSION_PREFIX.length)
|
||||
const combined = Buffer.from(b64, 'base64')
|
||||
|
||||
// v2: salt(32) + iv(12) + tag(16) + ciphertext
|
||||
const salt = combined.subarray(0, SALT_LENGTH)
|
||||
const iv = combined.subarray(SALT_LENGTH, SALT_LENGTH + IV_LENGTH)
|
||||
const tagStart = SALT_LENGTH + IV_LENGTH
|
||||
const tag = combined.subarray(tagStart, tagStart + AUTH_TAG_LENGTH)
|
||||
const encrypted = combined.subarray(tagStart + AUTH_TAG_LENGTH)
|
||||
|
||||
const key = deriveKey(password, salt)
|
||||
const decipher = crypto.createDecipheriv(ALGORITHM, key, iv)
|
||||
decipher.setAuthTag(tag)
|
||||
|
||||
const decrypted = Buffer.concat([
|
||||
decipher.update(encrypted),
|
||||
decipher.final()
|
||||
])
|
||||
|
||||
return decrypted.toString('utf8')
|
||||
}
|
||||
|
||||
/**
|
||||
* Verschlüsselt einen Text
|
||||
*/
|
||||
export function encrypt(text, password) {
|
||||
try {
|
||||
// Salt generieren
|
||||
const salt = crypto.randomBytes(SALT_LENGTH)
|
||||
|
||||
// Schlüssel ableiten
|
||||
const key = deriveKey(password, salt)
|
||||
|
||||
// IV generieren
|
||||
const iv = crypto.randomBytes(IV_LENGTH)
|
||||
|
||||
// Cipher erstellen
|
||||
const cipher = crypto.createCipheriv(ALGORITHM, key, iv)
|
||||
|
||||
// Verschlüsseln
|
||||
let encrypted = cipher.update(text, 'utf8', 'hex')
|
||||
encrypted += cipher.final('hex')
|
||||
|
||||
// Salt + IV + Verschlüsselter Text kombinieren
|
||||
const combined = Buffer.concat([
|
||||
salt,
|
||||
iv,
|
||||
Buffer.from(encrypted, 'hex')
|
||||
])
|
||||
|
||||
return combined.toString('base64')
|
||||
return encryptV2GCM(text, password)
|
||||
} catch (error) {
|
||||
console.error('Verschlüsselungsfehler:', error)
|
||||
throw new Error('Fehler beim Verschlüsseln der Daten')
|
||||
@@ -52,25 +111,12 @@ export function encrypt(text, password) {
|
||||
*/
|
||||
export function decrypt(encryptedData, password) {
|
||||
try {
|
||||
// Base64 dekodieren
|
||||
const combined = Buffer.from(encryptedData, 'base64')
|
||||
|
||||
// Komponenten extrahieren
|
||||
const salt = combined.subarray(0, SALT_LENGTH)
|
||||
const iv = combined.subarray(SALT_LENGTH, SALT_LENGTH + IV_LENGTH)
|
||||
const encrypted = combined.subarray(SALT_LENGTH + IV_LENGTH)
|
||||
|
||||
// Schlüssel ableiten
|
||||
const key = deriveKey(password, salt)
|
||||
|
||||
// Decipher erstellen
|
||||
const decipher = crypto.createDecipheriv(ALGORITHM, key, iv)
|
||||
|
||||
// Entschlüsseln
|
||||
let decrypted = decipher.update(encrypted, null, 'utf8')
|
||||
decrypted += decipher.final('utf8')
|
||||
|
||||
return decrypted
|
||||
if (typeof encryptedData === 'string' && encryptedData.startsWith(VERSION_PREFIX)) {
|
||||
return decryptV2GCM(encryptedData, password)
|
||||
}
|
||||
|
||||
// Fallback: legacy CBC ohne Prefix
|
||||
return decryptLegacyCBC(encryptedData, password)
|
||||
} catch (error) {
|
||||
console.error('Entschlüsselungsfehler:', error)
|
||||
throw new Error('Fehler beim Entschlüsseln der Daten')
|
||||
|
||||
Reference in New Issue
Block a user