技术学院 / 网络安全防护基础

网络安全防护基础

进阶

识别扫描与爆破、配置基础防护,看懂恶意 IP 情报。

6 章 · 30 节 · 约 14 分钟 · 更新于 2026-09-28 · 免费

章节
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 注入、命令注入、模板注入,本质都是把数据当成了代码。解决办法不是过滤关键字(永远过滤不全),而是从机制上让数据没机会变成代码:

php
// 错误:拼接,参数里放个引号就出事
$sql = "SELECT * FROM user WHERE name = '" . $_GET['name'] . "'";
 
// 正确:参数化查询,值永远是值
$stmt = $pdo->prepare('SELECT * FROM user WHERE name = ?');
$stmt->execute(array($_GET['name']));
php
// 命令注入同理:别拼字符串
exec('ping -c 1 ' . $_GET['host']);              // 危险
exec('ping -c 1 ' . escapeshellarg($_GET['host'])); // 好一些,但更该用白名单校验

「用正则过滤危险关键词」是最常见的错误思路,SeLeCt、/**/、编码变形都能绕过去。要校验就用白名单:这个参数只能是数字、只能是预定义的几个值之一。

XSS 的三种形态

类型特点
反射型恶意内容在 URL 里,诱导点击才触发
存储型已经存进数据库,所有访客都中招,危害最大
DOM 型完全在前端发生,服务端日志里看不到

防御的核心是按输出位置转义:进 HTML 文本用 HTML 实体转义,进标签属性要带引号并转义,进 JavaScript 上下文要 JSON 编码,进 URL 参数要 URL 编码。用错地方等于没转义。

再加一道 CSP 兜底:

text
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'

几个立刻该加的响应头

nginx
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 直接存。 通用哈希是为「快」设计的,而存口令恰恰需要「慢」,才能让爆破无利可图。要用专门的口令哈希算法:

php
// 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 位数字。它不依赖网络,也没法被重放太久。

text
code = HOTP(secret, floor(unix_time / 30))

服务端实现时要注意:允许前后一个时间窗的偏差(时钟不同步),同一个码用过就作废(否则被钓到的码在 30 秒内还能再用一次),备用恢复码要一次性且单独哈希存储。想看一个 secret 当前的验证码是多少,用 TOTP 两步验证码。

挡住爆破

nginx
# 对登录接口单独限速:每 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 在线生成。

恶意 IP 识别

日志里天天都有扫描,关键是分清「无害的背景噪音」和「真正针对你的攻击」。

先从日志里筛

bash
# 请求量 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 被扫到必须自查——这两个文件一旦真的能访问,等于数据库密码和全部源码直接送人。

nginx
location ~ /\.(?!well-known) {
    deny all;
}

判断这个 IP 是什么来头

拿到可疑 IP 后,用 IP 地址查询看归属:是国内运营商的家宽,还是境外机房的 IDC 段?机房段跑爬虫和扫描居多,家宽段更可能是真实用户(或者代理)。整段的范围用 IP 段与 CIDR 互转算出来,封的时候按段封比按单个 IP 封有效得多。

封之前务必排除搜索引擎蜘蛛:把真蜘蛛封了,收录会掉得很难看。验证方法见 SEO 那门课的「蜘蛛 IP 识别」,IP 段对照在搜索引擎蜘蛛 IP 地址大全。

封禁的几个层次

层次手段特点
应用层业务代码里的黑名单最灵活,但请求已经消耗了资源
nginxdeny、geo + map、limit_req够用,改配置 reload 即可
系统iptables / ipset性能好,适合大量 IP
网络层云平台安全组、高防流量根本到不了机器
bash
# 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

别把 X-Forwarded-For 当身份

用了 CDN 或反向代理之后,$remote_addr 是代理的 IP,真实客户端 IP 在 X-Forwarded-For 里。但这个头客户端可以随便伪造,直接拿它做黑白名单等于没做。

正确做法是只信任你自己的代理层:

nginx
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 基础

WAF(Web 应用防火墙)在应用前面拦一道,按规则识别恶意请求。它的定位要摆正:WAF 是补丁,不是修复。代码里的注入漏洞该改还得改,WAF 只是给你争取时间、挡掉自动化工具。

三种部署形态

形态例子特点
云 WAF各云厂商的 Web 应用防火墙改 DNS 即可接入,同时挡 CC,省心但按流量计费
反代模块ModSecurity + OWASP CRS、nginx 内置指令自己可控,要自己调规则
应用内框架中间件能拿到业务上下文,最精准

不装 WAF 也能做的基础防护

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 最大的成本不是部署,是误拦。上线节奏应该是:

  1. 先开观察模式(只记录不拦截)跑一两周;
  2. 看日志里被判为恶意的请求,挑出正常业务被误伤的,加白名单;
  3. 再切到拦截模式;
  4. 持续看拦截日志,每次业务上线新接口都要复查一遍。

直接开拦截模式上线,通常第二天就会收到「后台发文章保存不了」这类反馈——富文本里带 HTML 标签,太容易撞上 XSS 规则。

CC 与 DDoS 要分开看

CCDDoS
打什么应用层,专挑耗资源的接口网络层,纯拼带宽
流量特征流量不大,但请求都很贵流量极大
自己能防吗能:限速、缓存、验证码基本不能,带宽先被打满
对策限速 + 页面缓存 + 人机校验上高防 / 流量清洗,或临时切换 IP

真被打大流量 DDoS 时,源站 IP 已经暴露,换 IP 并把真实 IP 藏到 CDN 后面才是解法。日常就要注意别让源站 IP 泄漏:历史 DNS 记录、邮件服务器、证书透明日志、子域名解析,都是常见的泄漏点。确认一下自己域名的解析面有多大,用网站综合信息和全国 DNS 解析分布看一遍。

HTTPS 与传输安全

传输层做对了,能一次性消灭一大类问题:明文口令被嗅探、页面被运营商插广告、内容被中间人篡改。

最低要求

项要求
协议版本只留 TLS 1.2 / 1.3
加密套件只用带前向保密(ECDHE)的 AEAD 套件
全站 HTTPS不要只给登录页加密,Cookie 会在其他页面被明文带出去
HSTS确认全站可用后再开,先用小的 max-age
CookieSecure + 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 出口检测看实际走哪

令牌与密钥的保管

  • API 密钥、数据库口令不进代码仓库,用环境变量或配置中心;
  • .env、config.php 这类文件确保 Web 不可访问(见上一章的 nginx 规则);
  • 令牌设短有效期 + 刷新机制,JWT 尤其如此,因为它签发后无法撤销;
  • 前端代码里的任何东西都是公开的,别把密钥写进 JS。

拿到一个令牌想看看里面装了什么、有效期多久,用 JWT 在线解析——顺便体会一下它为什么不能放敏感信息。

应急响应流程

出事的时候最怕两件事:慌乱中把证据毁了,以及清理不干净反复被打。按流程走。

第一步:止血,但先留证

bash
# 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 更稳妥)

别急着重启:一重启内存里的进程信息、临时文件、网络连接全没了,很多线索就断了。也别急着删文件,先备份。

第二步:看现状

bash
# 可疑的对外连接(挖矿、反弹 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/

倒数第二条和最后一条最值得先查:攻击者进来之后加一个高权限账号或者塞一把公钥,是最常见的持久化手段。

第三步:定位入口

对着访问日志找那个时间点前后的异常请求:

bash
# 假设发现 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查询网 原创,正文中的命令与配置片段可直接取用。 内容会随实践持续修订,发现错漏欢迎反馈。