sheep 发表于 2026-7-20 15:21:36

《服务器安全配置与运维规范》〔2026〕

的🔥 服务器安全配置与运维规范(20260720)🔥

⚠️ 重要总则 ⚠️
🚫 服务器内禁止存放任何密码
🔐 所有业务使用20位以上随机密码
   - 组合要求:大写字母、小写字母、数字、特殊符号(!@#$%^&*()_+-=[]{}|;:,.?~)
   - 账号密码全部独立区分:root、宝塔、网站后台、数据库、安全软件


[*]9sK&p2G!vR7#qLz@dF8*jT5
[*]B3_xrQ6%mS1+cwZ4~ahD9(
[*]P7{gkE2$tjN8|fyA0:buH3
[*]5V,djR9^szU1[pxG4?evK7
[*]M2#ncY8-lbQ3.rdW6}igX0


---

📌 基础安全配置项
1. 🖥️ SSH设置:开启密钥登录,彻底关闭密码登录
2. 🧰 运行环境版本:Nginx1.31、PHP8.2、MySQL8.4,关闭所有不必要模块

# 一、Nginx 1.31 模块:必开模块 & 禁用冗余/危险模块
## (一)建议**保留开启**的核心模块(业务必备)
### 基础核心模块(默认启用,不可关闭)
1. `ngx_core_module`:Nginx 核心基础模块,进程、配置、内存管理,必开
2. `ngx_events_module`:事件驱动模型,网络连接调度,必开
3. `ngx_http_module`:HTTP 服务主模块,网站运行核心,必开

### Web 业务常用功能模块(根据站点场景选择性开启)
1. `ngx_http_access_module`:IP 访问控制,配合IP白名单使用,**必开**
2. `ngx_http_auth_basic_module`:基础账号验证,后台/私密站点可用
3. `ngx_http_log_module`:访问日志、错误日志,安全审计/故障排查,**必开**
4. `ngx_http_gzip_module`:资源压缩,提升访问速度,**常规站点必开**
5. `ngx_http_proxy_module`:反向代理、负载均衡,PHP/后端接口转发,**绝大多数业务必开**
6. `ngx_http_fastcgi_module`:对接 PHP-FPM 运行PHP程序,**PHP站点强制开启**
7. `ngx_http_rewrite_module`:URL伪静态、跳转、重定向,网站优化/路由必备,**必开**
8. `ngx_http_ssl_module`:HTTPS/SSL/TLS 加密,全站HTTPS场景**必开**
9. `ngx_http_vhost_module`:多虚拟主机配置,一台服务器多站点,**必开**
10. `ngx_http_headers_module`:自定义响应头、安全响应头(防XSS、防盗链),**安全加固必开**

## (二)建议**关闭/禁用**的非必要、高危、冗余模块
### 1. 高危/易被利用模块(优先关闭)
1. `ngx_http_autoindex_module`:目录浏览功能,攻击者可遍历服务器文件,**无特殊需求强制关闭**
2. `ngx_http_dav_module`:WebDAV 文件读写,可直接通过网页上传文件,**高危,一律关闭**
3. `ngx_http_cgi_module`:传统CGI解析,老旧漏洞多、几乎淘汰,**关闭**
4. `ngx_http_ssi_module`:服务器端包含(SSI),存在代码注入风险,**无老站点需求则关闭**

### 2. 小众/冗余功能模块(普通业务全部关闭)
1. `ngx_http_flv_module`/`ngx_http_mp4_module`:音视频流媒体模块,非视频站点**关闭**
2. `ngx_http_memcached_module`:对接Memcached缓存,未使用该缓存则**关闭**
3. `ngx_http_uwsgi_module`/`ngx_http_scgi_module`:Python/小众网关协议,仅PHP站点**关闭**
4. `ngx_http_geoip_module`:IP地域解析,未做地域限制/分流则**关闭**
5. `ngx_http_random_index_module`:随机主页,无用功能,**关闭**
6. `ngx_http_sub_module`/`ngx_http_sub_filter_module`:内容替换过滤,无定制需求**关闭**
7. `ngx_mail_module`:邮件代理模块,服务器不做邮件服务**强制关闭**
8. `ngx_stream_module`:四层TCP/UDP代理,仅做Web业务**关闭**

---

# 二、PHP 8.2 模块/扩展:必开扩展 & 禁用危险/冗余扩展
> 说明:PHP 安全核心原则:**最小化安装,禁用危险函数+冗余扩展**,搭配运行环境关闭非必要模块。

## (一)建议**保留开启**的核心扩展(PHP站点必备)
### 通用基础扩展(所有站点必开)
1. `curl`:网络请求、接口调用,主流业务必备
2. `fileinfo`:文件类型检测,文件上传安全校验,**必开**
3. `mbstring`:多字节字符串处理,中文、UTF-8站点**必开**
4. `openssl`:加密、HTTPS、签名验签,接口/支付/登录**必开**
5. `pdo` + `pdo_mysql`:MySQL数据库PDO驱动,主流数据库连接,**必开**
6. `mysqli`:传统MySQLi驱动(兼容老程序,按需保留)
7. `json`:JSON数据解析,接口、前后端交互**必开**
8. `gd`/`imagick`:图片处理(缩略图、水印、验证码),图片站点/后台**按需开启**
9. `zip`:压缩包解压/打包,备份、文件上传下载常用

## (二)建议**关闭/禁用**的扩展(高危、老旧、无用)
### 1. 高危风险扩展(强制关闭)
1. `eval`(函数,非扩展,php.ini禁用):代码执行漏洞重灾区,**禁用函数**
2. `system`/`exec`/`passthru`/`shell_exec`/`popen`:系统命令执行函数,**全部禁用**
3. `proc_open`:进程调用,高危,**禁用**
4. `ldap`:目录访问协议,未对接LDAP账号系统**关闭**
5. `ftp`/`ftps`:FTP协议扩展,规范要求FTP临时使用,**常态关闭**
6. `sockets`:原生Socket通信,非Socket服务**关闭**

### 2. 老旧/淘汰扩展(一律关闭)
1. `mysql`(传统mysql扩展):已废弃、漏洞极多,**强制关闭**(只用pdo/mysqli)
2. `mcrypt`:老旧加密扩展,PHP高版本已废弃,**关闭**
3. `ereg`/`eregi`:正则旧函数,已淘汰,**关闭**

### 3. 小众冗余扩展(普通业务关闭)
1. `gmp`、`bcmath`:数学高精度计算,金融/算法场景才用,普通站点**关闭**
2. `redis`/`memcached`:缓存扩展,未部署对应缓存服务**关闭**
3. `soap`:WebService接口,无对接第三方SOAP接口**关闭**
4. `exif`:图片EXIF信息读取,无需求**关闭**
5. `calendar`、`dba`、`ibase`、`oci8`、`pgsql`:小众数据库/日历功能,**全部关闭**

---

# 三、MySQL 8.4 模块/组件:必开组件 & 禁用高危/冗余组件
## (一)建议**保留开启**的核心组件/插件(数据库必备)
1. `InnoDB` 存储引擎:默认引擎,事务、行锁、崩溃恢复,**强制默认开启,唯一主力引擎**
2. `mysql_native_password`:原生密码认证插件,常规账号登录必备
3. `performance_schema`:性能监控、慢查询、会话审计,运维巡检**必开**
4. `information_schema`:系统元数据查询,运维、程序查询库表必备,**不可关闭**
5. `slow_query_log`:慢查询日志,故障排查、性能优化,**建议开启**
6. `error_log`:错误日志,安全告警、故障定位,**必开**
7. `binlog`:二进制日志,数据恢复、主从同步、操作审计,**生产环境必开**

## (二)建议**关闭/禁用**的组件、引擎、功能
### 1. 废弃/不安全存储引擎(强制关闭)
1. `MyISAM`:无事务、表锁、崩溃易丢数据,**仅历史老库兼容,新业务彻底禁用**
2. `MEMORY`(HEAP):内存表,数据断电丢失,无特殊临时业务**关闭**
3. `ARCHIVE`、`BLACKHOLE`、`FEDERATED`、`CSV`:小众引擎,漏洞多、几乎不用,**全部关闭**

### 2. 高危网络/远程功能(配合端口管控,关闭对应模块)
1. **远程访问模块**:限制仅本地+内网IP访问,关闭**全域远程连接**(对应禁用3306公网端口)
2. `mysqlx`(X Protocol):MySQL X协议端口,非专用开发**关闭**
3. `rpl_semi_sync`:半同步复制,无主从架构**关闭**
4. 匿名账号、测试库 `test`:初始化后**删除/禁用**(安全基础)

### 3. 冗余插件&功能
1. `audit_log`(审计插件):若无等保/强制审计需求,可关闭;合规环境按需开启
2. `thread_pool`:线程池插件,单服务器负载不高**关闭**
3. `load_file`/`into outfile`:文件读写函数,可被脱库、读取服务器文件,**权限层面禁用**
4. 分区、表空间高级组件:普通业务无分库分表**关闭冗余分区模块**
5. 全文检索插件:MySQL原生全文检索性能差,已用ES等则**关闭**

---

# 四、补充落地配置建议(结合你整体运维规范)
1. 所有模块遵循 **最小安装原则**:只开业务**当下必须**的模块,多余一律关闭
2. 模块关闭后重启对应服务(Nginx/PHP-FPM/MySQL),并验证业务可用性
3. 结合端口管控:关闭模块 + 防火墙封禁高危端口(21、23、3306、6379等)双重防护
4. 定期巡检:每次版本升级、漏洞修复后,复核模块状态,防止更新后冗余模块被重新启用

3. 🛡️ IP白名单:SSH、RDP、宝塔、安全软件、API接口等全部添加IP白名单
4. 🌐 海外IP管控:全域封禁国外IP,仅放行主流搜索引擎、AI访问


### 1)UA 白名单(Nginx / 宝塔防火墙)

```
~*Googlebot
~*GPTBot
~*OAI-SearchBot
~*ChatGPT-User
~*Bingbot
~*Meta-ExternalAgent
~*facebookexternalhit
~*Instagram
~*ClaudeBot
~*Claude-Web
~*PerplexityBot
~*Perplexity-User
~*Redditbot
```

### 2)IP 白名单(仅放官方固定段)

```
# Google / Gemini
66.249.64.0/19
2001:4860:4801::/48

# OpenAI (GPTBot)
208.68.234.0/24
208.68.236.0/24

# Bing
20.191.45.0/24
20.191.47.0/24
40.80.0.0/12

# Claude / Anthropic
160.79.104.0/23
2607:6bc0::/48
```


5. 🚪 端口管理:仅放行业务必需端口,禁用高危端口(21、23、3389、3306、6379、22默认端口等)


✅ **公网仅建议放行端口**(最小化原则)
1. **80** 标准 HTTP
2. **443** 标准 HTTPS

# 服务器端口安全清单(格式:端口 | 建议 | 服务 | 风险说明)
## 一、原有高危端口(强制公网封禁)
21 | 公网永久封禁 | FTP 文件传输 | 账号密码明文传输,易被抓包、暴力破解,常被用于上传木马、篡改文件
23 | 公网永久封禁 | Telnet 远程登录 | 全程无加密,明文传输所有操作与账号,入侵风险极高
22 | 修改为自定义冷门端口+IP白名单,封禁默认22 | SSH 远程连接 | 默认端口被全网高频扫描,易遭遇暴力破解、弱口令入侵
3306 | 公网永久封禁,仅内网/本地访问 | MySQL 数据库 | 公网暴露易被爆破、脱库、删库,注入攻击高发
3389 | 公网永久封禁 | Windows RDP 远程桌面 | 黑客重点扫描端口,暴力破解、勒索病毒、远程控机重灾区
6379 | 公网永久封禁,仅内网/本地访问 | Redis 缓存数据库 | 默认无身份验证,攻击者可远程写入木马、提权、接管服务器

## 二、一级高危端口(通用业务**强制公网封禁**)
135 | 公网永久封禁 | Windows RPC 远程过程调用 | 配合445端口实施漏洞攻击、横向渗透,蠕虫病毒常用入口
139 | 公网永久封禁 | NetBIOS 网络协议 | 泄露主机信息,易被探测、暴力破解,联动入侵Windows主机
445 | 公网永久封禁 | SMB 文件共享服务 | 永恒之蓝漏洞、勒索病毒、蠕虫主要利用端口,全网高危
1433/1434 | 公网永久封禁,仅内网访问 | SQL Server 数据库 | 公网暴露极易被爆破、拖库、执行恶意SQL语句
27017/27018 | 公网永久封禁,仅内网访问 | MongoDB 数据库 | 多数默认无密码,大量服务器遭遇删库、勒索、数据泄露
11211 | 公网永久封禁 | Memcached 缓存 | 易被利用发起DDoS放大攻击,存在未授权访问漏洞
8080 | 公网永久封禁,非业务禁用 | 备用Web/代理端口 | 黑客批量扫描首选备用网站端口,易遭受攻击、爬虫轰炸
8081/8082 | 公网永久封禁,非业务禁用 | 辅助Web服务端口 | 非常规Web端口,无业务需求直接封堵,减少攻击面

## 三、二级风险端口(非必需**全部公网封禁**,仅内网白名单按需放行)
20 | 公网永久封禁 | FTP 数据传输端口 | 配合21端口使用,禁用FTP则同步封禁,避免文件传输风险
1080 | 公网永久封禁 | Socks 代理服务 | 易被当作网络攻击、翻墙跳板,沦为肉鸡节点
2049 | 公网永久封禁 | NFS 网络文件共享(Linux) | 未授权可挂载服务器目录,造成文件泄露、篡改、越权访问
3690 | 公网永久封禁 | SVN 版本控制服务 | 极易泄露网站源码、配置文件、账号密码,源码泄露重灾区
5900-5910 | 公网永久封禁 | VNC 图形远程桌面 | 暴力破解风险高,攻击者可直接劫持桌面、操控服务器
6380-6385 | 公网永久封禁 | Redis 集群端口 | 仅集群内网使用,公网开放会扩大Redis入侵风险
161/162 | 公网永久封禁 | SNMP 网络监控协议 | 明文传输服务器硬件、服务、账号信息,方便攻击者探测架构
3307-3310 | 公网永久封禁 | MySQL 备用/集群端口 | 数据库附属端口,公网无需求直接封堵,防止数据库探测

## 四、小众风险/冗余端口(Web业务**一律公网封禁**)
25/465/110/995/143/993 | 公网永久封禁 | 邮件服务(SMTP/POP3/IMAP) | 非邮件业务无需开启,易被垃圾邮件、邮件病毒利用
873 | 公网永久封禁 | Rsync 文件同步 | 存在未授权访问漏洞,可遍历、下载、篡改服务器全部文件
1521 | 公网永久封禁 | Oracle 数据库 | 企业级数据库,公网暴露易被爆破、入侵、数据窃取
6667 | 公网永久封禁 | IRC 即时通讯服务 | 僵尸网络、肉鸡集群常用通信端口,恶意程序高频使用
7001/7002 | 公网永久封禁 | WebLogic 中间件 | 历史高危漏洞繁多,是黑客重点扫描和利用的中间件端口
9000/9001 | 公网永久封禁 | PHP-FPM/代理管理端口 | 公网暴露可被利用执行任意代码,远程代码执行高危漏洞端口
8888 | 公网封禁,仅IP白名单放行 | 宝塔面板默认端口 | 面板禁止对公网全开,防止面板被爆破、越权登录

## 五、Web业务**唯一允许公网放行**端口(核心业务端口)
80 | 永久公网放行 | HTTP 网页服务 | 网站标准访问端口,Web业务必需,配合防火墙做访问管控
443 | 永久公网放行 | HTTPS 加密网页服务 | 加密网站标准端口,全站HTTPS必备,安全优先级高于80

## 六、管理类端口(禁止公网全开,仅IP白名单放行)
自定义SSH端口 | 仅IP白名单放行 | SSH 远程管理 | 替换默认22端口,仅运维固定IP访问,杜绝全网扫描爆破
自定义面板端口 | 仅IP白名单放行 | 运维管理面板 | 隐藏默认端口,严格限制访问IP,防止面板入侵


6. 🔥 多层防火墙:系统防火墙+云防火墙+宝塔防火墙联动,统一拦截未授权端口访问
7. 📂 文件权限加固
   - Linux系统:所有程序文件执行 `chattr +i` 锁定

-R包含子目录,去掉则仅针对当前目录
加锁、解锁:
chattr -R +i /wwwchattr -R -i /www查看状态:
# 查看目录本身
lsattr /www

# 递归查看全部文件状态
lsattr -R /www
可放宝塔计划任务:
#!/bin/bash
chattr -R +i /www
echo "/www 目录已完成全局加锁"

#!/bin/bash
chattr -R -i /www
echo "/www 目录已完成全局解锁"

   - Windows系统:程序文件设置NTFS只读权限


# Windows 业务目录(D:\\www)NTFS 权限 + 只读属性 加固手册

适用:文件系统**必须为 NTFS**,所有命令需**右键 → 以管理员身份**运行 CMD / PowerShell
涉及主体用户组:`system`、`www`、`administrators`

---

## 一、环境前置要求

1. 分区格式:目标目录所在磁盘**必须是 NTFS 文件系统**,FAT32 不支持 NTFS 权限管控。
2. 运行权限:所有命令**务必使用管理员身份**打开 CMD/PowerShell 执行,普通用户权限不足。
3. 目录路径:示例统一使用 `D:\www`,可根据实际路径自行替换。

---

## 二、完整加锁命令(日常防护:只读防篡改、防删除)

### 作用说明

- `administrators`(管理员组):拥有完全控制权限,正常运维操作
- `system`(系统账户)、`www`(网站运行账户):仅读取 + 执行,禁止写入、删除
- 叠加文件只读属性,双重防护,对标 Linux `chattr +i`

```
:: ========== 第一步:配置NTFS精细权限(递归所有子文件/目录) ==========
:: 1. 授予管理员组 完全控制权限(OI=文件继承 CI=目录继承 /T=递归)
icacls "D:\www" /grant administrators:(OI)(CI)F /T

:: 2. 授予系统账户、网站运行账户 读取+执行权限(保障网站正常运行)
icacls "D:\www" /grant system:(OI)(CI)RX /T
icacls "D:\www" /grant www:(OI)(CI)RX /T

:: 3. 拒绝系统、网站账户 写入、删除权限(核心防篡改)
icacls "D:\www" /deny system:(OI)(CI)W,D /T
icacls "D:\www" /deny www:(OI)(CI)W,D /T

:: ========== 第二步:设置全局只读文件属性(强锁定) ==========
:: +r 添加只读属性 /s 递归子目录文件 /d 同时作用于文件夹
attrib +r "D:\www\*" /s /d
```

---

## 三、完整解锁命令(网站更新 / 文件修改 / 上传时使用)

### 作用说明

先解除文件只读属性,再放开写入 / 删除权限,操作完成后**务必重新执行加锁命令**。

```
:: ========== 第一步:取消文件只读属性(优先执行) ==========
:: -r 移除只读属性 /s 递归 /d 包含目录
attrib -r "D:\www\*" /s /d

:: ========== 第二步:放开NTFS写入权限,允许修改、删除 ==========
:: 授予系统、网站账户 修改权限,支持文件上传/编辑/删除
icacls "D:\www" /grant system:(OI)(CI)M /T
icacls "D:\www" /grant www:(OI)(CI)M /T

:: 移除之前的写入、删除拒绝规则
icacls "D:\www" /remove:d system:(OI)(CI)W,D /T
icacls "D:\www" /remove:d www:(OI)(CI)W,D /T
```

---

## 四、辅助查看命令(校验状态)

### 1. 查看 NTFS 权限配置

```
icacls "D:\www" /T
```

### 2. 查看文件 / 目录只读属性

```
attrib "D:\www\*" /s /d
```

出现标识 `R` 代表已开启只读锁定。

---

## 五、运维强制规范

1. 仅对**业务目录(D:\\www)** 执行以上命令,**严禁作用于 C 盘系统目录**。
2. 网站改版、程序升级、文件上传:先解锁 → 操作文件 → 立即重新加锁。
3. 权限逻辑:
   - administrators:全程完全控制
   - system、www:日常仅读 + 执行,仅维护期间临时开放修改权限。


8. 🛡️ Nginx 安全规则(宝塔 - 点击网站 - 配置文件,需要放到include php/82.conf;的上面)

# WordPress上传目录禁止执行PHP(核心防图片马)
location ~* ^/wp-content/uploads/.*\.(php|php5|phtml|phar|cgi) {
    deny all;
    access_log off;
}

# 图片路径解析漏洞防御
location ~* \.(jpg|png|gif|jpeg|bmp|webp)/.*\.php$ {
    deny all;
    access_log off;
}

# 禁止直接访问核心配置文件
location ~* /(wp-config\.php|readme\.html|license\.txt) {
    deny all;
}

# 不需要API采集、手机客户端建议关闭xmlrpc.php
location = /xmlrpc.php {
    deny all;
}


# Discuz上传附件目录、缓存目录禁止执行PHP
location ~* ^/(attachments|data)/.*\.(php|php5|phtml|phar|cgi) {
    deny all;
    access_log off;
}

# 图片马解析漏洞防御
location ~* \.(jpg|png|gif|jpeg|bmp|webp)/.*\.php$ {
    deny all;
    access_log off;
}

# 禁止访问安装目录(如有install文件夹务必拦截)
location ^~ /install/ {
    deny all;
}

# 拦截备份文件
location ~* \.(bak|sql|tar|zip)$ {
    deny all;
}


# uploads、data 禁止执行PHP后门
location ~* ^/(uploads|data)/.*\.(php|php5|phtml|phar|cgi) {
    deny all;
    access_log off;
}

# Nginx经典解析漏洞防护 a.jpg/xxx.php
location ~* \.(jpg|png|gif|jpeg|bmp|webp)/.*\.php$ {
    deny all;
    access_log off;
}

# 禁止访问备份、敏感配置文件
location ~* \.(bak|sql|txt\.php|inc\.php|old)$ {
    deny all;
}


其他程序可直接用ai重写,注意核对目录路径和文件
---

📅 日常运维要求
1. 🔍 文件监测:所有服务器配置定时脚本(宝塔计划任务可用),监控文件修改、新增行为


# 通用前置约定 & 规则重申

## 一、核心规则(最终版)

1. **合法新增后缀(仅这类新增不告警)**
允许:`.jpg` `.png`
其余后缀文件**只要新增必告警**。
2. **全局文件白名单**
白名单文件:记录加入瞬间 MD5 状态,**仅监测内容修改**,无修改不展示,有修改强制告警。
3. **CMS 缓存 / 日志 / Session 目录**
内置主流 CMS 临时目录,**扫描全程直接跳过**,不参与遍历、比对,杜绝无效告警。
4. **PHP 文件交互**
列出所有 PHP 并编号 → 选择编号加入白名单 → 剩余 PHP 自选:全删 / 部分删 / 保留。
5. **日志**
全流程操作、变更、删除、加白、异常全部落地日志,可审计溯源。
6. **状态文件锁策略**
   - 基准库 `base.db`:首次生成后 `chattr +i` / 只读锁定,永久不变;误删则重建。
   - 动态库 `dynamic.db`:每次更新前解锁、写入完毕立即重新上锁。
7. **断点续扫**
超大目录生成**进度临时文件**,中断后下次执行继续扫描,防止重头遍历卡顿。
8. **白名单校验**
自动过滤空行、空格,校验路径有效性、重复项,异常输出提示 + 日志记录。
9. **运行身份**
Linux 必须 `root`;Windows 必须 **管理员身份** 运行。

## 二、路径统一配置

### Linux

- 网站根目录:`/www`
- 基准库:`/usr/local/www_base.db`(永久锁定)
- 动态库:`/usr/local/www_dynamic.db`(读写自动加解锁)
- 白名单:`/usr/local/www_whitelist.txt`
- 运行日志:`/var/log/www_file_check.log`
- 断点进度文件:`/tmp/www_scan_progress.tmp`
- CMS 排除目录:内置脚本内

### Windows

- 网站根目录:`D:\www`
- 基准库:`D:\script\www_base.db`(永久只读)
- 动态库:`D:\script\www_dynamic.db`(读写自动加解锁)
- 白名单:`D:\script\www_whitelist.txt`
- 运行日志:`D:\script\www_file_check.log`
- 断点进度文件:`D:\script\www_scan_progress.tmp`
- CMS 排除目录:内置脚本内

---

# 第一部分:Linux 版本(Shell 脚本)

## 1. 前置初始化(仅首次执行前操作)

```
# 创建目录 & 空白文件
mkdir -p /usr/local /var/log /tmp
touch /usr/local/www_whitelist.txt
chmod 700 /usr/local/www_check.sh
```

## 2. 完整脚本 `/usr/local/www_check.sh`

```
#!/bin/bash
##############################################################################
# 网站文件安全检测脚本 Linux版
# 功能:基准快照+动态快照+白名单+CMS目录排除+断点续扫+日志+文件锁+PHP精细化操作
##############################################################################
# ====================== 基础配置 ======================
WWW_DIR="/www"
BASE_DB="/usr/local/www_base.db"
DYNAMIC_DB="/usr/local/www_dynamic.db"
WHITELIST="/usr/local/www_whitelist.txt"
LOG_FILE="/var/log/www_file_check.log"
PROGRESS_FILE="/tmp/www_scan_progress.tmp"
NOW=$(date +"%Y-%m-%d %H:%M:%S")

# 合法新增后缀(仅这些新增不告警)
ALLOW_EXT=("jpg" "png")

# 主流CMS 缓存/日志/session/临时目录(全局排除,不扫描)
EXCLUDE_DIRS=(
    "/data/cache" "/data/log" "/data/session" "/data/sessions" "/temp" "/tmp" "/cache"
    "/runtime" "/logs" "/session" "/var/cache" "/var/log" "/attachments/cache"
    "/templets/cache" "/e/data/cache" "/e/data/log" "/e/tmp"
    "/wp-content/cache" "/wp-content/uploads/cache"
    "/data/threadcache" "/dayrui/cache" "/dayrui/log" "/dayrui/temp"
    "/zb_users/cache" "/zb_users/log"
)

# ====================== 公共函数 ======================
# 写入日志
write_log(){
    echo "[$NOW] $1" >> ${LOG_FILE}
    echo "$1"
}

# 校验root权限
check_root(){
    if [ "$(id -u)" -ne 0 ];then
      write_log "ERROR: 请使用 root 身份执行脚本!"
      exit 1
    fi
}

# 锁定文件 chattr +i
lock_file(){
    if [ -f "$1" ];then
      chattr +i "$1" 2>/dev/null
    fi
}

# 解锁文件 chattr -i
unlock_file(){
    if [ -f "$1" ];then
      chattr -i "$1" 2>/dev/null
    fi
}

# 校验白名单:去空行、去空格、校验路径、去重
check_whitelist(){
    write_log "开始校验白名单文件 ${WHITELIST}"
    local tmp_white=/tmp/white_tmp.tmp
    > ${tmp_white}
    local -A path_map

    while IFS= read -r line;do
      # 去除首尾空格
      line=$(echo "$line" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
      [ -z "$line" ] && continue

      if [[ -n "${path_map[$line]}" ]];then
            write_log "WARN: 白名单存在重复路径: $line"
            continue
      fi
      path_map[$line]=1

      if [ ! -f "$line" ];then
            write_log "WARN: 白名单路径不存在: $line"
            continue
      fi
      echo "$line" >> ${tmp_white}
    done < ${WHITELIST}

    mv -f ${tmp_white} ${WHITELIST}
    write_log "白名单校验完成"
}

# 生成MD5快照 + 断点续扫
create_snapshot(){
    local target_db=$1
    unlock_file ${target_db}
    > ${target_db}

    # 拼接find排除目录参数
    local exclude_param=""
    for ed in "${EXCLUDE_DIRS[@]}";do
      exclude_param+=" -not -path \"${WWW_DIR}${ed}/*\" "
    done

    # 断点续扫:读取上次进度
    local start_path=""
    if [ -f "${PROGRESS_FILE}" ];then
      start_path=$(cat ${PROGRESS_FILE})
      write_log "检测到断点进度,从 $start_path 继续扫描"
    fi

    # 流式遍历文件,实时写进度、写快照
    find ${WWW_DIR} -type f ${exclude_param} | while read file;do
      echo "$file" > ${PROGRESS_FILE}
      md5sum "$file" >> ${target_db}
    done

    rm -f ${PROGRESS_FILE}
    lock_file ${target_db}
    write_log "快照 $target_db 生成完成并已锁定"
}

# 比对快照:区分合法后缀、非法新增、修改文件
diff_snapshot(){
    local old_db=$1
    local new_db=$2
    local tmp_new=/tmp/new_files.tmp
    local tmp_mod=/tmp/mod_files.tmp
    > ${tmp_new}
    > ${tmp_mod}

    # 构建哈希表
    declare -A old_hash
    while read h p;do old_hash[$p]=$h;done < ${old_db}

    # 遍历新快照
    while read h p;do
      if [[ -z "${old_hash[$p]}" ]];then
            # 判定是否为合法后缀
            ext=${p##*.}
            local is_allow=0
            for ae in "${ALLOW_EXT[@]}";do
                if [ "${ext,,}" = "$ae" ];then
                  is_allow=1
                  break
                fi
            done
            if [ $is_allow -eq 0 ];then
                echo "$p" >> ${tmp_new}
            fi
      else
            if [ "${old_hash[$p]}" != "$h" ];then
                echo "$p" >> ${tmp_mod}
            fi
      fi
    done < ${new_db}

    # 输出非法新增
    if [ -s ${tmp_new} ];then
      write_log "===== 检测到【非法新增文件】 ====="
      cat ${tmp_new}
    else
      write_log "未检测到非法新增文件"
    fi

    # 输出全局修改文件
    if [ -s ${tmp_mod} ];then
      write_log "===== 检测到【内容修改文件】 ====="
      cat ${tmp_mod}
    else
      write_log "未检测到内容修改文件"
    fi

    rm -f ${tmp_new} ${tmp_mod}
    unset old_hash
}

# 白名单专项检测(仅比对修改)
check_whitelist_mod(){
    write_log "===== 白名单文件修改检测 ====="
    if [ ! -s ${WHITELIST} ];then
      write_log "白名单为空,跳过检测"
      return
    fi

    while read p;do
      base_md5=$(grep -F "$p" ${BASE_DB} | awk '{print $1}')
      curr_md5=$(md5sum "$p" | awk '{print $1}')
      if [ "$base_md5" != "$curr_md5" ];then
            write_log "【白名单文件已修改】$p"
      fi
    done < ${WHITELIST}
}

# PHP文件扫描 + 交互式加白/删除
check_php_interactive(){
    write_log "===== 专项目录 PHP 文件检测 ====="
    local spec_dirs=("template" "static" "static1" "static2" "skin" "uploadfile")
    local php_list=()

    # 收集所有PHP
    for sd in "${spec_dirs[@]}";do
      fp="${WWW_DIR}/${sd}"
      [ -d "$fp" ] || continue
      while IFS= read -r f;do
            php_list+=("$f")
      done < <(find "$fp" -type f -name "*.php")
    done

    if [ ${#php_list[@]} -eq 0 ];then
      write_log "未发现PHP文件"
      return
    fi

    # 编号展示
    write_log "发现PHP文件列表:"
    for i in "${!php_list[@]}";do
      echo "[$((i+1))] ${php_list[$i]}"
    done

    # 选择编号加入白名单
    read -p "请输入要加入白名单的编号(多个空格分隔,无则直接回车):" sel_nums
    if [[ -n "$sel_nums" ]];then
      for num in $sel_nums;do
            idx=$((num-1))
            if (( idx >=0 && idx < ${#php_list[@]} ));then
                file_add="${php_list[$idx]}"
                echo "$file_add" >> ${WHITELIST}
                write_log "已将 $file_add 加入白名单"
            fi
      done
    fi

    # 过滤已加白的PHP
    local remain_php=()
    for f in "${php_list[@]}";do
      if ! grep -qxF "$f" ${WHITELIST};then
            remain_php+=("$f")
      fi
    done

    if [ ${#remain_php[@]} -eq 0 ];then
      write_log "所有PHP均已加入白名单,无需删除"
      return
    fi

    # 选择删除策略
    echo "剩余待处理PHP:"
    for i in "${!remain_php[@]}";do echo "[$((i+1))] ${remain_php[$i]}";done
    read -p "选择操作:1=全部删除 2=部分删除 3=全部保留:" op
    case $op in
      1)
            for f in "${remain_php[@]}";do
                rm -f "$f"
                write_log "已删除PHP文件:$f"
            done
            ;;
      2)
            read -p "输入要删除的编号(空格分隔):" del_nums
            for num in $del_nums;do
                idx=$((num-1))
                if (( idx >=0 && idx < ${#remain_php[@]} ));then
                  f="${remain_php[$idx]}"
                  rm -f "$f"
                  write_log "已删除PHP文件:$f"
                fi
            done
            ;;
      3)
            write_log "选择保留所有剩余PHP"
            ;;
      *)
            write_log "无效选择,跳过删除"
            ;;
    esac
}

# 全局文件手动删除
manual_delete(){
    write_log "===== 全局文件手动删除 ====="
    read -p "输入需删除文件完整路径(多个空格分隔,无需删除直接回车):" del_files
    if [[ -n "$del_files" ]];then
      for f in $del_files;do
            if [ -f "$f" ];then
                rm -f "$f"
                write_log "手动删除文件:$f"
            fi
      done
    else
      write_log "未执行手动删除"
    fi
}

# ====================== 主流程 ======================
check_root
write_log "========== 脚本开始执行 =========="

# 1. 校验白名单
check_whitelist

# 2. 首次运行:创建基准库并锁定
if [ ! -f "${BASE_DB}" ];then
    write_log "基准库不存在,首次生成全局基准快照"
    create_snapshot ${BASE_DB}
    lock_file ${BASE_DB}
    write_log "基准库已永久锁定"
    cp ${BASE_DB} ${DYNAMIC_DB}
    lock_file ${DYNAMIC_DB}
    write_log "初始化动态库完成,脚本退出"
    exit 0
fi

# 校验基准库锁定状态
if ! lsattr ${BASE_DB} | grep -q "i";then
    write_log "WARN: 基准库已被解锁,存在安全风险!"
    read -p "按回车继续..."
fi

# 3. PHP文件交互式处理
check_php_interactive

# 4. 更新动态快照(自动加解锁+断点续扫)
write_log "开始更新动态快照"
create_snapshot ${DYNAMIC_DB}

# 5. 全局文件比对(非法新增 + 修改)
diff_snapshot ${BASE_DB} ${DYNAMIC_DB}

# 6. 白名单文件仅检测修改
check_whitelist_mod

# 7. 手动删除全局文件
manual_delete

write_log "========== 脚本执行结束 =========="
exit 0
```

## 3. Linux 使用方法

1. 赋予执行权限
```
chmod +x /usr/local/www_check.sh
```
2. **首次执行**(生成基准库 + 锁定)
```
/usr/local/www_check.sh
```
3. **日常手动执行**
```
/usr/local/www_check.sh
```
4. 编辑白名单(一行一个完整路径)
```
vi /usr/local/www_whitelist.txt
```
5. 临时解锁基准库(仅维护)
```
chattr -i /usr/local/www_base.db
```

---

# 第二部分:Windows 版本(PowerShell 脚本)

## 1. 前置准备

1. 创建目录:`D:\script`
2. 新建空白文件:`D:\script\www_whitelist.txt`
3. **必须右键 PowerShell → 以管理员身份运行**

## 2. 完整脚本 `D:\script\www_check.ps1`

```
<#
Windows 网站文件安全检测脚本
运行要求:管理员身份启动PowerShell,手动执行
#>
# ====================== 基础配置 ======================
$WWW_DIR = "D:\www"
$BASE_DB = "D:\script\www_base.db"
$DYNAMIC_DB = "D:\script\www_dynamic.db"
$WHITELIST = "D:\script\www_whitelist.txt"
$LOG_FILE = "D:\script\www_file_check.log"
$PROGRESS_FILE = "D:\script\www_scan_progress.tmp"
$Now = Get-Date -Format "yyyy-MM-dd HH:mm:ss"

# 合法新增后缀
$ALLOW_EXT = @("jpg","png")

# CMS 全局排除目录
$EXCLUDE_DIRS = @(
    "\data\cache","\data\log","\data\session","\data\sessions","\temp","\tmp","\cache",
    "\runtime","\logs","\session","\var\cache","\var\log","\attachments\cache",
    "\templets\cache","\e\data\cache","\e\data\log","\e\tmp",
    "\wp-content\cache","\wp-content\uploads\cache",
    "\data\threadcache","\dayrui\cache","\dayrui\log","\dayrui\tmp",
    "\zb_users\cache","\zb_users\log",
    "\runtime\cache","\runtime\log"
)

# ====================== 公共函数 ======================
# 写入日志
function Write-Log{
    param($Msg)
    $logStr = "[$Now] $Msg"
    Add-Content -Path $LOG_FILE -Value $logStr -Encoding UTF8
    Write-Host $logStr
}

# 设置只读锁定
function Lock-File{
    param($Path)
    if(Test-Path $Path){
      $attr = (Get-Item $Path).Attributes
      Set-ItemProperty -Path $Path -Name Attributes -Value ($attr + ::ReadOnly)
    }
}

# 解除只读
function Unlock-File{
    param($Path)
    if(Test-Path $Path){
      Set-ItemProperty -Path $Path -Name Attributes -Value ::Normal
    }
}

# 白名单校验
function Test-WhiteList{
    Write-Log "开始校验白名单文件 $WHITELIST"
    $lines = Get-Content $WHITELIST -Encoding UTF8 -ErrorAction SilentlyContinue
    $outLines = @()
    $pathDict = @{}

    foreach($line in $lines){
      $line = $line.Trim()
      if(::IsNullOrEmpty($line)){ continue }
      if($pathDict.ContainsKey($line)){
            Write-Log "WARN: 白名单重复路径: $line"
            continue
      }
      $pathDict[$line] = $true
      if(-not (Test-Path $line -PathType Leaf)){
            Write-Log "WARN: 白名单路径不存在: $line"
            continue
      }
      $outLines += $line
    }
    $outLines | Out-File $WHITELIST -Encoding UTF8 -Force
    Write-Log "白名单校验完成"
}

# 生成快照 + 断点续扫
function New-Snapshot{
    param($DbPath)
    Unlock-File $DbPath
    "" | Out-File $DbPath -Encoding UTF8 -Force

    $excludePaths = $EXCLUDE_DIRS | ForEach-Object { "$WWW_DIR$_" }
    $lastPath = ""
    if(Test-Path $PROGRESS_FILE){
      $lastPath = Get-Content $PROGRESS_FILE -Encoding UTF8
      Write-Log "检测到断点进度,从 $lastPath 继续扫描"
    }

    $files = Get-ChildItem -Path $WWW_DIR -Recurse -File -ErrorAction SilentlyContinue | Where-Object {
      $fp = $_.FullName
      $isExclude = $false
      foreach($ep in $excludePaths){
            if($fp.StartsWith($ep)){ $isExclude = $true; break }
      }
      -not $isExclude
    }

    $start = ::IsNullOrEmpty($lastPath)
    foreach($f in $files){
      if(-not $start){
            if($f.FullName -eq $lastPath){ $start = $true }
            continue
      }
      $f.FullName | Out-File $PROGRESS_FILE -Encoding UTF8 -Force
      $md5 = (Get-FileHash -Path $f.FullName -Algorithm MD5).Hash
      "$md5|$($f.FullName)" | Out-File $DbPath -Append -Encoding UTF8
    }

    Remove-Item $PROGRESS_FILE -Force -ErrorAction SilentlyContinue
    Lock-File $DbPath
    Write-Log "快照 $DbPath 生成完成并已锁定"
}

# 快照比对
function Compare-Snap{
    param($OldDb,$NewDb)
    $oldData = Get-Content $OldDb -Encoding UTF8
    $oldHash = @{}
    foreach($line in $oldData){
      $arr = $line -split "\|",2
      $oldHash[$arr] = $arr
    }

    $newFiles = @()
    $modFiles = @()
    $newData = Get-Content $NewDb -Encoding UTF8

    foreach($line in $newData){
      $arr = $line -split "\|",2
      $p = $arr
      $h = $arr
      if(-not $oldHash.ContainsKey($p)){
            $ext = $p.Split(".")[-1].ToLower()
            $allow = $false
            foreach($ae in $ALLOW_EXT){
                if($ext -eq $ae){ $allow = $true; break }
            }
            if(-not $allow){ $newFiles += $p }
      }
      else{
            if($oldHash[$p] -ne $h){ $modFiles += $p }
      }
    }

    if($newFiles.Count -gt 0){
      Write-Log "===== 检测到【非法新增文件】 ====="
      $newFiles | ForEach-Object { Write-Log $_ }
    }
    else{ Write-Log "未检测到非法新增文件" }

    if($modFiles.Count -gt 0){
      Write-Log "===== 检测到【内容修改文件】 ====="
      $modFiles | ForEach-Object { Write-Log $_ }
    }
    else{ Write-Log "未检测到内容修改文件" }
}

# 白名单修改检测
function Check-WhiteModify{
    Write-Log "===== 白名单文件修改检测 ====="
    if(-not (Test-Path $WHITELIST) -or (Get-Content $WHITELIST -Encoding UTF8).Count -eq 0){
      Write-Log "白名单为空,跳过检测"
      return
    }
    $baseData = Get-Content $BASE_DB -Encoding UTF8
    $baseHash = @{}
    foreach($line in $baseData){
      $arr = $line -split "\|",2
      $baseHash[$arr] = $arr
    }
    $whitePaths = Get-Content $WHITELIST -Encoding UTF8
    foreach($p in $whitePaths){
      if(-not (Test-Path $p -PathType Leaf)){ continue }
      $currHash = (Get-FileHash -Path $p -Algorithm MD5).Hash
      if($baseHash[$p] -ne $currHash){
            Write-Log "【白名单文件已修改】$p"
      }
    }
}

# PHP交互式处理
function Check-Php{
    Write-Log "===== 专项目录 PHP 文件检测 ====="
    $specDirs = @("template","static","static1","static2","skin","uploadfile")
    $phpFiles = @()
    foreach($d in $specDirs){
      $fp = Join-Path $WWW_DIR $d
      if(Test-Path $fp){
            $php = Get-ChildItem -Path $fp -Recurse -Filter "*.php" -File -ErrorAction SilentlyContinue
            $phpFiles += $php.FullName
      }
    }
    if($phpFiles.Count -eq 0){
      Write-Log "未发现PHP文件"
      return
    }

    Write-Log "发现PHP列表:"
    for($i=0;$i -lt $phpFiles.Count;$i++){
      Write-Host "[$($i+1)] $($phpFiles[$i])"
    }

    $sel = Read-Host "输入加入白名单的编号(空格分隔,无则回车)"
    if(-not ::IsNullOrEmpty($sel)){
      $nums = $sel -split " "
      foreach($n in $nums){
            $idx = $n - 1
            if($idx -ge 0 -and $idx -lt $phpFiles.Count){
                $f = $phpFiles[$idx]
                Add-Content -Path $WHITELIST -Value $f -Encoding UTF8
                Write-Log "已将 $f 加入白名单"
            }
      }
    }

    # 过滤已加白
    $whiteList = Get-Content $WHITELIST -Encoding UTF8
    $remainPhp = $phpFiles | Where-Object { $_ -notin $whiteList }
    if($remainPhp.Count -eq 0){
      Write-Log "所有PHP已加入白名单"
      return
    }

    Write-Host "剩余PHP:"
    for($i=0;$i -lt $remainPhp.Count;$i++){
      Write-Host "[$($i+1)] $($remainPhp[$i])"
    }
    $op = Read-Host "选择:1=全删 2=部分删 3=保留"
    switch($op){
      "1"{
            foreach($f in $remainPhp){
                Remove-Item $f -Force -ErrorAction SilentlyContinue
                Write-Log "已删除PHP: $f"
            }
      }
      "2"{
            $delSel = Read-Host "输入删除编号(空格分隔)"
            $dnums = $delSel -split " "
            foreach($n in $dnums){
                $idx = $n - 1
                if($idx -ge0 -and $idx -lt $remainPhp.Count){
                  $f = $remainPhp[$idx]
                  Remove-Item $f -Force -ErrorAction SilentlyContinue
                  Write-Log "已删除PHP: $f"
                }
            }
      }
      "3"{ Write-Log "选择保留所有PHP" }
      default{ Write-Log "无效选择,跳过" }
    }
}

# 手动删除文件
function Manual-Delete{
    Write-Log "===== 全局文件手动删除 ====="
    $input = Read-Host "输入删除文件路径(空格分隔,无需删除直接回车)"
    if(-not ::IsNullOrEmpty($input)){
      $list = $input -split " "
      foreach($f in $list){
            if(Test-Path $f -PathType Leaf){
                Remove-Item $f -Force
                Write-Log "手动删除文件: $f"
            }
      }
    }
    else{
      Write-Log "未执行手动删除"
    }
}

# ====================== 主流程 ======================
Write-Log "========== 脚本开始执行 =========="

# 1. 白名单校验
Test-WhiteList

# 2. 首次创建基准库
if(-not (Test-Path $BASE_DB)){
    Write-Log "基准库不存在,首次生成快照"
    New-Snapshot $BASE_DB
    Lock-File $BASE_DB
    Write-Log "基准库已设为只读锁定"
    Copy-Item $BASE_DB $DYNAMIC_DB -Force
    Lock-File $DYNAMIC_DB
    Write-Log "动态库初始化完成,脚本退出"
    exit
}

# 检查基准库锁定
$baseAttr = (Get-Item $BASE_DB).Attributes
if(($baseAttr -band ::ReadOnly) -eq 0){
    Write-Log "WARN: 基准库已解除只读,存在风险!"
    Read-Host "按回车继续" | Out-Null
}

# 3. PHP处理
Check-Php

# 4. 更新动态快照
Write-Log "开始更新动态快照"
New-Snapshot $DYNAMIC_DB

# 5. 全局比对
Compare-Snap $BASE_DB $DYNAMIC_DB

# 6. 白名单修改检测
Check-WhiteModify

# 7. 手动删除
Manual-Delete

Write-Log "========== 脚本执行结束 =========="
```

## 3. Windows 使用方法

1. 管理员 PowerShell 执行脚本
```
D:\script\www_check.ps1
```
2. 首次运行自动生成基准库 + 设为只读;
3. 日常直接重复执行即可;
4. 编辑白名单:`D:\script\www_whitelist.txt`,一行一个完整路径;
5. 解除基准库只读(仅维护):
```
Set-ItemProperty D:\script\www_base.db -Name Attributes -Value Normal
```

---

# 最终功能核对(全部需求已落地)

✅ 仅 `jpg/png` 允许合法新增,其余新增必告警
✅ 白名单:记录加入时状态,**仅检测内容修改**,无修改不展示
✅ PHP 文件编号展示 → 自选编号加白 → 剩余文件支持全删 / 部分删 / 保留
✅ 全操作落地独立日志,可审计
✅ 动态库:读写自动解锁 / 上锁,防护篡改
✅ 内置 9 大主流 CMS 缓存 / 日志目录,扫描直接跳过
✅ 超大目录支持**断点续扫**,实时进度文件,避免重头遍历卡顿
✅ 白名单自动校验:空行、空格、重复、无效路径均有提示
✅ 基准库永久锁定,误删则自动重建基线
✅ 全局文件支持手动单独 / 批量删除

2. 📤 FTP管理:临时启用,使用完毕立即删除,不长期保留FTP服务
3. 🛡️ 安全软件:确保安全软件全部功能正常开启、在线运行

---

⏰ 定期巡检&维护任务
1. 🔄 更换密码、修改后台入口;升级系统、网站程序、宝塔面板、运行环境;持续关注高危漏洞公告
2. 📢 及时处理服务商、宝塔、安全软件推送的安全提醒与告警
3. 🧹 关闭宝塔闲置插件/服务,卸载无用第三方插件
4. 🚨 巡检入侵行为、DDoS攻击、异常登录、流量异常等风险
5. ⚙️ 核查系统开机启动项、系统定时任务,清理异常项
6. 🕵️ 检查系统隐藏文件与定时任务
   - Linux:`/usr/lib` 目录
   - Windows:`/System32`、`/SysWOW64` 目录
7. 👥 清理系统、网站后台内所有无用账号
8. 💾 全量备份:系统、网站文件、数据库、配置文件;定期恢复测试,保障备份可用
9. 🌍 多设备(PC/移动端)测试网站访问状态,保证业务正常

---

🧩 安全产品清单
✅ 宝塔官方防护
✅ 护卫神
✅ 火绒
✅ 阿里云官方防护
✅ 百度云官方防护




页: [1]
查看完整版本: 《服务器安全配置与运维规范》〔2026〕