xss漏洞主要分为反射型、存储型和dom型三种。区分它们的核心依据是恶意脚本的来源与执行路径:反射型需要用户点击包含payload的链接,脚本由服务器临时返回;存储型将payload持久化保存在数据库或文件中,任何访问该页面的用户都会中招;dom型则完全在浏览器端通过javascript操作dom树完成,不经过服务端处理。

反射型XSS的工作流程是怎样的
反射型XSS(Reflected XSS)要求攻击者构造一个包含恶意脚本的URL,诱骗受害者点击。当受害者请求该URL时,服务器端的代码通常会直接读取URL中的参数(如搜索关键词),并将其未经充分过滤地嵌入到HTML响应中返回给浏览器。浏览器解析这段包含<script>标签的响应时,就会执行其中的恶意代码。这种攻击是一次性的,脚本不会在服务器上留下痕迹。</script>

from flask import Flask, request, render_template_string
app = Flask(__name__)
@app.route('/search')
def search():
# 获取URL参数 q
query = request.args.get('q', '')
# 直接将用户输入渲染到模板中,未做转义
template = 'You searched for: <b>{{ query }}</b>'
return render_template_string(template, query=query)
if __name__ == '__main__':
app.run(debug=True)
预期结果:当访问 /search?q=<script>alert(1)</script> 时,页面会弹出一个警告框,显示“1”。这是因为 query 变量被直接插入到了HTML中,浏览器将其识别为可执行脚本。
存储型XSS的危害范围有多大
存储型XSS(Stored XSS),也称为持久型XSS,其危险性远高于反射型。攻击者提交的恶意脚本会被服务器接收并保存到后端数据库、日志文件或文件系统中。随后,当其他用户浏览受影响的页面(如查看帖子、评论列表)时,服务器会从数据库中取出这些恶意数据,并将其作为正常内容发送给受害者的浏览器。这意味着一次注入,永久生效,所有访问该页面的用户都可能成为受害者,无需诱导点击特定链接。

import sqlite3
from flask import Flask, request, render_template_string
app = Flask(__name__)
db = sqlite3.connect('test.db')
cursor = db.cursor()
cursor.execute('CREATE TABLE IF NOT EXISTS comments (id INTEGER PRIMARY KEY, content TEXT)')
db.commit()
@app.route('/comment', methods=['POST'])
def add_comment():
content = request.form.get('content', '')
# 将用户输入直接存入数据库
cursor.execute("INSERT INTO comments (content) VALUES (?)", (content,))
db.commit()
return 'Comment added'
@app.route('/view')
def view_comments():
cursor.execute('SELECT content FROM comments')
comments = cursor.fetchall()
# 直接从数据库取出数据并渲染,未做转义
html = '' + ''.join(['<p>' + c[0] + '</p>' for c in comments]) + ''
return html
if __name__ == '__main__':
app.run(debug=True)
预期结果:首先通过POST请求提交 content=<script>alert(document.cookie)</script>,然后访问 /view 页面。此时,所有加载该页面的用户浏览器都会执行 alert(document.cookie),窃取当前用户的Cookie信息。脚本被存储在数据库中,每次访问 /view 都会触发。
DOM型XSS在服务端有交互吗
DOM型XSS(DOM-based XSS)与前两种类型的最大区别在于它不涉及服务端的逻辑处理。恶意脚本的执行完全发生在客户端的JavaScript代码中。攻击者构造的Payload通常通过URL片段(Hash部分)、查询参数或其他客户端数据源进入页面。前端JavaScript代码在读取这些数据源后,使用不安全的方法(如 innerHTML、 document.write() 或 eval())将其写入DOM树中,从而触发脚本执行。由于整个过程都在浏览器内完成,服务器可能根本不知道Payload的存在,因此传统的WAF(Web应用防火墙)往往难以检测。
<div id="output"></div>
<script>
// 获取URL中的hash部分
const hash = window.location.hash.substring(1);
// 直接将hash内容写入DOM,未做转义
document.getElementById('output').innerHTML = hash;
</script>
预期结果:当访问 page.html# 时,页面中的 div 元素会被插入 标签,触发 onerror 事件弹出警告框。服务器只返回静态HTML文件,不参与Payload的处理和返回过程。











