feat(security): Phase 1 — critical security fixes and hardening

- #42: Remove hardcoded ENCRYPTION_KEY fallback from config.js,
  add startup validation for BOT_TOKEN and ENCRYPTION_KEY length
- #43: Fix SQL injection vulnerabilities — add ALLOWED_TABLES
  whitelist in database.js, ALLOWED_USER_FIELDS in userService.js,
  validate table names before PRAGMA
- #44: Fix race condition in purchaseService.js — wrap createPurchase
  in BEGIN IMMEDIATE TRANSACTION, add atomic balance/stock checks
- #41: Move all secrets from docker-compose.yml to .env file,
  use env_file directive
- #45: Replace MD5 tx_hash with crypto.randomUUID()
- #46: Upgrade KDF from SHA-256 to HKDF for mnemonic encryption,
  add backward compatibility for legacy format
- #47: Add input validation across all handlers — walletType
  whitelist, string length limits, numeric ID checks, price bounds

New files:
- src/utils/encryption.js (HKDF key derivation)
- src/__tests__/security.test.js (SQL injection prevention tests)

Closes: #41, #42, #43, #44, #45, #46, #47
This commit is contained in:
NW
2026-06-17 21:52:49 +01:00
parent d1503a0180
commit de415633be
17 changed files with 360 additions and 154 deletions

View File

@@ -4,6 +4,11 @@ import db from "../config/database.js";
import Wallet from "../models/Wallet.js";
import WalletUtils from "../utils/walletUtils.js";
const ALLOWED_USER_FIELDS = new Set([
'telegram_id', 'username', 'country', 'city',
'district', 'status', 'total_balance', 'bonus_balance'
]);
class UserService {
// Функция для нормализации telegram_id
@@ -44,10 +49,14 @@ class UserService {
}
// Подготавливаем данные для вставки в базу данных
const fields = Object.keys(userData);
const values = Object.values(userData);
const fields = Object.keys(userData).filter(key => ALLOWED_USER_FIELDS.has(key));
const values = fields.map(key => userData[key]);
const marks = Array(fields.length).fill('?');
if (fields.length === 0) {
throw new Error('No valid fields provided for user creation');
}
const query = `
INSERT INTO users (${fields.join(', ')})
VALUES (${marks.join(', ')})