Web Development

Secure Web Development: Practical Controls Every Business Site Needs

Published September 4, 2026 Scriplit

Secure web development for a small business site is a set of ordinary controls, not a special product you buy once. HTTPS, careful handling of input, hashed passwords, and least-privilege hosting stop the failures that actually show up: dumped databases, defaced homepages, and stolen session cookies. You do not need a security theatre slide deck. You need a short list of habits that survive a busy month.

Start with the boring perimeter

Every public site should redirect HTTP to HTTPS, use a certificate that auto-renews, and refuse mixed content. Turn off directory listing. Do not leave phpinfo, installer folders, or sample configs on production. Keep error messages generic in public; log details on the server. These steps will not impress a conference audience. They close the doors that automated scanners try first.

Admin URLs deserve extra friction: unique logins (no shared “admin/admin”), two-factor authentication if the host or CMS offers it, and an allowlist of who still has access after a contractor finishes. Former developers with live SSH keys are a recurring incident type. A yearly access review belongs on the same calendar as website maintenance.

Treat every form as hostile input

Contact forms, search boxes, file uploads, and webhook endpoints all accept data from the internet. The rule is the same: validate type and length, encode output for the context (HTML, SQL, shell), and never concatenate untrusted strings into queries or commands. In PHP that usually means prepared statements, htmlspecialchars on output, and a whitelist of upload MIME types stored outside the web root or behind an authorized download script.

  • SQL: bound parameters, never string-built queries with request data.
  • HTML: escape on output; do not “sanitize until it looks safe” as your only defence.
  • Files: random stored names, size caps, and no executing uploads as PHP.
  • Redirects: only allow relative paths or a fixed list of hosts.
  • CSRF: tokens on state-changing forms for logged-in users; same-site cookies help but are not a complete plan.

Authentication without inventing a protocol

If people log in, hash passwords with a modern algorithm (password hashing APIs in PHP, not a homemade SHA-256). Session cookies should be HTTPS-only, have a sensible lifetime, and be regenerated after login. Rate-limit login and password-reset endpoints so a script cannot spray the form all night. Store reset tokens as hashes, not as reusable secrets in email logs.

Do not roll your own “remember me” scheme if a well-tested library or platform feature exists. Do not put API keys or session tokens in JavaScript that ships to the browser unless those credentials are designed to be public (a Stripe publishable key is; a secret key is not). Payment-specific handling is covered in payment security for websites — the short version is that your server should never see raw card numbers.

Roles are a business decision written in code

A receptionist who can update job status should not be able to export the full customer list. An editor who can publish pages should not have FTP. Encode that in the application, then test it by logging in as each role. Security bugs in small apps are often “the intern template still queries every row.” Write the query with the user’s scope from the start.

Dependencies and secrets

Most sites are a pile of other people’s code. Pin versions, apply patches, and delete plugins you do not use. One abandoned WordPress plugin with a known exploit is enough. Custom PHP apps have the same problem via Composer packages. Subscribe to security notices for the platform you actually run, not for a generic “cyber” newsletter.

Secrets belong in environment configuration, not in git. Rotate them when someone with access leaves. If a secret leaked into a chat log, treat it as public and replace it. This is unglamorous work and it prevents the screenshot-of-the-.env incident.

Control What it prevents Typical owner
HTTPS and HSTS Trivial interception on public Wi-Fi Host / DNS
Prepared statements Classic SQL injection on forms Developer
Password hashing + 2FA Credential stuffing on admin logins Developer + owner
Least-privilege DB user A web bug becoming a full database wipe Host / developer
Offsite backups Ransomware or a bad deploy ending the business week Owner of hosting
Content Security Policy (start strict, then tune) Some classes of injected script Developer

Third-party scripts are part of your attack surface

Chat widgets, tag managers, and “free” analytics extras run with the privileges of your page. Prefer loading them after you know they are needed. Review what they collect if you publish a privacy notice. A compromised third-party JavaScript file can become your homepage. That is an argument for fewer tags, not for more security products that add yet another tag.

What to do when something looks wrong

Have a short incident list before you need it: who can take the site offline, who can rotate keys, who talks to customers if a form leaked emails. Preserve logs. Do not quietly restore from backup over evidence if you may need to understand the hole. After you are stable, patch the cause, then rotate secrets that might have been read.

  1. Take a snapshot or copy of logs before you “clean” anything.
  2. Rotate host, database, CMS, and API credentials that could have been exposed.
  3. Audit admin users and scheduled tasks (cron, WP-Cron, systemd timers).
  4. Search the web root for files you did not deploy.
  5. Write down what you changed so the next incident is shorter.

Scriplit is not a penetration-testing firm. We build and maintain sites with these controls as a default part of web development services. If you want a review of an existing PHP or CMS site, send the stack and whether you have staging through the web development contact form. Do not email production passwords; arrange a proper hand-off.