《服务器安全配置与运维规范》〔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
~*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]