识别扫描与爆破、配置基础防护,看懂恶意 IP 情报。
| 章节 | |
|---|---|
| 01 常见攻击类型 | 3 小节 |
| 02 弱口令与爆破防护 | 4 小节 |
| 03 恶意 IP 识别 | 4 小节 |
| 04 WAF 基础 | 4 小节 |
| 05 HTTPS 与传输安全 | 4 小节 |
| 06 应急响应流程 | 5 小节 |
站长实际会遇到的攻击,九成集中在下面这几类。先认清它们分别打在哪一层,才知道该在哪一层防。
| 攻击 | 打在哪 | 典型表现 | 主要防御 |
|---|---|---|---|
| 扫描与探测 | 全站 | 日志里大量 404,路径全是 /wp-admin、/.env、/phpmyadmin | 关闭无用入口、限速 |
| 暴力破解 | 登录接口、SSH | 同一 IP 高频 POST 登录 | 限速、验证码、封禁、密钥登录 |
| SQL 注入 | 数据层 | 参数里出现 ' or 1=1、union select | 参数化查询 |
| XSS | 浏览器 | 用户内容里混入 <script> | 输出转义 + CSP |
| CSRF | 浏览器 | 用户在别的站上被诱导发请求 | SameSite Cookie + Token |
| 文件上传 | 服务器 | 传上来一个 .php 然后直接访问 | 白名单 + 存储目录禁执行 |
| CC / DDoS | 带宽与并发 | 流量暴涨、服务器打满 | 限速、CDN、高防 |
SQL 注入、命令注入、模板注入,本质都是把数据当成了代码。解决办法不是过滤关键字(永远过滤不全),而是从机制上让数据没机会变成代码:
// 错误:拼接,参数里放个引号就出事
$sql = "SELECT * FROM user WHERE name = '" . $_GET['name'] . "'";
// 正确:参数化查询,值永远是值
$stmt = $pdo->prepare('SELECT * FROM user WHERE name = ?');
$stmt->execute(array($_GET['name']));// 命令注入同理:别拼字符串
exec('ping -c 1 ' . $_GET['host']); // 危险
exec('ping -c 1 ' . escapeshellarg($_GET['host'])); // 好一些,但更该用白名单校验「用正则过滤危险关键词」是最常见的错误思路,SeLeCt、/**/、编码变形都能绕过去。要校验就用白名单:这个参数只能是数字、只能是预定义的几个值之一。
| 类型 | 特点 |
|---|---|
| 反射型 | 恶意内容在 URL 里,诱导点击才触发 |
| 存储型 | 已经存进数据库,所有访客都中招,危害最大 |
| DOM 型 | 完全在前端发生,服务端日志里看不到 |
防御的核心是按输出位置转义:进 HTML 文本用 HTML 实体转义,进标签属性要带引号并转义,进 JavaScript 上下文要 JSON 编码,进 URL 参数要 URL 编码。用错地方等于没转义。
再加一道 CSP 兜底:
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options SAMEORIGIN always; # 防点击劫持
add_header Referrer-Policy strict-origin-when-cross-origin always;
add_header Strict-Transport-Security "max-age=31536000" always;配完用 HTTP 请求测试或 HTTP 状态检测确认这些头真的发出来了——add_header 在有嵌套 location 且下层也写了 add_header 时会被覆盖,是很常见的失效原因。
被打穿的服务器里,绝大多数不是因为什么高深漏洞,而是口令太弱、或者到处复用。
| 做法 | 说明 |
|---|---|
| 长度优先于复杂度 | 16 位随机小写字母的强度高于 8 位「大小写+数字+符号」 |
| 不复用 | 一处泄漏等于全部泄漏,撞库就是吃这个 |
| 用密码管理器 | 唯一能同时做到「够长」和「不复用」的办法 |
| 关键账号开两步验证 | 口令泄漏后的最后一道防线 |
自己的密码大概什么水平,用密码强度检测看一眼;需要一串随机密钥用密钥生成器。
永远不要明文存,也不要用 MD5、SHA-1 直接存。 通用哈希是为「快」设计的,而存口令恰恰需要「慢」,才能让爆破无利可图。要用专门的口令哈希算法:
// bcrypt / argon2,自带随机盐,验证时不用自己取盐
$hash = password_hash($plain, PASSWORD_DEFAULT);
if (password_verify($plain, $hash)) {
// 算法或代价因子升级了就重算一次
if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
$newHash = password_hash($plain, PASSWORD_DEFAULT);
}
}| 用途 | 该用 |
|---|---|
| 存用户口令 | bcrypt / argon2id / scrypt |
| 校验文件完整性 | SHA-256 |
| 带密钥的消息认证 | HMAC-SHA256 |
| 任何安全用途 | 都不要用 MD5 / SHA-1 |
MD5、SHA-1 现在只适合做非安全场景的校验与去重,想直观看看各种摘要的结果用 MD5 / 哈希加密算法,带密钥的用 HMAC 消息认证码生成。
TOTP 的原理很简单:服务端和客户端共享一个密钥,双方各自用「密钥 + 当前 30 秒时间窗」算出同一个 6 位数字。它不依赖网络,也没法被重放太久。
code = HOTP(secret, floor(unix_time / 30))服务端实现时要注意:允许前后一个时间窗的偏差(时钟不同步),同一个码用过就作废(否则被钓到的码在 30 秒内还能再用一次),备用恢复码要一次性且单独哈希存储。想看一个 secret 当前的验证码是多少,用 TOTP 两步验证码。
# 对登录接口单独限速:每 IP 每秒 1 次,允许短时突发 5 次
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
location = /login {
limit_req zone=login burst=5 nodelay;
limit_req_status 429;
proxy_pass http://backend;
}应用层再加三条:连续失败 N 次后要求验证码、失败次数按账号也计一份(换 IP 爆同一个账号很常见)、登录失败的提示统一成「账号或密码错误」,别泄漏账号是否存在。
SSH 侧用 fail2ban 自动封禁,并且直接关掉密码登录(做法见 Linux 运维那门课)。给后台加一层 HTTP 基础认证也很划算,密码文件用 htpasswd 在线生成。
日志里天天都有扫描,关键是分清「无害的背景噪音」和「真正针对你的攻击」。
# 请求量 Top 20 的 IP
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -20
# 404 最多的 IP —— 扫描器的典型特征
awk '$9 == 404 {print $1}' access.log | sort | uniq -c | sort -rn | head -20
# 某个 IP 到底在扫什么
grep '^1.2.3.4 ' access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head -30
# 针对登录接口的高频 POST
awk '$7 ~ /login/ && $6 ~ /POST/ {print $1}' access.log | sort | uniq -c | sort -rn | head第三条最有价值:看它请求的路径就知道意图。清一色 /wp-login.php、/.env、/.git/config、/actuator/env 的是通用扫描器;反复打你某个真实业务接口的,才是针对性攻击。
顺带一提:/.env 和 /.git/config 被扫到必须自查——这两个文件一旦真的能访问,等于数据库密码和全部源码直接送人。
location ~ /\.(?!well-known) {
deny all;
}拿到可疑 IP 后,用 IP 地址查询看归属:是国内运营商的家宽,还是境外机房的 IDC 段?机房段跑爬虫和扫描居多,家宽段更可能是真实用户(或者代理)。整段的范围用 IP 段与 CIDR 互转算出来,封的时候按段封比按单个 IP 封有效得多。
封之前务必排除搜索引擎蜘蛛:把真蜘蛛封了,收录会掉得很难看。验证方法见 SEO 那门课的「蜘蛛 IP 识别」,IP 段对照在搜索引擎蜘蛛 IP 地址大全。
| 层次 | 手段 | 特点 |
|---|---|---|
| 应用层 | 业务代码里的黑名单 | 最灵活,但请求已经消耗了资源 |
| nginx | deny、geo + map、limit_req | 够用,改配置 reload 即可 |
| 系统 | iptables / ipset | 性能好,适合大量 IP |
| 网络层 | 云平台安全组、高防 | 流量根本到不了机器 |
# ipset 适合成千上万条规则,比一条条 iptables 快得多
ipset create blacklist hash:net
ipset add blacklist 1.2.3.0/24
iptables -I INPUT -m set --match-set blacklist src -j DROP用了 CDN 或反向代理之后,$remote_addr 是代理的 IP,真实客户端 IP 在 X-Forwarded-For 里。但这个头客户端可以随便伪造,直接拿它做黑白名单等于没做。
正确做法是只信任你自己的代理层:
set_real_ip_from 10.0.0.0/8; # 只有这些来源的 XFF 才采信
set_real_ip_from 172.16.0.0/12;
real_ip_header X-Forwarded-For;
real_ip_recursive on;并且确保后端服务不直接暴露在公网,否则攻击者绕过代理直连源站,伪造的头就生效了。
WAF(Web 应用防火墙)在应用前面拦一道,按规则识别恶意请求。它的定位要摆正:WAF 是补丁,不是修复。代码里的注入漏洞该改还得改,WAF 只是给你争取时间、挡掉自动化工具。
| 形态 | 例子 | 特点 |
|---|---|---|
| 云 WAF | 各云厂商的 Web 应用防火墙 | 改 DNS 即可接入,同时挡 CC,省心但按流量计费 |
| 反代模块 | ModSecurity + OWASP CRS、nginx 内置指令 | 自己可控,要自己调规则 |
| 应用内 | 框架中间件 | 能拿到业务上下文,最精准 |
# 1. 禁掉点文件(.env / .git / .svn),只放行 well-known
location ~ /\.(?!well-known) { deny all; }
# 2. 上传目录禁止执行脚本 —— 挡 WebShell 最有效的一条
location ^~ /uploads/ {
location ~ \.(php|phtml|jsp|asp|aspx|sh|py)$ { deny all; }
}
# 3. 限制请求体大小,挡大包攻击
client_max_body_size 10m;
# 4. 全站基础限速
limit_req_zone $binary_remote_addr zone=perip:10m rate=10r/s;
limit_req zone=perip burst=20 nodelay;
# 5. 隐藏版本号
server_tokens off;第二条值得单独强调:文件上传漏洞的最终危害几乎都是「传上去的文件被当成脚本执行了」。只要上传目录不解析脚本,即使白名单被绕过,危害也大幅下降。更彻底的做法是把上传文件放到独立域名或对象存储上。
WAF 最大的成本不是部署,是误拦。上线节奏应该是:
直接开拦截模式上线,通常第二天就会收到「后台发文章保存不了」这类反馈——富文本里带 HTML 标签,太容易撞上 XSS 规则。
| CC | DDoS | |
|---|---|---|
| 打什么 | 应用层,专挑耗资源的接口 | 网络层,纯拼带宽 |
| 流量特征 | 流量不大,但请求都很贵 | 流量极大 |
| 自己能防吗 | 能:限速、缓存、验证码 | 基本不能,带宽先被打满 |
| 对策 | 限速 + 页面缓存 + 人机校验 | 上高防 / 流量清洗,或临时切换 IP |
真被打大流量 DDoS 时,源站 IP 已经暴露,换 IP 并把真实 IP 藏到 CDN 后面才是解法。日常就要注意别让源站 IP 泄漏:历史 DNS 记录、邮件服务器、证书透明日志、子域名解析,都是常见的泄漏点。确认一下自己域名的解析面有多大,用网站综合信息和全国 DNS 解析分布看一遍。
传输层做对了,能一次性消灭一大类问题:明文口令被嗅探、页面被运营商插广告、内容被中间人篡改。
| 项 | 要求 |
|---|---|
| 协议版本 | 只留 TLS 1.2 / 1.3 |
| 加密套件 | 只用带前向保密(ECDHE)的 AEAD 套件 |
| 全站 HTTPS | 不要只给登录页加密,Cookie 会在其他页面被明文带出去 |
| HSTS | 确认全站可用后再开,先用小的 max-age |
| Cookie | Secure + HttpOnly + SameSite 三件套 |
| 混合内容 | HTTPS 页面里不能引 http 资源,否则被拦或降级 |
具体配置见「SSL 证书与 HTTPS 部署」那门课。配完用 HTTP/2 与 TLS 协议检测确认协商结果,用 SSL 证书检测确认证书链、有效期和域名覆盖。
运营商插广告、DNS 被污染这类问题,特点是只在部分地区、部分网络下出现,自己本地怎么试都正常。判断方法是从多个出口看同一个页面:网站劫持检测看内容有没有被注入,DNS 污染与解析一致性检测看解析结果是不是被改了。
全站 HTTPS 是对付插入式劫持最有效的办法——中间人改不了加密流量,最多只能断开。
网站本身上了 HTTPS,下面这些常常还在裸奔:
| 面 | 怎么办 |
|---|---|
| 邮件投递 | 检查 MX 是否支持 STARTTLS,用邮件服务器 STARTTLS 检测 |
| 数据库连接 | 跨机房连接开 TLS,同机房也至少走内网 |
| 内部 API | 内网不等于可信,尤其是共享环境 |
| 第三方回调 | 回调地址用 HTTPS,并校验签名 |
| WebRTC | 会暴露客户端真实 IP,用WebRTC 泄漏检测确认影响 |
| DNS 查询本身 | 明文的,考虑 DoH / DoT,用 DNS 出口检测看实际走哪 |
.env、config.php 这类文件确保 Web 不可访问(见上一章的 nginx 规则);拿到一个令牌想看看里面装了什么、有效期多久,用 JWT 在线解析——顺便体会一下它为什么不能放敏感信息。
出事的时候最怕两件事:慌乱中把证据毁了,以及清理不干净反复被打。按流程走。
# 1. 先做快照 / 打包关键证据,再动手清理
cp -a /var/log /root/incident-$(date +%F)/log
ps auxf > /root/incident-$(date +%F)/ps.txt
ss -antp > /root/incident-$(date +%F)/conn.txt
crontab -l > /root/incident-$(date +%F)/cron.txt
# 2. 断开对外访问(云平台安全组只放行你自己的 IP 更稳妥)别急着重启:一重启内存里的进程信息、临时文件、网络连接全没了,很多线索就断了。也别急着删文件,先备份。
# 可疑的对外连接(挖矿、反弹 shell 都会有)
ss -antp | grep ESTAB
# 占 CPU 最高的进程
top -b -n1 | head -20
# 最近被修改的 Web 文件 —— 找 WebShell 最快的一招
find /var/www -type f -mmin -1440 -name '*.php' -ls
# 近期新增的定时任务与启动项
crontab -l; cat /etc/crontab; ls -la /etc/cron.*
systemctl list-unit-files --state=enabled | tail -20
# 有没有新增账号,或者 UID 为 0 的非 root 账号
awk -F: '$3 == 0 {print}' /etc/passwd
lastlog | grep -v 'Never'
# 有没有被塞公钥
cat /root/.ssh/authorized_keys; ls -la /home/*/.ssh/倒数第二条和最后一条最值得先查:攻击者进来之后加一个高权限账号或者塞一把公钥,是最常见的持久化手段。
对着访问日志找那个时间点前后的异常请求:
# 假设发现 shell.php 是 9 月 20 日传上来的,就去那天的日志里找
grep '20/Sep/2026' access.log | grep -iE 'POST|upload|\.php' | less常见入口:有上传功能但没校验、老版本 CMS 或组件的已知漏洞、后台弱口令、泄漏的 .git 目录、数据库未授权访问。
| 顺序 | 动作 |
|---|---|
| 1 | 修补入口漏洞(不补就一定会被再打一次) |
| 2 | 清除 WebShell、后门、异常计划任务与启动项 |
| 3 | 全量更换凭证:所有账号口令、数据库口令、API 密钥、SSH 密钥、会话密钥 |
| 4 | 从可信备份恢复被篡改的文件,不要在被入侵的系统上「挑着改」 |
| 5 | 恢复访问,并盯着日志观察几天 |
系统被彻底控制过(拿到 root)的情况下,唯一稳妥的做法是重装系统 + 从备份恢复数据。内核模块级的后门在原系统上是查不干净的。
日常把这几件事做了,能挡掉绝大部分麻烦:关掉不必要的端口(在线端口扫描自查)、口令够强且不复用(密码强度检测)、全站 HTTPS 且证书不过期(SSL 证书检测)、及时更新组件、定期备份并演练恢复。
本文由 ip438查询网 原创,正文中的命令与配置片段可直接取用。 内容会随实践持续修订,发现错漏欢迎反馈。