某个国外的真实XSS漏洞利用探寻
字数 965 2025-08-22 18:37:22
Flask应用中的XSS漏洞利用分析与防御教学
漏洞背景
在一个基于Flask框架的Web应用中,发现存在XSS(跨站脚本)漏洞。漏洞源于开发者对用户输入的处理不完善,仅使用BeautifulSoup的html.parser进行简单的标签检测,而没有进行更严格的过滤或编码处理。
漏洞分析
1. 现有防护机制
应用中使用以下函数检查XSS:
def check_xss(smeo_text):
soup = BeautifulSoup(smeo_text, "html.parser")
tags_found = soup.find_all()
return bool(tags_found)
这个检查仅检测输入中是否存在HTML标签,但没有:
- 对特殊字符进行实体化编码
- 验证标签属性是否安全
- 检查事件处理属性(如onload, onerror等)
2. BeautifulSoup的html.parser工作机制
BeautifulSoup的html.parser使用以下正则表达式模式匹配HTML结构:
interesting_normal = re.compile('[&<]')
incomplete = re.compile('&[a-zA-Z#]')
entityref = re.compile('&([a-zA-Z][-.a-zA-Z0-9]*)[^a-zA-Z0-9]')
charref = re.compile('&#(?:[0-9]+|[xX][0-9a-fA-F]+)[^0-9a-fA-F]')
starttagopen = re.compile('<[a-zA-Z]')
piclose = re.compile('>')
commentclose = re.compile(r'--\s*>')
tagfind_tolerant = re.compile(r'([a-zA-Z][^\t\n\r\f />\x00]*)(?:\s|/(?!>))*')
attrfind_tolerant = re.compile(r'((?<=[\'"\s/])[^\s/>][^\s/=>]*)(\s*=+\s*'
r'(\'[^\']*\'|"[^"]*"|(?[^>\s]*))?')
关键点:
- 主要基于
<和>来识别标签 - 对标签属性的处理较为宽松
- 不强制要求标签闭合
3. XSS绕过技术
由于检查仅验证标签存在性,以下XSS向量可以绕过防护:
自闭合标签利用
<body/onload=alert(1)>
<svg/onload=alert(1)>
<iframe/onload=alert(1)>
不完整标签利用
HTML解析的宽松性允许不完整标签:
<img src="1" onerror="alert(1)"
浏览器会自动补全结构,将后续内容解释为属性值。
实际利用示例
在真实环境中,以下payload可以成功执行:
<img src=1 onerror=alert(1) //
注释掉后续可能存在的错误语法部分。
4. 扩大攻击面
在Flask应用中还发现其他安全问题可被组合利用:
无验证的转账功能
存在一个转账路由/transfer,如果从用户主页跳转则不需要验证:
fetch('/page', {method: 'GET'})
.then(function() {
return fetch('/transfer', {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: 'money=10000&transfer_id=21e3e7f6210'
});
})
.then(function() {
window.location.href = '/forum';
});
防御措施
1. 输入处理改进
严格过滤
from bs4 import BeautifulSoup
from html import escape
def safe_input(text):
# 先进行HTML实体编码
text = escape(text)
# 仅允许特定标签和属性
soup = BeautifulSoup(text, 'html.parser')
allowed_tags = {'b', 'i', 'u', 'em', 'strong', 'a'}
allowed_attrs = {'a': ['href', 'title']}
for tag in soup.find_all():
if tag.name not in allowed_tags:
tag.decompose()
else:
attrs = dict(tag.attrs)
for attr in attrs:
if attr not in allowed_attrs.get(tag.name, []):
del tag.attrs[attr]
return str(soup)
使用专业库
考虑使用专业的安全库如:
bleach(Mozilla维护的HTML清理库)django.utils.html.escape(Django的HTML转义工具)
2. 输出编码
确保所有动态内容在输出时进行适当的编码:
from flask import escape
@app.route('/')
def index():
user_input = request.args.get('input', '')
return escape(user_input) # 自动进行HTML实体编码
3. 内容安全策略(CSP)
设置严格的CSP头:
@app.after_request
def add_csp(response):
response.headers['Content-Security-Policy'] = "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://trusted.cdn.com; object-src 'none'"
return response
4. 会话保护
- 设置HttpOnly和Secure标志的cookies
- 实现CSRF保护
app.config['SESSION_COOKIE_HTTPONLY'] = True
app.config['SESSION_COOKIE_SECURE'] = True
app.config['SESSION_COOKIE_SAMESITE'] = 'Lax'
5. 关键操作验证
对所有敏感操作(如转账)实施严格验证:
@app.route('/transfer', methods=['POST'])
@login_required
def transfer():
form = TransferForm(request.form)
if not form.validate():
abort(400)
# 处理转账逻辑
总结
这个案例展示了:
- 仅检测标签存在性不足以防御XSS
- HTML解析器的宽松性可能被利用
- 组合漏洞可导致更严重的攻击
- 防御需要多层措施:输入验证、输出编码、CSP等
完整的安全方案应结合技术防御和开发流程中的安全实践,如代码审计、安全测试等。