网站慢排查实录:证书、CDN 与诊断方法论的教训

一、今天做了什么 1. 域名解析:renjiaxing.ren 的 A 记录 → 154.8.147.160(10 分钟生效) 2. 免费证书:申请腾讯云 90 天免费 DV 证书(TrustAsia CA) 3. 配置 HTTPS:Nginx 加载证书,HTTP 自动跳转 HTTPS 4. 排查"网站加载慢":最终发现是模板引用的境外 CDN 资源被墙 5. 资源本地化:font-awesome、jquery 下载到本地 static/,删除 busuanzi、mermaid 二、排查全程回顾(走弯路的每一步) 现象 电脑浏览器打开网站要 15-30 秒才出页面。手机秒开。 弯路 1:怀疑 Let’s Encrypt 证书的 OCSP 被墙 当时的证书:Let's Encrypt Windows curl 报错:CRYPT_E_REVOCATION_OFFLINE(吊销服务器离线) 分析:LE 的 OCSP 服务器在国内被墙,Windows schannel 检查吊销失败 行动:换腾讯云 TrustAsia 证书 结果:curl 不报错了,但 TLS 握手还是 15 秒——问题没解决 弯路 2:怀疑 TrustAsia 证书链的吊销检查 测试了所有吊销检查端点: ✓ 叶子证书 OCSP —— 0.19 秒(快) ✓ 中间证书 OCSP —— 快 ✓ 中间证书 CRL —— 快 ✓ 交叉根证书 CRL —— 0.29 秒(快,762 字节合法 CRL) 分析:TrustAsia 的"根证书"实际是波兰 Certum 交叉签发的, 怀疑 Windows 把交叉根当中间证书查 CRL → 查 Certum 波兰服务器超时 行动:开启 OCSP Stapling(服务器把吊销状态钉在握手包里) 结果:stapling 生效了(OCSP Response Status: successful), curl 还是 15 秒——问题依旧 弯路 3:怀疑 Windows 客户端自身 测试: ✓ 所有吊销检查 URL 直连都快 ✓ 服务器本地握手 4 毫秒 ✓ curl --ssl-no-revoke 秒过(证明问题在吊销检查) ✓ 手机同一 WiFi 秒进(排除网络路径问题) 行动:禁用 Windows 自动根证书更新(CTL 更新) 结果:curl 变快了!但浏览器还是慢——问题还在 弯路 4:真正的答案——F12 网络面板 浏览器 F12 → Network 标签 → 刷新 → 看到两个请求卡 30 秒: https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css https://cdn.jsdelivr.net/npm/jquery@3.6.3/dist/jquery.min.js 真相:jsDelivr CDN 在国内被墙! 模板 extend_head.html 是从 sulv 博客样例复制来的, 里面带了三个境外 CDN 引用:jsDelivr(两个)+ busuanzi 统计。 浏览器加载页面时死等这些资源超时——这就是"网站慢"的真正原因。 三、为什么一开始找不到? 复盘诊断过程,犯了三个错误: ...

August 20, 2026 · 3 min · 536 words

SQL 注入 Impossible(4):PHP 源码分析与四级对比

概述 DVWA SQL 注入的四个等级中,Impossible 不是让你攻破的——它是安全样例,告诉你"如果一开始就写对,前面那些漏洞根本不会存在"。本文逐一拆解四级源码,以 Impossible 为重点,看它如何从根源上消除 SQL 注入。 一、Low:裸奔 $id = $_REQUEST[ 'id' ]; $query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $query); 问题清单 问题 代码体现 后果 无过滤 直接 $_REQUEST['id'] 进 SQL 输入即代码 字符型拼接 WHERE user_id = '$id' — 引号包裹 ' 可用于闭合字符串上下文 报错暴露信息 or die(...mysqli_error()...) 攻击者看到语法错误,帮助调试 payload 为什么 1' or '1'='1' # 能打穿 -- 拼接后: SELECT ... WHERE user_id = '1' or '1'='1' #' -- ↑ 闭合 ↑ 注入 ↑ 注释吞尾 攻击者的 ' 提前结束了字符串字面量,or '1'='1' 进入代码上下文,# 吞掉尾部多余引号。数据越界变成了代码。 ...

