security: round 3 hardening (CSRF double-submit, TRX MITM, container hardening)

This commit is contained in:
ZOMBIIIIIII
2026-05-12 01:47:58 +03:00
parent c8bc40af97
commit 8dc0855827
37 changed files with 1852 additions and 318 deletions

View File

@@ -1,4 +1,4 @@
-- CryptoWallet API — DB schema (idempotent, non-custodial v4.0)
-- CryptoWallet API — DB schema (idempotent, custodial v5.0)
CREATE TABLE IF NOT EXISTS users (
id VARCHAR(26) PRIMARY KEY,
@@ -17,13 +17,36 @@ CREATE TABLE IF NOT EXISTS users (
kyc_verified BOOLEAN NOT NULL DEFAULT FALSE,
kyc_verified_at TIMESTAMPTZ,
is_deleted BOOLEAN NOT NULL DEFAULT FALSE,
encrypted_vault TEXT, -- legacy, unused
vault_salt VARCHAR(128), -- legacy, unused
encrypted_mnemonic TEXT, -- legacy, unused
encrypted_vault TEXT, -- legacy
vault_salt VARCHAR(128), -- legacy
encrypted_mnemonic TEXT, -- AES-256-GCM blob (custodial)
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_name = 'users' AND column_name = 'encrypted_mnemonic'
) THEN
ALTER TABLE users ADD COLUMN encrypted_mnemonic TEXT;
END IF;
END $$;
-- AES-GCM blob: 12 IV + plaintext + 16 tag.
-- 12-word mnemonic ~ 116 байт = ~156 base64 chars; 24-word ~ 212 байт = ~284 chars.
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_constraint WHERE conname = 'users_encrypted_mnemonic_size'
) THEN
ALTER TABLE users
ADD CONSTRAINT users_encrypted_mnemonic_size
CHECK (encrypted_mnemonic IS NULL OR (char_length(encrypted_mnemonic) BETWEEN 140 AND 512));
END IF;
END $$;
CREATE TABLE IF NOT EXISTS wallets (
id VARCHAR(26) PRIMARY KEY,
user_id VARCHAR(26) NOT NULL REFERENCES users(id) ON DELETE CASCADE,
@@ -36,12 +59,6 @@ CREATE TABLE IF NOT EXISTS wallets (
CREATE INDEX IF NOT EXISTS idx_wallets_user_id ON wallets(user_id);
CREATE TABLE IF NOT EXISTS sessions (
id VARCHAR(26) PRIMARY KEY,
user_id VARCHAR(26) NOT NULL REFERENCES users(id) ON DELETE CASCADE,
expires_at TIMESTAMPTZ NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_sessions_user_id ON sessions(user_id);
CREATE INDEX IF NOT EXISTS idx_sessions_expires_at ON sessions(expires_at);
-- sessions table removed — JWT-stateless, не используется в коде.
-- Если существует от старой версии — оператор может drop вручную:
-- DROP TABLE IF EXISTS sessions CASCADE;