安全加固手册

更新于 2026-11-08 15:31:54 19 次浏览
本文面向已完成部署的 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_errorsOff禁止在响应中输出错误详情,防止泄露路径与配置
log_errorsOn错误写入日志文件,便于事后排查
expose_phpOff响应头中不暴露 PHP 版本号
session.use_strict_modeOn拒绝未初始化的会话 ID
upload_max_filesize按需(默认 2M)与后台「安全设置」中的上传大小限制配合
allow_url_includeOff禁止远程文件包含

说明:系统日志(操作日志、登录日志等)由系统自行管理,存放于 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_limit5 次1 - 20 次
锁定时长login_lock_time1800 秒(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-OptionsDENY禁止被 iframe 嵌套,防点击劫持
X-Content-Type-Optionsnosniff禁止浏览器嗅探 MIME 类型
X-XSS-Protection1; mode=block启用浏览器反射型 XSS 过滤
Referrer-Policystrict-origin-when-cross-origin限制 Referer 泄露
X-Permitted-Cross-Domain-Policiesnone禁止 Flash/PDF 跨域读取
X-Download-Optionsnoopen禁止 IE 直接打开下载文件
Content-Security-Policydefault-src 'self'; ...限制资源加载来源(因主题模板含内联样式与脚本,含 unsafe-inline)
Strict-Transport-Securitymax-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 并记录安全日志:

  1. 进入「系统设置 → 安全设置」,找到「IP 白名单」区块;
  2. 打开启用开关;
  3. 添加允许访问的 IP,支持两种格式:
    • 单个 IP:如 203.0.113.10(支持 IPv4 与 IPv6);
    • CIDR 网段:如 203.0.113.0/24(适合办公网络出口带宽变动的情况);
  4. 保存后立即生效,建议先添加自己当前 IP 再开启开关,避免把自己锁在门外;
  5. 若配置失误导致无法访问,可通过数据库工具修改 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 备份恢复注意事项

  1. 恢复操作会覆盖当前数据,执行前先确认备份文件时间点,必要时先把当前状态再备份一次;
  2. 恢复期间建议开启维护模式(见第 4.8 节),避免恢复过程中产生新数据造成不一致;
  3. 备份文件包含全站文章、用户数据与密码哈希,属于敏感文件,妥善保管,不要存放到 uploads/ 等可公开访问的目录;
  4. 系统在恢复前会校验备份文件完整性,校验失败会中止恢复。

7. HTTPS 部署

系统对 HTTPS 的适配是自动的,无需修改代码:

  1. 在服务器或 CDN 上配置证书(Let's Encrypt 等均可),确保 https://你的域名 正常访问;
  2. 确认访客实际通过 HTTPS 进入(可在 Web 服务器层将 80 端口 301 跳转到 HTTPS);
  3. 部署完成后系统自动获得:
    • 会话 Cookie 附加 Secure 属性;
    • 响应头启用 HSTS(max-age=31536000; includeSubDomains),浏览器此后一年内强制使用 HTTPS 访问本域名及其子域名。

注意事项:

  • HSTS 一旦下发便持续生效,回退 HTTP 需等待缓存过期,配置证书前请确认 HTTPS 稳定可用;
  • 使用 CDN 或反向代理时,请按第 5.2 节配置可信代理,避免协议与真实 IP 判断失真;
  • 「基本设置」中的站点地址建议同步改为 HTTPS,避免页面内资源走 HTTP 引发混合内容告警。

8. 应急响应

8.1 疑似入侵后的排查步骤

  1. 立即止损:开启维护模式或把站点状态设为「关闭」(见第 4.8 节);修改管理员密码与数据库密码;
  2. 检查登录日志:系统在 storage/logs/ 下按类别记录日志(如 login-*.log、security-*.log),重点查看:
    • login 类别中的「用户登录失败」记录(含用户名、IP、尝试次数);
    • security 类别中的「后台访问被拦截」记录(含 IP、URL、User-Agent);
  3. 检查上传目录:浏览 uploads/ 各子目录,排查是否存在近期新增、命名异常的可疑文件(尤其非图片扩展名的文件),发现后立即删除;
  4. 检查后台账号:「用户管理」中确认管理员角色账号数量与最后登录时间,移除陌生账号;
  5. 检查数据库:通过数据库工具检查 bk_users 表是否存在陌生的管理员角色账号、bk_config 表中安全相关配置(上传开关、白名单、站点地址等)是否被篡改;启用了「开放API」插件的话,同时核对 API 密钥列表;
  6. 检查配置文件:「安全设置」确认 IP 白名单、上传开关等未被篡改;core/config/ 下文件确认未被改动;
  7. 核对文件完整性:与官方 GitHub 仓库 对比 core/、app/、index.php、admin.php 等核心文件是否被篡改;
  8. 核对 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 节全新安装:

  1. 先备份现有数据库与 uploads/ 附件;
  2. 删除站点根目录的 install.lock(此操作将允许安装器重新运行);
  3. 部署官方最新源码包(覆盖可疑文件),重新运行安装向导;
  4. 通过后台「数据迁移」工具导入备份数据,重装所需插件。

相关文档