August 4, 2026 · 4 min · 692 words

SQL 注入 High(3):分页注入与三级对比总结

High 的变化 DVWA High 的 SQL 注入与 Low/Medium 不同——输入页面和结果页面分开了。 Low/Medium: 一个页面 — 上面输入框,下面结果 High: 两个页面 — Session 页面(输入 payload)→ 结果页面(看输出) 在 SQL Injection 主页面看到的是 “Click here to change your ID”,点击后弹出新页面输入 ID,Submit 后回到主页面看结果。 后端做了什么 High 的 PHP 源码逻辑: // 结果页面(sqli.php): if (isset($_SESSION['id'])) { $id = $_SESSION['id']; $query = "SELECT first_name, last_name FROM users WHERE user_id = '$id'"; // 执行查询,显示结果 } // 输入页面(sqli_session.php): $_SESSION['id'] = $_POST['id']; Payload 存在 PHP session 变量里,两个页面通过 $_SESSION['id'] 共享同一个值。SQL 语句本身没有任何变化——字符型注入,没有任何过滤。 ...

August 4, 2026 · 2 min · 400 words

SQL 注入 Medium(2):数字型注入与 Burp Suite 绕过

Medium 的变化 DVWA Medium 相比 Low 加了三道防线: 防线 Low Medium 有效吗 输入方式 文本框 下拉菜单(1-5) ⚠️ 前端限制,可绕过 请求方式 GET POST ⚠️ 换种发请求的方式 后端过滤 无 mysqli_real_escape_string() 转义 ' ❌ 数字型没有引号可转 关键发现:Medium 后端 SQL 是数字型——WHERE user_id = 1,没有单引号包裹参数。 绕过下拉菜单:curl + Burp Suite 代理 环境 Kali Firefox → Burp Suite (127.0.0.1:8081) → DVWA (127.0.0.1:8080) SSH 隧道:Kali 8080 → mycvm 127.0.0.1:8080(DVWA 容器) Burp 代理:Kali 8081 → 截获/修改请求 → 转发到 8080 Burp Suite 配置 Kali 桌面搜 burp → Burp Suite Community → Temporary project → Use Burp defaults → Start Proxy → Options → Proxy Listeners → 确认/添加 127.0.0.1:8081 Firefox → Settings → Network Settings → Manual proxy → 127.0.0.1:8081 → 勾选 “Also use this proxy for HTTPS” 用 curl 绕过下拉菜单 DVWA Medium 的 SQL Injection 使用 POST 请求。curl 直接发 POST,不受前端下拉菜单限制: ...

August 4, 2026 · 4 min · 650 words

SQL 注入 Low(1):字符型注入与手工测试流程

第一部分:SQL 注入概述 什么是 SQL 注入 SQL 注入(SQL Injection)是将恶意的 SQL 语句片段插入到应用程序的输入参数中,让后端数据库误以为这是合法的查询指令并执行它。 简单说:你的输入被当作代码执行了。 正常请求: 浏览器 → 输入 user_id=1 → 服务器 → SQL: SELECT * FROM users WHERE id='1' → 返回 admin 注入请求: 浏览器 → 输入 user_id=1' or '1'='1' # → 服务器 → SQL 被篡改 → 返回全部用户数据 为什么 SQL 注入能成立 三个条件同时满足: 用户输入直接拼接到 SQL 语句中(没有参数化查询) 输入中的特殊字符('、"、--、#)没有被转义或过滤 数据库把拼接后的字符串当作 SQL 执行 这三个条件缺一个,注入就不成立。 注入的本质:脱离数据上下文,进入代码上下文 SELECT * FROM users WHERE id = '1' │ │ │ └── 后引号(后端写死的) └── 前引号(后端写死的,你的输入从它后面开始) -- 正常输入时,你的数据在引号里——是"数据" -- 你的输入里包含 ' 后,你提前闭合了引号——后面的内容进入了"代码"区域 -- 这就是注入的本质 什么是 Payload Payload = 攻击载荷 = 你精心构造的那段输入字符串。 ...

