"Use strong passwords" is not a security practice. It is hygiene. When I review the security posture of B2B web applications, the gaps I find are almost never about password strength — they are about structural decisions that were made (or skipped) during the design phase and never revisited.
Here are the seven practices I treat as non-negotiable on every production B2B system I build or audit.
1. Parameterized Queries — Always, Without Exception
SQL injection remains one of the most common and most damaging attack vectors in web applications. The fix is not complicated: never concatenate user input into a SQL string. Use parameterized queries or an ORM that generates them for you.
With Entity Framework Core or Dapper in .NET, you get parameterization by default as long as you use the provided query APIs correctly. The danger zone is raw string interpolation — $"SELECT * FROM users WHERE email = '{input}'" — which hands an attacker a direct line to your database. I review every data access layer in an audit specifically looking for this pattern.
2. Principle of Least Privilege on Database Accounts
The application's database user should have only the permissions it needs to do its job — nothing more. A read-heavy reporting service should not have INSERT, UPDATE, or DELETE permissions. The main application user should not be the database owner. A user that only needs to read one table should not have access to the entire schema.
This limits blast radius. If an attacker compromises the application layer and escalates to the database connection, they get exactly what that connection can do — not the keys to the entire database. I set this up at the database level, not the application level.
3. Encryption at Rest
For B2B applications handling client data, PII, or anything subject to GDPR, HIPAA, or similar — encryption at rest is mandatory. On AWS RDS this is a checkbox at provisioning time (enable it; there is no performance excuse not to). On SQL Server, Transparent Data Encryption (TDE) encrypts the underlying data files.
Encryption at rest does not protect against a compromised application with valid credentials. It protects against physical theft of storage media, backup file exfiltration, and certain classes of cloud misconfiguration. It is not sufficient by itself, but it is necessary.
4. TLS in Transit — Including Internal Traffic
Encrypt the connection between your application server and your database. This is standard for internet-facing traffic but routinely skipped for internal VPC traffic on the assumption that the network perimeter is sufficient protection.
It is not. If an attacker gains access to your network (through a compromised EC2 instance, a misconfigured security group, or a supply chain compromise), unencrypted internal database traffic is readable with a packet capture. Enabling TLS on RDS connections is a configuration change, not a development effort.
5. VPC Isolation and Security Group Hygiene
Your database should never be directly reachable from the internet. Full stop. In AWS, this means placing RDS instances in private subnets with no route to the internet gateway, and configuring security groups to allow inbound traffic only from your application tier's security group — not from a CIDR range, and certainly not from 0.0.0.0/0.
I routinely find databases in B2B systems that were provisioned "temporarily" with public access enabled and a wide-open security group, then promoted to production without ever being locked down. A misconfigured security group is one of the most common causes of cloud data breaches.
6. Row-Level Security for Multi-Tenant Data
If your B2B application serves multiple organizations from a single database schema (the most common architecture for SaaS and B2B portals), you need to ensure that one tenant cannot access another tenant's data.
Row-Level Security (RLS) in PostgreSQL and SQL Server lets you define access policies at the database engine level — the database itself enforces tenant isolation, independently of whatever the application layer does. This means a bug in your application's tenant-filtering logic does not automatically become a data breach. It is a defense-in-depth layer that I implement on every multi-tenant system.
7. Secrets Management — No Credentials in Code or Config Files
Database connection strings, API keys, and service account credentials should never appear in your source code, .env files committed to a repository, or unencrypted configuration files on a server.
In AWS environments I use AWS Secrets Manager or SSM Parameter Store with IAM roles. The application instance has an IAM role that allows it to read specific secrets — no credentials are stored on the instance at all. Secrets rotation is automated. Access to secrets is logged via CloudTrail.
This single practice prevents an entire class of credential exposure incidents — including the extremely common scenario where a junior developer accidentally commits a .env file to a public GitHub repository.
These seven practices are the baseline. They are not advanced security — they are the minimum standard for a B2B system handling client data in 2025. If your current system is missing any of them, that is a remediation project, not a nice-to-have.
For deeper treatment of how database design decisions affect both security and performance, my post on database bottlenecks in SMBs covers the structural side. And if you need a security review of an existing system, reach out.