Implementing Security Best Practices

1. Preventing SQL Injection

// Safe — parameterized
await prisma.$queryRaw`SELECT * FROM "User" WHERE email = ${email}`;
// Safe composition
const where = Prisma.sql`WHERE role = ${role}`;
await prisma.$queryRaw`SELECT * FROM "User" ${where}`;
Warning: Never concatenate user input into $queryRawUnsafe. Use the tagged template form or Prisma.sql for safe parameterization.
APISafe?
$queryRaw`...`Yes — parameterized
$queryRawUnsafeOnly with sanitized input
Prisma.sqlComposable, parameterized

2. Sanitizing User Input

ToolDetail
Zod / ValibotSchema validation
class-validatorDecorator-based
DOMPurifyStrip HTML for rich text

3. Implementing Field-Level Security

const safe = prisma.$extends({
  result: {
    user: { passwordHash: { needs: { passwordHash: true }, compute: () => undefined } }
  }
});
StrategyDetail
Omit fieldsUse extension to strip secrets
Select allow-listDefault select in repo

4. Managing Database Credentials

PracticeDetail
Secrets managerAWS SM / Vault / Doppler
Never commitUse .env.* + gitignore
RotatePeriodic + on incident

5. Using Environment Variables

DATABASE_URL="postgresql://user:pass@host:5432/db?schema=public"
TipDetail
Per env.env.development, .env.test, .env.production
ValidateZod env schema on boot

6. Implementing Row-Level Security

ApproachDetail
PG RLSNative policies via raw SQL
App-leveltenantId filter via extension
SET LOCALPass user context per tx

7. Encrypting Sensitive Data

LayerDetail
At restDB TDE / disk encryption
Field-levelApp encrypts before insert (AES-GCM)
KMSAWS KMS / GCP KMS

8. Implementing Audit Logging

const audited = prisma.$extends({
  query: {
    $allModels: {
      async $allOperations({ model, operation, args, query }) {
        const result = await query(args);
        if (["create","update","delete"].includes(operation)) {
          await prisma.auditLog.create({ data: { model, op: operation, args: args as any } });
        }
        return result;
      }
    }
  }
});
StoreDetail
Same DBEasy joins, transactional
SeparateTamper resistance, scale
Append-onlyWORM storage / S3 Object Lock

9. Managing Database Permissions

PrincipleDetail
Least privilegeApp user ≠ migration user
GRANT/REVOKEPer schema/table
No superuserFor runtime

10. Implementing Rate Limiting

LayerDetail
API gatewayCloudflare / Kong / NGINX
App-levelexpress-rate-limit + Redis
DB-levelStatement timeout, connection cap