August 4, 2026 · 5 min · 1027 words

SQL 注入基础:字符型注入与手工测试流程

第一部分:SQL 注入概述 什么是 SQL 注入 SQL 注入(SQL Injection)是将恶意的 SQL 语句片段插入到应用程序的输入参数中,让后端数据库误以为这是合法的查询指令并执行它。 简单说:你的输入被当作代码执行了。 正常请求: 浏览器 → 输入 user_id=1 → 服务器 → SQL: SELECT * FROM users WHERE id='1' → 返回 admin 注入请求: 浏览器 → 输入 user_id=1' or '1'='1' # → 服务器 → SQL 被篡改 → 返回全部用户数据 为什么 SQL 注入能成立 三个条件同时满足: 用户输入直接拼接到 SQL 语句中(没有参数化查询) 输入中的特殊字符('、"、--、#)没有被转义或过滤 数据库把拼接后的字符串当作 SQL 执行 这三个条件缺一个,注入就不成立。 注入的本质:脱离数据上下文,进入代码上下文 SELECT * FROM users WHERE id = '1' │ │ │ └── 后引号(后端写死的) └── 前引号(后端写死的,你的输入从它后面开始) -- 正常输入时,你的数据在引号里——是"数据" -- 你的输入里包含 ' 后,你提前闭合了引号——后面的内容进入了"代码"区域 -- 这就是注入的本质 什么是 Payload Payload = 攻击载荷 = 你精心构造的那段输入字符串。 ...

August 4, 2026 · 5 min · 1027 words

Linux 基础:tmux 和 vim 操作

一、tmux — 终端复用器 它解决什么问题 SSH 连接到远程服务器时,一旦网络断开或关闭终端窗口,正在运行的程序(比如 hugo server、apt install)会被强制终止。 tmux 在用户和服务器之间插入了一个持久层——你关掉终端、断开 SSH,tmux 里的程序继续跑。下次连上,tmux a 一切恢复原样。 普通 SSH: SSH + tmux: 你 ──SSH── 服务器 你 ──SSH── 服务器 │ │ 跑程序 tmux(持久层) │ │ SSH 断开 → 程序死 SSH 断开 → tmux 里的程序继续跑 下次连上 → tmux a → 恢复 层级结构 tmux 服务 ├── session 0(工作区 A:博客开发) │ ├── window 0(这个窗口跑 hugo server) │ │ ├── pane 0(左边:编辑 config.yml) │ │ └── pane 1(右边:看日志) │ └── window 1(这个窗口跑 docker) │ └── pane 0 ├── session 1(工作区 B:渗透练习) │ ├── window 0(DVWA 目录) │ └── window 1(查资料) └── session 2 session = 独立工作区,window = 浏览器标签页,pane = 分屏。 你在一个 session 里"挂起"(detach),另一个终端可以"接入"(attach),无缝切换。 ...

August 1, 2026 · 5 min · 865 words

Linux 文件管理及常用命令

