Shang Gao
Guides
📋 ← Back to Home · 返回首页
Shang Gao www.shanggao.net
© 2000-2026 Shang Gao. All rights reserved. 未经书面许可,不得用于商业用途。
Read 19

Server Security Guide

Practical Server Hardening v1.0.0

Shang Gao 2026-09-18

1. Overview

概述

This guide documents the security practices applied to a PHP website on shared hosting. It's not exhaustive — but it covers the most common attack surfaces: exposed files, browsable directories, and improper access control.

本指南记录在共享主机上运行 PHP 网站时的安全实践。不追求面面俱到,只覆盖最常见的攻击面: 暴露的文件、可浏览的目录、访问控制不当。

Threat Model · 威胁模型

  • Direct file access: 攻击者直接访问 config.php、meta.php 等敏感文件
  • Directory listing: 攻击者浏览 /includes/、/cgi-bin/ 等目录,获取文件列表
  • URL guessing: 攻击者猜测私有文章的 URL,绕过前端隐藏
  • CGI abuse: 服务器上多余的 CGI 脚本被利用

2. File Protection

文件保护

Sensitive PHP files (configuration, metadata, shared functions) should not be directly accessible via HTTP. We use a load constant pattern: the file only executes if the caller has defined a specific constant.

Pattern · 模式

Protected file:

<?php if (!defined('ALLOW_CONFIG_LOAD')) { http_response_code(404); exit; } return [ ... ];

Caller:

define('ALLOW_CONFIG_LOAD', true); $config = require __DIR__ . '/config.php';

Protected Files · 受保护文件

File Constant
config.phpALLOW_CONFIG_LOAD
meta.phpALLOW_META_LOAD
includes/functions.phpALLOW_FUNCTIONS_LOAD
includes/site.phpALLOW_SITE_LOAD
Why 404, not 403?

403 Forbidden tells an attacker "something is here, you just can't access it". 404 Not Found reveals nothing. For sensitive files, use 404.

3. Directory Protection

目录保护

Disable Directory Listing · 禁止目录列表

By default, Apache may serve a directory listing when no index.php is present. Disable this globally:

Options -Indexes

Sensitive Directories · 敏感目录

For directories that should never be browsed — like includes/, phpmailer/, cgi-bin/ — add a .htaccess with:

Order deny,allow Deny from all

This returns 403 Forbidden for any direct access.

Directory-Specific Protection

Directory Protection
/includes/ .htaccess (Deny from all) + index.php (redirect)
/phpmailer/ .htaccess (Deny from all) + index.php (redirect)
/cgi-bin/ .htaccess (Deny from all)
/{category}/{slug}/assets/ index.php (redirect back to article)
Defense in depth

Using both .htaccess and index.php gives defense in depth: if one fails (server reconfiguration, etc.), the other still protects.

4. .htaccess Configuration

.htaccess 配置

Root .htaccess

Place in the website root directory:

# ============================================ # Security # ============================================ # Disable directory listing (site-wide) Options -Indexes # Protect sensitive files <FilesMatch "^(config\.php|config-sample\.php)$"> Order deny,allow Deny from all </FilesMatch>

Notes on FilesMatch · 关于 FilesMatch

  • require in PHP is a filesystem operation, not HTTP — FilesMatch won't block it.
  • FilesMatch only blocks direct URL access.
  • We do not use FilesMatch for meta.php — that file relies on its own PHP-level check (ALLOW_META_LOAD) to avoid interfering with load_posts().

Testing .htaccess · 测试

URL Expected
/includes/403
/includes/functions.php403
/phpmailer/403
/cgi-bin/403
/config.php403
/config-sample.php403
Nginx note

Nginx does not support .htaccess. On Nginx, equivalent rules go in the server block: location /includes/ { deny all; }.

5. Content Visibility

内容可见性

Visibility Levels · 可见性级别

Value Listing Detail page
publicShownAnyone
membersShown (future: by login)Logged-in members
privateHidden404
draftHidden404
Critical Rule · 关键规则

Front-end hiding ≠ back-end protection. Even if a private article is hidden from the listing, the detail page must independently check and return 404.

Server-side Check · 服务端检查

if (($meta['status'] ?? 'published') !== 'published') { http_response_code(404); exit; } if (($meta['visibility'] ?? 'public') === 'private') { http_response_code(404); exit; }

6. Error Responses

错误响应

Situation Response Reason
Permission denied (private/draft) 404 Do not reveal the resource exists
Missing configuration 500 Server error
Wrong HTTP method 405 Method not allowed
Direct access to protected file 404 or 403 404 for user-facing, 403 for server-level

7. Checklist

检查清单

File Protection

  • config.php has ALLOW_CONFIG_LOAD check
  • meta.php has ALLOW_META_LOAD check
  • includes/functions.php has ALLOW_FUNCTIONS_LOAD check
  • includes/site.php has ALLOW_SITE_LOAD check

Directory Protection

  • Options -Indexes in root .htaccess
  • /includes/ has .htaccess (Deny from all)
  • /includes/ has index.php (redirect)
  • /phpmailer/ has .htaccess + index.php
  • /cgi-bin/ has .htaccess (Deny from all)
  • /{category}/{slug}/assets/ has index.php

Content Security

  • Detail pages check status and visibility
  • private / draft return 404
  • Listing pages skip private / non-published

Test URLs · 测试 URL

URL Expected
/config.php403 or 404
/includes/403
/includes/functions.php403 or 404
/phpmailer/403
/cgi-bin/403
/milestones/26091300-.../assets/Redirect to article
/ (home page)200 OK
Send message formWorks normally
Book call formWorks normally

8. Future Improvements

未来改进方向

  • User system: registration, login, sessions for members content
  • Member checks: verify login state + membership level
  • Private assets: images/PDFs for private content via server-side reads
  • Watermark PDFs: embed member ID to trace leaks
  • Audit logs: who accessed what and when
  • Rate limiting: prevent brute force / spam on forms
  • CSRF tokens: on all POST forms
  • reCAPTCHA: alternative or additional layer for forms
  • HTTPS enforcement: redirect HTTP → HTTPS via .htaccess
  • Content Security Policy: restrict script sources

9. References

参考

  • Apache .htaccess Guide
  • OWASP Top 10
  • HTTP Status Codes (MDN)
  • PHP Security Manual

— End of Guide · 指南结束 —

© 2000-2026 Shang Gao. All rights reserved. 未经书面许可,不得用于商业用途。

© 2000-2026 Shang Gao. All rights reserved.