Keep secrets out of public output
Database credentials, API keys, mail passwords, and administrative tokens should never be displayed in error messages or committed to public repositories. On production systems, detailed exceptions belong in private logs.
Where hosting allows it, keep configuration outside the public web directory or load secrets from environment configuration. On shared hosting where that is difficult, at minimum restrict direct web access to configuration files and keep file permissions tight.
- Never echo database exception messages to visitors.
- Do not place credentials in JavaScript.
- Restrict direct access to configuration and backup files.
Use prepared statements for database input
Prepared statements separate SQL structure from user-supplied data and are the normal defense against SQL injection. Every query that includes form, URL, cookie, or API input should use parameter binding rather than string concatenation.
Validation still matters because prepared statements do not determine whether a value is appropriate for the business rule. Validate format, length, and allowed values before storing data.
- Bind user input as parameters.
- Validate expected length and format.
- Use allow-lists for fields such as role, status, or sort direction.
Escape output in the correct context
Data that is safe to store is not automatically safe to render. Escape text before inserting it into HTML, and use context-appropriate handling for attributes, URLs, JavaScript, and CSS.
For PHP-generated HTML, htmlspecialchars with the correct encoding is a strong default for ordinary text. Rich HTML content requires a controlled sanitization strategy rather than simply disabling escaping.
- Escape dynamic text in HTML.
- Do not trust database content merely because it was entered by an administrator.
- Avoid inline JavaScript built from untrusted values.
Protect sessions and forms
Authentication needs secure cookies, session regeneration after login, authorization checks on every protected page, and CSRF protection for state-changing requests. Logging in is not enough if a user can change the URL to access another role's page.
Forms should also limit input sizes and apply rate controls where abuse is likely. Contact forms can use CSRF tokens, spam controls, and server-side validation.
- Regenerate session IDs after successful login.
- Check authorization server-side on each admin action.
- Use Secure, HttpOnly, and suitable SameSite cookie settings over HTTPS.
- Use CSRF protection for changes and submissions.
Restrict uploads and executable files
File upload features require special care. Check file type using server-side inspection, limit size, generate safe filenames, and store uploads where they cannot be executed as PHP scripts.
Do not trust the original extension or browser-provided MIME type alone. If users only need images or documents, explicitly allow those types.
- Allow only required file types.
- Store uploads with generated filenames.
- Prevent script execution in upload directories.
Maintain, log, and recover
Security is an operating process. Keep PHP and dependencies supported, review logs for repeated failures, protect hosting and domain accounts with multi-factor authentication, and maintain restorable backups.
A checklist is only useful when it is repeated. Add a monthly or quarterly review that covers updates, users, backups, certificates, and unexpected public files.
- Patch supported runtime and libraries.
- Review admin accounts and access.
- Test backups.
- Monitor expiry dates for domains and certificates.
- Check public directories for old archives, SQL dumps, or debug files.