一、Linux 文件系统的核心哲学 一切皆文件 Linux 最根本的设计思想:系统中的一切——硬盘、目录、进程、键盘、网络连接——在操作系统眼里都是"文件"。 /dev/sda ← 你的硬盘,是个文件 /proc/cpuinfo ← CPU 信息,是个文件 /etc/passwd ← 用户账号,是个文件 /home/renbudang/.ssh/id_ed25519 ← SSH 私钥,是个文件 这意味着同一套读、写、移动的操作可以作用于任何对象。你 cat /proc/cpuinfo 就能读 CPU 信息,和读一个 txt 文件没有区别。 单根树结构 Windows 的世界里,每个分区是一个独立的起点(C: / D: / E:)。Linux 的世界里,只有一个根 /,所有的硬盘、U 盘、网络存储都"挂载"到这棵树的某个分支上。 / ← 根,一切从这里开始 ├── bin/ ← 系统基础命令(ls、cp、mv 等) ├── boot/ ← 启动相关文件(内核) ├── dev/ ← 设备文件(硬盘、键盘、终端) ├── etc/ ← 配置文件(Nginx、SSH、用户信息) ├── home/ ← 普通用户的家目录 │ └── renbudang/ ← 你的家目录(~ 就指向这里) ├── tmp/ ← 临时文件(重启后清空,不保证保留) ├── var/ ← 变化的数据(日志、网站、数据库) │ └── www/html/ ← Nginx 默认网站目录 ├── proc/ ← 进程和内核信息(虚拟文件系统,不占磁盘) └── usr/ ← 用户安装的软件 路径:绝对 vs 相对 # 绝对路径——从根 / 出发 ls /home/renbudang/myblog/config.yml # 相对路径——从当前位置出发 # 假设已经在 /home/renbudang 目录下: ls myblog/config.yml # 等价于上面那条 ls ./myblog/config.yml # . 代表"当前目录",等价 ls ../ubuntu/.ssh # .. 代表"上一级目录",这里等于 /home/ubuntu/.ssh ls ~/myblog # ~ 代表"当前用户的家目录" 判断规则:第一个字符是不是 /。 ...

July 30, 2026 · 5 min · 911 words

Hugo 博客搭建与 PaperMod 配置全记录

为什么选 Hugo Hugo 是一个用 Go 写的静态网站生成器。它和 WordPress 这类动态博客的区别是: Hugo WordPress 原理 Markdown → 预生成 HTML 文件 每次访问查数据库 + 渲染 PHP 服务器要求 纯静态文件,Nginx 直接 serve 需要 PHP + MySQL 内存占用 0(只有 Nginx 的几 MB) MySQL 400M+ 安全 没有后台、没有数据库,攻击面极窄 PHP + 插件 = 常见攻击入口 写作方式 VS Code 写 Markdown 浏览器里写 速度 秒开 看服务器性能 版本控制 Git 数据库导出,不优雅 对于一台 2C2G 的轻量服务器,Hugo 是唯一正确的选择。 技术栈 云服务器:腾讯云轻量应用服务器 2C2G 3Mbps(Ubuntu 22.04) 静态生成:Hugo 0.146.5 主题:PaperMod(Gitee 镜像) Web 服务器:Nginx 部署方式:Hugo 生成 HTML → Nginx 直接 serve HTTPS:等域名备案下来后 Let's Encrypt 免费证书 博客目录结构 ~/myblog/ ├── config.yml ← 博客配置(核心文件) ├── content/ ← 所有文章和页面 │ ├── posts/ │ │ ├── 技术/ │ │ ├── 杂文/ │ │ ├── 美食/ │ │ └── 健身/ │ ├── about.md ← 关于页面 │ ├── archives.md ← 时间轴页面 │ ├── search.md ← 搜索页面 │ └── tags/_index.md ← 标签页面 ├── layouts/ ← 自定义布局(覆盖主题默认) │ ├── _default/ │ │ ├── archives.html ← 时间轴模板(来自 sulv-hugo-papermod) │ │ └── search.html ← 搜索模板 │ └── partials/ │ └── index_profile.html ← 首页 profileMode 模板 ├── assets/js/ ← 自定义 JS │ ├── fastsearch.js │ └── fuse.basic.min.js ├── static/img/ ← 静态资源(头像、二维码等) ├── themes/PaperMod/ ← Hugo 主题(不改动) └── deploy.sh ← 构建+部署脚本 config.yml 关键配置 首页:profileMode PaperMod 内置两种首页模式。homeInfoParams 是纯文字,profileMode 是头像 + 按钮布局。选择后者: ...

