免责声明本文仅用于技术学习与研究,所有操作均在合法授权的靶场环境(DVWA / sqli-labs/pikachu)中进行。请勿将本文所述方法用于任何未授权测试,否则可能违反《网络安全法》
《刑法》并承担相应法律责任。
| 维度 | XSS | CSRF | SSRF |
|---|---|---|---|
| 全称 | Cross-Site Scripting(跨站脚本) | Cross-Site Request Forgery(跨站请求伪造) | Server-Side Request Forgery(服务端请求伪造) |
| 攻击对象 | 浏览器端用户 | 已登录用户的浏览器 | 服务器 |
| 触发位置 | 客户端 JS 执行 | 利用用户身份发请求 | 服务器发起内网请求 |
| 核心利用 | 信任用户的输入未过滤 | 信任用户的身份(自动携带 Cookie) | 信任用户提供的 URL |
| 危害 | 盗 Cookie、钓鱼、挂马、内网探测 | 改密码、转账、发布内容 | 读内网文件、攻击内网服务、获取云元数据 |
| 利用前提 | 反射/存储/DOM 注入点 | 目标站点无 CSRF Token | 服务器能请求用户传入的 URL |
| 防御 | 输出编码、CSP、HttpOnly | Token 校验、Referer 校验、SameSite | URL 白名单、内网隔离、协议限制 |
跨域
跨域就是协议、域名、端口三者其一发生变化就是跨域
xss(跨站脚本攻击)
原理
攻击者通过在web页面注入恶意脚本代码(通常是javascript),当其他用户访问该页面时,恶意脚本代码通过用户浏览器执行发生获取用户cookie、sessionid、劫持用户、钓鱼等行为。
攻击对象
因为xss的攻击行为是发生在客户端浏览器、所以其攻击对象是客户端浏览器。
触发位置
客户端浏览器
核心利用
信任用户的输入未过滤
类型
反射型、存储型、DOM型
其中反射型和DOM是非持久化的当客户端浏览器刷新后就会消失,而存储型是持久化的因为其存储在服务端的当每个用户访问该页面都会触发,所以存储型的危害是最大的。
危害
盗cookie、钓鱼、挂马、内网探测、盗取键盘记录
绕过方式
-
大小写绕过
-
双写绕过
-
编码绕过
-
标签替换
[外链图片转存中...(img-Aq5Nd0a6-1787469958610)]
-
协议绕过
-
标签闭合
-
注释绕过
防御方式
-
输出编码
-
输入过滤
-
重要操作进行二次验证
csrf(跨站请求伪造)
原理
攻击者诱导已经保持系统登录状态的用户点击恶意链接、利用用户身份向目标网站发送请求、目标网站认为是用户主动发起的请求从而执行恶意操作。
攻击对象
已保持登录状态的浏览器用户。
核心利用
信任用户的身份(自动携带 Cookie)
触发位置
客户端浏览器;但是触发条件极其苛刻必须满足一下两个条件:
用户必须保持目标系统的登录状态
用户必须点击恶意链接
如果csrf要攻击成功这两个条件必须同时成立。
类型
- get型
get型是最简单的、恶意请求是直接拼接在url地址中。
<!-- 通过图片加载自动触发 -->
<img src=”http://bank.com/transfer?to=hacker&amount=10000” width=”0” height=”0” />
<!-- 通过链接诱导点击 -->
<a href=”http://bank.com/delete-account”>点击领取大奖</a>
- post型
当目标接口要求 POST 请求时,攻击者需构造一个自动提交的隐藏表单,页面加载后通过 JS 自动提交。
document.getElementById('csrf-form').submit();
======
- json型
针对只接受 JSON 格式的 API,攻击者可利用 的 enctype="text/plain" 属性来构造畸形请求体,使服务器端解析为合法 JSON。
var xhr = new XMLHttpRequest();
xhr.open('POST', 'http://bank.com/transfer', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.withCredentials = true;
xhr.send(JSON.stringify({to: 'attacker', amount: 10000}));
======
const form = document.createElement('form');
form.method = 'POST';
form.action = 'http://api.example.com/update';
form.enctype = 'text/plain';
const input = document.createElement('input');
input.name = '{”to”:”attacker”,”amount”:1000,”ignore”:”';
input.value = '”}';
form.appendChild(input);
document.body.appendChild(form);
form.submit();
- ajax型
用 fetch 或 XMLHttpRequest 发起跨域请求,并通过 credentials: 'include' 携带目标站点的 Cookie。
fetch('http://bank.com/change-email', {
method: 'POST',
credentials: 'include',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({email: 'hacker@evil.com'})
});
========
危害
转账、发布内容、改密码等。
绕过方式
了解即可;触发方式极其苛刻、因为要触发csrf攻击要同时满足用户保持目标系统登录状态和用户点击恶意链接。
1:referer校验绕过
2:token校验绕过
3:origin/referer校验绕过
====绕过方式===
查看常见web漏洞总结_V6.1.docx
防御方式
了解即可
1:token绑定
2:SameSite Cookie
3:orgin/referer校验
4:自定义请求头(AJAX 专用)
5:关键操作进行二次确认
4:不使用get做关键操作
==========完整防御方式==========
# Flask 完整 CSRF 防御
from flask import Flask, request, session, abort
from functools import wraps
import secrets
app = Flask(__name__)
app.secret_key = secrets.token_hex(32)
def csrf_protect(f):
@wraps(f)
def decorated(*args, **kwargs):
if request.method in ('POST', 'PUT', 'DELETE', 'PATCH'):
token = request.headers.get('X-CSRF-Token') or request.form.get('csrf_token')
if not token or token != session.get('csrf_token'):
abort(403)
return f(*args, **kwargs)
return decorated
def generate_csrf_token():
if 'csrf_token' not in session:
session['csrf_token'] = secrets.token_urlsafe(32)
return session['csrf_token']
app.jinja_env.globals['csrf_token'] = generate_csrf_token
@app.route('/transfer', methods=['POST'])
@csrf_protect
def transfer():
# 业务逻辑
return 'OK
ssrf(服务端请求伪造)
ssrf内网穿透路径
+======================================================================+
| SSRF 内网穿透路径 |
+======================================================================+
[外部攻击者]
|
| 1. 寻找 SSRF 入口
| target.com/proxy?url=...
v
[目标应用]
|
| 2. URL = http://internal-api.local/admin
| (用户输入, 服务器发起请求)
v
+---+----------------------+
|SSRF 漏洞点| proxy.php?url=...|
+---+----------------------+
|
| 3. 服务端发起请求 (带内网访问权, 通常不受防火墙限制)
v
[内网应用/服务] (172.16.x.x, 10.x.x.x, 192.168.x.x)
|
+---+---+---+---+---+---+
| | | | | | |
v v v v v v v
Redis MySQL FastCGI Admin SMTP CloudMeta File
6379 3306 9000 :80 :25 169.254.169.254 file://
| | | | | | |
v v v v v v v
写公钥 读文件 代码执行 读后台 伪造 偷 IAM 读系统
Webshell 反弹 数据 邮件 凭据 配置
| | | | | | |
+---+---+---+---+---+---+
|
| 4. 敏感数据通过 SSRF 响应回传给攻击者
v
[外部攻击者] 获得:
- 内网应用访问权
- 用户凭据 / IAM Token
- 系统文件 / 配置
- RCE (Redis/FastCGI)
+======================================================================+
常见 SSRF 入口:
- 图片代理 / 文件下载 / 短链
- 转码 / 截图 / OCR / 离线预览
- RSS 聚合 / API 网关
- 微信/QQ OAuth 头像获取
- PDF/DOCX 内嵌外部资源
协议选择优先级:
curl_exec → 全协议 (HTTP/HTTPS/FILE/FTP/GOPHER/DICT/LDAP) 最强
file_get_contents → HTTP/HTTPS/FILE/FTP + php://data://phar://
fsockopen → 纯 TCP (发任意字节)
Java URLConnection → HTTP/HTTPS/FILE/FTP/JAR
Node.js / Go / C
# → 仅 HTTP/HTTPS
+======================================================================+
原理
攻击者能够控制服务器发起的请求、诱使服务器访问攻击者指定的内部或外部资源。
攻击对象
因为是直接控制服务器发送请求的、所以攻击对象是服务器。
触发位置
服务器内部
核心利用
信任用户提供的 URL
危害
读内网文件、攻击内网服务、获取云元数据
-
内网探测(攻击内网服务)
-
读取文件
-
云元数据访问
利用前提
服务器能请求用户传入的 URL
绕过方式
-
IP黑名单绕过
-
协议黑名单绕过
-
302跳转绕过
防御方式
-
协议白名单
-
域名/IP黑名单
-
解析URL后验证IP
-
限制端口
-
禁止跟随重定向/重定向后再次校验
-
关闭不需要的协议
-
使用统一资源访问服务:
不要让用户直接输入 URL。如果可能,将资源下载功能封装在后端,用户只能选择预定义的资源 ID。
- 网络隔离
将需要访问外网的应用服务器与核心内网服务(数据库、缓存等)进行网络隔离,即使发生 SSRF,攻击者也无法触达核心资产。
- 错误信息处理
不要将详细的错误信息(如堆栈跟踪、连接超时信息)直接返回给用户,这会帮助攻击者判断端口开放情况。
思考总结
本篇文章是本人的学习总结、可能不是很全面、文章中有不足的望大家批评指正。
🤔 学完考一考(评论区写下答案,全对的我置顶!)
1.(判断题)反射型 XSS 和存储型 XSS 的本质区别是:存储型会持久化在服务端,每个访问用户都会触发。
2.(判断题)CSRF 要攻击成功,用户只需要保持登录状态就行,不需要其他条件。
3.(选择题)SSRF 中,攻击者访问 169.254.169.254 这个地址,目的是什么?
A. 探测内网 MySQL 端口
B. 获取云服务器元数据(可能拿到 IAM 临时凭据)
C. 读取本地 /etc/passwd
4.(送分题)以下哪个能自动触发 GET 型 CSRF,不需要用户点击?
A. 一个"点击领奖"链接,点击后访问转账接口
B.一个隐藏的图片标签,img 的 src 直接指向转账接口
C. 以上都不能
──────────────────
⚡ 互动投票:三个漏洞,你觉得哪个最"阴"?
A. XSS —— 你只是打开网页,就中招了
B. CSRF —— 你什么都没做,钱没了
C. SSRF —— 攻击者绕过了防火墙,直接打进内网
评论区站队 + 说理由,我挑一条最精彩的置顶!
📌 文中提到的绕过手法(大小写、双写、编码、DNS Rebinding……)你印象最深的是哪个?或者你在实战里遇到/用到过哪种,欢迎来评论区分享。
──────────────────
一句话记住这三个漏洞:
XSS——用户输入,永远别信
CSRF——你什么都没做,攻击就完成了
SSRF——外网的一根针,内网的一扇门
觉得有用的话,点个赞 + 在看,转发给还在"裸奔"写代码的同事。