安全加固手册
本文面向已完成部署的 BlogKit 站长,提供生产环境的安全加固指导:从部署前检查、服务器与 Web 服务器配置,到系统内置安全机制的说明、后台访问控制、数据备份策略与应急响应流程。
1. 部署前加固清单
系统安装完成后,请逐项确认以下清单(与 01-系统介绍 第 5.4 节互为补充):
- 删除服务器上的
install.php:安装器虽受install.lock保护不会重复运行,但该文件不应继续暴露在站点根目录; - 确认
install.lock存在:该文件是安装状态标记,删除后所有入口会重定向回安装向导,切勿误删; - 收紧配置文件权限:
core/config/database.php含数据库凭据,建议权限 0644(用户与组可读、其他用户只读),并确认未被 Web 服务器直接下载(见第 3 节屏蔽规则); - 修改默认管理员密码:安装时生成的密码请在后台「个人资料」中再次确认为强密码(长度 8 位以上、混合大小写字母与数字,避免在其他站点复用);
- 关闭调试模式:生产环境将
core/config/system.php中debug.enabled设为false,避免报错信息泄露路径与配置细节; - 关闭 PHP 详细错误输出:
php.ini中设置display_errors = Off,错误仅记录到日志; - 开启后台 IP 白名单(可选但强烈推荐):详见第 5.1 节;
- 开启后台登录验证码:默认关闭,建议在「验证码设置」中开启(详见第 4.1 节);
- 配置 HTTPS:启用后会自动升级会话 Cookie 安全属性并启用 HSTS,详见第 7 节;
- 建立定期备份策略:详见第 6 节;
- 数据库账号最小权限:日常运行只需
SELECT / INSERT / UPDATE / DELETE,仅在安装与备份恢复时使用具备CREATE / ALTER / DROP的账号。
1.1 安装器自带的安全检测
运行 install.php 时,安装向导会先完成一轮环境自检,全部必需项通过后方可安装,可作为部署环境的基线参考:
| 检测项 | 性质 | 说明 |
|---|---|---|
| PHP 版本 ≥ 7.4 | 必需 | 低版本无法继续安装 |
| MySQLi / PDO MySQL 扩展 | 必需 | 数据库访问依赖 |
| 目录写入权限 | 必需 | 检测站点根目录、core/config/、uploads/、storage/ 四处,缺失时尝试自动创建 |
| GD 扩展 | 推荐 | 图片处理与验证码绘制依赖 |
| cURL 扩展 | 推荐 | 应用市场与更新检测依赖 |
| Fileinfo 扩展 | 推荐 | 上传文件类型检测更可靠 |
安装环节自身的安全措施:安装表单带 CSRF 令牌防跨站提交;管理员密码要求至少 8 位并提供 16 位随机强密码生成器;密码仅以单向哈希形态写入数据库;安装完成后生成仅含时间戳的 install.lock,此后安装器拒绝再次运行。
2. 服务器与 PHP 环境加固
2.1 PHP 配置建议
以下为生产环境推荐的 php.ini 关键项(修改后需重启 PHP 服务):
| 配置项 | 推荐值 | 说明 |
|---|---|---|
display_errors | Off | 禁止在响应中输出错误详情,防止泄露路径与配置 |
log_errors | On | 错误写入日志文件,便于事后排查 |
expose_php | Off | 响应头中不暴露 PHP 版本号 |
session.use_strict_mode | On | 拒绝未初始化的会话 ID |
upload_max_filesize | 按需(默认 2M) | 与后台「安全设置」中的上传大小限制配合 |
allow_url_include | Off | 禁止远程文件包含 |
说明:系统日志(操作日志、登录日志等)由系统自行管理,存放于 storage/logs/,与 PHP 错误日志相互独立。
2.2 使用 open_basedir 限定访问范围
若主机环境允许多站点共存,建议为站点单独设置 open_basedir,把 PHP 可访问的文件范围限定在站点目录内,即使出现漏洞也能限制影响面:
open_basedir = /www/wwwroot//:/tmp/宝塔等面板可在「网站设置 → 防跨站攻击」中一键开启,效果等同于为站点配置 open_basedir。
2.3 目录权限最小化
系统运行仅需 uploads/ 与 storage/(以及 core/config/ 在安装阶段)可写,其余目录建议全部设为只读:
| 目录 | 建议权限 | 说明 |
|---|---|---|
core/、app/、themes/、plugins/ | 只读(755 / 文件 644) | 业务与内核代码,升级时才临时放开 |
core/config/ | 安装后只读 | 存放数据库等配置文件 |
uploads/ | 可写(755),禁止执行 PHP | 上传附件目录,按类型分 avatars/、articles/、comments/、attachments/ 子目录 |
storage/ | 可写(755),禁止执行 PHP | 缓存、日志、会话、备份等运行时数据 |
| 站点根目录 | 安装后只读 | 仅需 install.php 运行阶段可写(生成 install.lock) |
Linux 下禁止目录执行 PHP 的方法见第 3 节 Web 服务器配置;文件落盘后系统会将上传文件权限收紧为 0644(去除执行位)。
3. Web 服务器加固
核心原则:只让 index.php、admin.php、api.php 及静态资源被访问,其余 PHP 文件与运行时目录一律屏蔽。
3.1 Nginx
在站点的 server 块中添加(建议放在伪静态规则之前):
# 屏蔽敏感目录:内核、业务代码、运行时数据
location ~ ^/(core|app|storage|docs)/ {
deny all;
}
# 屏蔽安装器与安装锁(已安装后务必生效)
location ~ ^/(install\.php|install\.lock) {
deny all;
}
# 屏蔽各目录下的敏感文件(数据库配置、SQL、日志、JSON、MD 等)
location ~* \.(sql|log|json|md|lock)$ {
deny all;
}
# 关键:uploads 目录禁止执行任何 PHP 脚本
location ~* ^/uploads/.*\.(php|php3|php4|php5|phtml)$ {
deny all;
}整合到完整 server 块中的参考顺序如下(安全屏蔽规则务必放在伪静态规则之前,避免被 try_files 先行命中):
server {
listen 80;
server_name 你的域名;
root /www/wwwroot/你的站点目录;
index index.php index.html;
# 1. 安全屏蔽规则(上一代码块中的 location 配置)
# 2. 伪静态
location / {
try_files $uri $uri/ /index.php$uri?$args;
}
# 3. PHP 解析
location ~ \.php$ {
fastcgi_pass unix:/tmp/php-cgi.sock; # 按实际环境填写
fastcgi_index index.php;
include fastcgi.conf;
}
}3.2 Apache
在站点根目录 .htaccess(或虚拟主机配置)中添加:
# 屏蔽敏感目录
RedirectMatch 403 ^/(core|app|storage|docs)/
# 屏蔽安装器与安装锁
<FilesMatch "^(install\.php|install\.lock)$">
Require all denied
</FilesMatch>
# uploads 目录禁止执行 PHP(放置于 uploads/.htaccess 中更佳)
<IfModule mod_php7.c>
php_flag engine off
</IfModule>若 uploads/.htaccess 单独配置,可仅写 php_flag engine off(Apache 2.4 配合 mod_php);使用 PHP-FPM 模式时请改用 SetHandler 拦截或在虚拟主机中对该目录移除 PHP 处理器。
提示:无论使用哪种 Web 服务器,请将storage/整体视为敏感目录(其中storage/sessions/存放登录会话、storage/backups/存放备份文件、storage/runtime/存放登录防爆破锁定记录),务必禁止外部直接访问。
4. 系统内置安全机制说明
以下机制均随系统内置,无需安装额外插件。总体开关位于后台「安全设置」,验证码细分开关位于「验证码设置」,登录防爆破参数位于「用户设置」(各设置页说明可参阅 02-使用手册 第 7 节)。
4.1 图形验证码
验证码由核心类 Captcha 生成(GD 绘制,默认 4 位字符、5 分钟内有效,验证通过后立即销毁),可按场景独立开关,配置键与默认值如下:
| 场景 | 配置键 | 默认 |
|---|---|---|
| 验证码总开关 | captcha_enabled | 开启 |
| 前台用户登录 | captcha_login_enabled | 开启 |
| 用户注册 | captcha_register_enabled | 开启 |
| 发表评论 | captcha_comment_enabled | 开启 |
| 找回密码 | captcha_forgot_password_enabled | 开启 |
| 重置密码 | captcha_reset_enabled | 开启 |
| 后台管理员登录 | captcha_admin_login_enabled | 关闭(建议开启) |
后台路径:「系统设置 → 验证码设置」,可调整类型(混合 / 纯数字 / 纯字母)、长度、噪点与干扰线密度。
4.2 登录防爆破
同一 IP 连续登录失败达到阈值后,登录、找回密码、重置密码及验证码接口将整体锁定,锁定期间返回 HTTP 429 提示页(不含任何可提交表单),防止继续尝试:
| 参数 | 配置键 | 默认值 | 可配范围 |
|---|---|---|---|
| 最大失败次数 | login_attempt_limit | 5 次 | 1 - 20 次 |
| 锁定时长 | login_lock_time | 1800 秒(30 分钟) | 300 - 86400 秒 |
补充说明:
- 计时窗口从首次失败起算,窗口内累计计数,窗口过期后自动清零;登录成功会立即清除该 IP 的锁定记录;
- 锁定状态按客户端真实 IP 存储于
storage/runtime/login_lock_*.json; - 后台路径:「系统设置 → 用户设置」。
4.3 CSRF 防护
所有后台 POST 操作与前台表单均要求携带 CSRF 令牌(表单隐藏字段 csrf_token),服务端使用 hash_equals 做时序安全比较;令牌有效期 7200 秒(2 小时),过期需刷新页面重新提交。
- 总开关:
security_csrf_protection(后台「安全设置」,默认开启;除非排查兼容性问题,否则不建议关闭); - 关闭后表单不再渲染隐藏字段、校验直接放行,系统将失去跨站请求伪造防护。
4.4 XSS 过滤
security_xss_protection 开启时(默认开启),系统对用户输入执行 HTML 特殊字符转义(htmlspecialchars,ENT_QUOTES,UTF-8);文章正文等富文本内容按编辑器约定处理,不受该开关影响。数据库访问全程使用 PDO 预处理语句,不存在字符串拼接查询。
4.5 文件上传防护
上传环节的多层校验(核心类 Upload):
| 校验层 | 说明 |
|---|---|
| 上传总开关 | security_file_upload_enabled,关闭后所有上传接口直接拒绝 |
| 大小限制 | security_file_upload_max_size,默认 5MB |
| 扩展名黑名单 | 默认拒绝 php / php3 / php4 / php5 / phtml / exe / dll / asp / aspx / jsp / js / html / htm / shtml / cgi / pl 等 |
| MIME 内容检测 | 图片文件读取真实内容(getimagesize)判定类型,仅允许 jpeg / png / gif / webp,不信任客户端提交的 Content-Type |
| 文件名重写 | 落盘文件名统一重写为「时间戳 + 随机数」,不保留原始文件名 |
| 权限收紧 | 保存后自动 chmod 0644,去除执行位 |
后台路径:「系统设置 → 安全设置」。即使如此,仍强烈建议按第 3 节在 Web 服务器层禁止 uploads/ 执行 PHP,形成双保险。
4.6 安全响应头与 HSTS
系统在每个入口统一发送以下响应头(见 core/bootstrap.php):
| 响应头 | 值 | 作用 |
|---|---|---|
X-Frame-Options | DENY | 禁止被 iframe 嵌套,防点击劫持 |
X-Content-Type-Options | nosniff | 禁止浏览器嗅探 MIME 类型 |
X-XSS-Protection | 1; mode=block | 启用浏览器反射型 XSS 过滤 |
Referrer-Policy | strict-origin-when-cross-origin | 限制 Referer 泄露 |
X-Permitted-Cross-Domain-Policies | none | 禁止 Flash/PDF 跨域读取 |
X-Download-Options | noopen | 禁止 IE 直接打开下载文件 |
Content-Security-Policy | default-src 'self'; ... | 限制资源加载来源(因主题模板含内联样式与脚本,含 unsafe-inline) |
Strict-Transport-Security | max-age=31536000; includeSubDomains | 仅在 HTTPS 下自动发送,强制浏览器一年内使用 HTTPS |
HSTS 无需手动开启:检测到当前请求为 HTTPS 即自动生效。
4.7 会话安全
会话相关机制(引导文件统一处理):
- 会话 Cookie 名为
BKSID,属性为HttpOnly(禁止 JS 读取)+SameSite=Strict(阻止跨站携带); - HTTPS 环境下自动附加
Secure属性(仅通过加密连接传输); - 登录状态 30 分钟无操作自动过期(滑动过期),过期后需重新登录;
- 后台登录成功后会话 ID 自动重新生成,防止会话固定攻击。
4.8 维护模式与站点运行状态
遇到安全事件需要临时关闭站点时,可使用以下内置手段(后台「系统设置 → 基本设置」):
| 手段 | 行为 | 管理员访问 |
|---|---|---|
| 维护模式 | 全站返回 503 状态码与维护提示页,附带 Retry-After 头 | 不受影响,仍可登录后台处理 |
| 站点状态「关闭」 | 前台返回 503 | 不受影响 |
| 站点状态「私密」 | 未登录用户跳转登录页,仅注册用户可浏览 | 不受影响 |
4.9 后台认证与权限体系
后台所有请求经过统一认证中间件处理,机制如下:
- 登录强制校验:除公开页面(登录、退出、找回密码、重置密码、验证码图片)外,后台任何页面都要求有效登录会话,且账号角色必须具备后台访问权限(管理员或被授权角色);无权限的残留会话会被自动清理并跳转登录页;
- 操作方法白名单:各后台控制器仅允许调用登记在册的方法,未登记的 URL 请求直接拒绝,缩小参数注入面;
- 权限码校验:每个后台操作按权限码(如文章、媒体、
config系统设置等)逐一校验,未授权时返回 403 页面; - 插件后台页双重校验:插件管理页需插件处于启用状态且已注册后台路由,同时受角色授权名单(插件详情页「访问授权」)约束,停用即拒绝访问。
该体系意味着:只要管理员密码不泄露,即使前台用户账号被盗,也无法触及后台功能;多角色账号的权限边界由「角色与权限」配置决定(见第 5.3 节)。
5. 后台访问控制
5.1 IP 白名单
开启后,所有后台入口(admin.php)请求将按白名单校验客户端 IP,不在名单内的请求直接返回 403 并记录安全日志:
- 进入「系统设置 → 安全设置」,找到「IP 白名单」区块;
- 打开启用开关;
- 添加允许访问的 IP,支持两种格式:
- 单个 IP:如
203.0.113.10(支持 IPv4 与 IPv6); - CIDR 网段:如
203.0.113.0/24(适合办公网络出口带宽变动的情况);
- 单个 IP:如
- 保存后立即生效,建议先添加自己当前 IP 再开启开关,避免把自己锁在门外;
- 若配置失误导致无法访问,可通过数据库工具修改
bk_config表中admin_ip_whitelist_enabled的值为0,或直接清空admin_ip_whitelist。
5.2 可信代理
当站点位于反向代理(Nginx 代理、CDN、负载均衡)之后时,PHP 看到的 REMOTE_ADDR 是代理 IP 而非访客真实 IP,白名单与防爆破将按代理 IP 判定而失效。此时需要配置可信代理:
- 在「安全设置 → IP 白名单」的「可信代理」中添加代理服务器 IP 或网段(如内网网段
10.0.0.0/8); - 配置后,系统仅在
REMOTE_ADDR命中可信代理时才从转发头(CF-Connecting-IP、X-Real-IP、X-Forwarded-For等)解析真实客户端 IP; - 安全提示:可信代理名单务必只填写你实际控制的代理地址,切勿留空或随意添加,否则攻击者可通过伪造请求头冒充任意 IP 绕过白名单。
5.3 角色与最小权限
系统内置管理员 / 编辑 / 作者 / 注册用户 / 游客五级角色,并支持自定义角色与细粒度权限。分配后台账号时遵循最小权限原则:
- 仅内容维护人员授予「编辑」「作者」角色,不要滥发管理员账号;
- 「安全设置」等系统级配置页需要系统设置权限(
config权限码),仅限管理员持有; - 人员离职或设备遗失时,立即在「用户管理」中停用对应账号;
- 角色与权限的日常操作参阅 02-使用手册 第 3.2 节。
5.4 后台安全日志
IP 白名单的拦截与放行、登录失败等安全事件均会写入系统日志,是日常巡检与事后取证的主要依据:
| 事件 | 日志类别 | 记录内容 |
|---|---|---|
| 后台访问被拦截 / 允许 | security | 真实 IP、请求 URL、User-Agent、是否放行 |
| 用户登录失败 | login | 用户名、IP、累计失败次数、剩余可尝试次数 |
日志文件位于 storage/logs/,默认按 类别名.log 命名(开启按日切割后为 类别名-日期.log)。系统日志默认关闭记录,可在后台日志设置中开启并选择记录级别与保留天数。此外请勿删除 storage/runtime/ 下的登录锁定文件,它们是防爆破机制的计数依据。
6. 数据安全
6.1 备份策略
后台提供「数据备份」功能(参阅 02-使用手册 第 8.2 节),支持两种类型:
| 类型 | 内容 | 文件名格式 |
|---|---|---|
| 数据库备份 | 全部数据表 | backup_db_日期_时间.sql.gz(gzip 压缩) |
| 全站备份 | 数据库 + uploads/ 附件等目录 | backup_full_日期_时间.zip |
建议策略:
- 常规站点每周至少一次全站备份;内容更新频繁的站点可提高至每日一次;
- 备份文件仅存放在服务器本机是不够的,应定期通过「下载」功能将备份转移到异地(本地电脑、对象存储等);
- 每次升级系统前必须先做一次全站备份(升级流程参阅 01-系统介绍 第 7 节 FAQ)。
6.2 备份恢复注意事项
- 恢复操作会覆盖当前数据,执行前先确认备份文件时间点,必要时先把当前状态再备份一次;
- 恢复期间建议开启维护模式(见第 4.8 节),避免恢复过程中产生新数据造成不一致;
- 备份文件包含全站文章、用户数据与密码哈希,属于敏感文件,妥善保管,不要存放到
uploads/等可公开访问的目录; - 系统在恢复前会校验备份文件完整性,校验失败会中止恢复。
7. HTTPS 部署
系统对 HTTPS 的适配是自动的,无需修改代码:
- 在服务器或 CDN 上配置证书(Let's Encrypt 等均可),确保
https://你的域名正常访问; - 确认访客实际通过 HTTPS 进入(可在 Web 服务器层将 80 端口 301 跳转到 HTTPS);
- 部署完成后系统自动获得:
- 会话 Cookie 附加
Secure属性; - 响应头启用 HSTS(
max-age=31536000; includeSubDomains),浏览器此后一年内强制使用 HTTPS 访问本域名及其子域名。
- 会话 Cookie 附加
注意事项:
- HSTS 一旦下发便持续生效,回退 HTTP 需等待缓存过期,配置证书前请确认 HTTPS 稳定可用;
- 使用 CDN 或反向代理时,请按第 5.2 节配置可信代理,避免协议与真实 IP 判断失真;
- 「基本设置」中的站点地址建议同步改为 HTTPS,避免页面内资源走 HTTP 引发混合内容告警。
8. 应急响应
8.1 疑似入侵后的排查步骤
- 立即止损:开启维护模式或把站点状态设为「关闭」(见第 4.8 节);修改管理员密码与数据库密码;
- 检查登录日志:系统在
storage/logs/下按类别记录日志(如login-*.log、security-*.log),重点查看:login类别中的「用户登录失败」记录(含用户名、IP、尝试次数);security类别中的「后台访问被拦截」记录(含 IP、URL、User-Agent);
- 检查上传目录:浏览
uploads/各子目录,排查是否存在近期新增、命名异常的可疑文件(尤其非图片扩展名的文件),发现后立即删除; - 检查后台账号:「用户管理」中确认管理员角色账号数量与最后登录时间,移除陌生账号;
- 检查数据库:通过数据库工具检查
bk_users表是否存在陌生的管理员角色账号、bk_config表中安全相关配置(上传开关、白名单、站点地址等)是否被篡改;启用了「开放API」插件的话,同时核对 API 密钥列表; - 检查配置文件:「安全设置」确认 IP 白名单、上传开关等未被篡改;
core/config/下文件确认未被改动; - 核对文件完整性:与官方 GitHub 仓库 对比
core/、app/、index.php、admin.php等核心文件是否被篡改; - 核对 Web 服务器访问日志:结合 Nginx / Apache 的访问日志定位可疑请求的来源 IP 与时间线,必要时在 Web 服务器或防火墙层封禁来源 IP。
8.2 利用备份恢复
确认环境清理完毕(或已切换到全新服务器)后,使用入侵前确认完好的备份执行恢复(见第 6.2 节)。恢复后:
- 立即修改管理员密码与数据库密码;
- 重新检查各项安全设置;
- 切勿使用入侵发生之后生成的备份,其中可能已携带被篡改的数据。
8.3 无法登录后台的处理
- 忘记密码:优先通过登录页「忘记密码」邮箱重置;邮件不可用时可通过数据库将管理员
password字段更新为新的password_hash()哈希值,具体 SQL 示例见 01-系统介绍 第 7 节 FAQ; - 被 IP 白名单锁在门外:见第 5.1 节第 5 步;
- 锁定提示无法登录:登录防爆破按 IP 锁定(默认 30 分钟),等待窗口结束或删除
storage/runtime/下对应login_lock_*.json文件即可解锁。
8.4 极端情况:全新重装
当文件损坏严重、无法定位篡改点时,可按 01-系统介绍 第 5 节全新安装:
- 先备份现有数据库与
uploads/附件; - 删除站点根目录的
install.lock(此操作将允许安装器重新运行); - 部署官方最新源码包(覆盖可疑文件),重新运行安装向导;
- 通过后台「数据迁移」工具导入备份数据,重装所需插件。
相关文档
- 01-系统介绍:安装部署与安装后安全清单
- 02-使用手册:安全设置、验证码设置、数据备份的后台操作路径
- 03-目录与文件说明:目录职责与权限规划参考
- 项目主页:https://www.blogkit.cn
- 源码仓库:https://github.com/cnbana/BlogKit
- 安全问题反馈:请通过 https://www.blogkit.cn/community 联系我们,请勿在公开渠道披露未修复的漏洞细节。