July 29, 2026 · 3 min · 487 words

Docker 部署 DVWA 与 SSH 隧道

Docker 部署 DVWA 与 SSH 隧道 日期:2026-07-28 前文:02_Docker与虚拟机与NAS 一、DVWA 是什么 DVWA(Damn Vulnerable Web Application) 是一个故意设计得漏洞百出的 PHP/MySQL Web 应用,用于安全从业人员练习渗透测试。 内置漏洞类型(对应 CISP-PTE Web 维度 40 分) 漏洞类型 攻击方法 CISP-PTE 覆盖 SQL 注入 联合查询 / 报错注入 / 盲注 ✅ XSS 反射型 / 存储型 / DOM 型 ✅ CSRF 跨站请求伪造 ✅ 文件包含 LFI(本地文件包含)/ RFI(远程文件包含) ✅ 文件上传 前端绕过 / MIME 绕过 / 黑名单绕过 ✅ 命令注入 RCE(远程命令执行) ✅ 暴力破解 弱口令爆破 ✅ CAPTCHA 绕过 验证码逻辑漏洞 ✅ 安全等级 Low → 无任何防护,学习漏洞原理 Medium → 有基础过滤(如 mysql_real_escape_string),但可绕过 High → 更强的防御,需要更高级的绕过技巧 Impossible → 理论上无法攻破(最佳实践级别的防御) 二、部署过程 完整命令 # 1. 拉取镜像(经中科大 Docker 镜像加速) docker pull vulnerables/web-dvwa # 2. 启动容器(仅监听本地 127.0.0.1,不暴露到公网) docker run -d --name dvwa -p 127.0.0.1:8080:80 vulnerables/web-dvwa 参数解释 参数 含义 docker pull 从镜像仓库下载 DVWA 镜像到本地 docker run -d 后台运行容器(-d = detached) --name dvwa 给容器起名 dvwa,之后用这个名字操作容器 -p 127.0.0.1:8080:80 端口映射——宿主机 127.0.0.1 的 8080 端口 → 容器内的 80 端口 vulnerables/web-dvwa 使用的镜像名 三、验证结果分析 命令 1:docker ps(查看正在运行的容器) CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 89beb5ef831d vulnerables/web-dvwa "/main.sh" 7 minutes ago Up 7 minutes 127.0.0.1:8080->80/tcp dvwa 字段 本机输出 含义 CONTAINER ID 89beb5ef831d 容器的唯一标识(与镜像 ID 不同——镜像是模板,容器是运行实例) IMAGE vulnerables/web-dvwa 基于哪个镜像创建的 COMMAND /main.sh 容器启动时执行的脚本(DVWA 的入口) CREATED 7 minutes ago 容器创建时间 STATUS Up 7 minutes Up = 正在运行(Exited = 已停止) PORTS 127.0.0.1:8080→80/tcp 端口映射——关键:只有 127.0.0.1,公网无法访问 NAMES dvwa 容器名称,之后用 docker stop dvwa 等控制它 命令 2:ss -tlnp | grep -E '22|8080'(查看端口监听状态) LISTEN 0 4096 127.0.0.1:8080 0.0.0.0:* LISTEN 0 128 0.0.0.0:22 0.0.0.0:* LISTEN 0 128 [::]:22 [::]:* 行 监听地址 端口 含义 第 1 行 127.0.0.1 8080 DVWA 容器——只监听本地回环,外网无法访问 第 2 行 0.0.0.0 22 SSH 服务——监听所有网卡,任何 IP 都能连(但只允许密钥认证) 第 3 行 [::] 22 SSH 服务 IPv6 版 0.0.0.0 和 127.0.0.1 的区别 0.0.0.0:22 → "谁来都行":公网 IP、内网 IP、127.0.0.1 都能访问 22 端口 SSH 需要这个——你从家里连服务器,走的就是公网 IP 的 22 端口 127.0.0.1:8080 → "只允许我自己":只有在本机(服务器自己)才能访问 8080 外部任何 IP 都连不上 8080——即使知道端口号也没用 DVWA 要的就是这个——靶机不能暴露给公网脚本小子 四、SSH 隧道:在保证安全的前提下让你访问靶机 为什么需要隧道 问题: 浏览器在你的 Windows 电脑上 → DVWA 在远程服务器上 但 DVWA 只监听 127.0.0.1 → 你的浏览器无法直接访问 解决: SSH 隧道 = 在你的电脑和服务器之间挖一条加密通道 你把本地 8080 端口的请求,通过 SSH(22 端口)转发到服务器的 127.0.0.1:8080 结果:浏览器打开 127.0.0.1:8080,实际上访问的是服务器上的 DVWA 隧道命令 ssh -L 8080:127.0.0.1:8080 mycvm 参数 含义 -L Local port forwarding(本地端口转发) 8080 本地(Windows)监听的端口 127.0.0.1 目标 IP——这里指服务器自己的 127.0.0.1 8080 目标端口——DVWA 容器映射出来的端口 mycvm SSH 别名,指向你的云服务器 隧道工作原理 ┌─────────────────────────────────────────────────────┐ │ 你的 Windows 电脑 │ │ │ │ 浏览器 ──→ http://127.0.0.1:8080 │ │ │ │ │ ▼ │ │ SSH 客户端(ssh -L 8080:...) │ │ 把本地 8080 的请求通过 SSH 隧道转发 │ └────────────────┬────────────────────────────────────┘ │ │ SSH 隧道(走 22 端口,全程加密) │ ┌────────────────┴────────────────────────────────────┐ │ 云服务器 │ │ │ │ SSH 服务端 ──→ 转发到 127.0.0.1:8080 │ │ │ │ │ ▼ │ │ Docker 容器(DVWA:80) │ └─────────────────────────────────────────────────────┘ 访问步骤 1. 本地 PowerShell 跑:ssh -L 8080:127.0.0.1:8080 mycvm → 保持这个窗口开着(关了隧道就断了) 2. 本地浏览器打开:http://127.0.0.1:8080 → 默认账号 admin / password → 进入后点击 "Create / Reset Database" 初始化 3. 隧道窗口 Ctrl+C → 隧道断开 → 浏览器访问不了 → 靶机关闭不影响安全 安全边界总结 公网能访问的: ✅ 22 端口(SSH)——但只允许密钥认证,暴力破解无效 公网不能访问的: ❌ 8080 端口(DVWA)——127.0.0.1 绑定 + 安全组未开放 ❌ 通过 22 端口的 SSH 隧道 → 需要先通过密钥认证才能建立隧道 结论:要访问 DVWA,必须同时满足: 1. 拥有你的私钥(id_ed25519) 2. 建立 SSH 隧道 缺少任何一个条件 → 靶机完全不可见 五、Docker 常用控制命令速查 docker ps # 查看运行中的容器 docker stop dvwa # 停止 DVWA docker start dvwa # 重新启动 docker rm dvwa # 删除容器 docker images # 查看本地所有镜像 docker system prune -a # 清理所有未使用的镜像/容器(省磁盘) 六、当前服务器状态 一台云服务器:mycvm(154.8.147.160) ├── SSH(22 端口,密钥认证) ├── Docker Engine │ ├── 镜像:vulnerables/web-dvwa │ └── 容器:dvwa(127.0.0.1:8080,仅本机访问) ├── Docker 镜像加速:中科大 + DaoCloud └── apt 源:腾讯云内网源 下一步:开始在 DVWA 上手动练习 SQL 注入(Low 等级) ...

July 28, 2026 · 3 min · 521 words