python安全问题
字数 915 2025-08-22 12:22:37
Python 安全最佳实践指南
1. 断言(assert)的安全隐患
1.1 断言的主要安全问题
- 运行时被忽略:使用
python -O优化模式运行时,所有 assert 语句会被跳过 - 不适用于异常处理:不能替代正式的错误处理机制
- 敏感信息泄露:可能暴露内部状态、系统路径或错误消息
1.2 安全替代方案
# 不安全方式
assert user == "admin" and password == "secure_password", "Authentication failed!"
# 安全替代方案
if not (user == "admin" and password == "secure_password"):
raise ValueError("Authentication failed!")
- 使用显式条件检查和异常处理
- 实现安全的日志记录机制
- 对外部输入进行严格验证
2. 目录创建的安全问题
2.1 权限问题
import os
# Python 3.6+ 行为
os.makedirs("a/b/c", mode=0o700) # a:755, b:755, c:700
# Python 2.7 行为
os.makedirs("a/b/c", mode=0o700) # 所有目录:700
2.2 条件竞争风险
dir_path = "/tmp/sensitive_data"
os.makedirs(dir_path) # 临时创建
# 在此时间窗口内存在风险
os.chmod(dir_path, 0o700) # 事后设置权限
2.3 路径遍历攻击
def create_user_dir(username):
dir_path = f"/home/{username}/data" # 危险:未验证输入
os.makedirs(dir_path)
create_user_dir("../../etc") # 攻击:在/etc下创建目录
3. 路径拼接的安全问题
3.1 路径遍历攻击
import os
def save_file(upload_dir, filename):
file_path = os.path.join(upload_dir, filename) # 危险拼接
with open(file_path, 'w') as f:
f.write("This is a test file.")
save_file("/uploads", "../../etc/passwd") # 攻击:覆盖系统文件
3.2 符号链接攻击
- 攻击者可能创建符号链接指向敏感文件
- 应用程序错误信任这些符号链接会导致安全问题
3.3 绝对路径覆盖
file_path = os.path.join("/safe/directory", "/etc/passwd")
print(file_path) # 输出: /etc/passwd (忽略前面路径)
4. 临时文件安全问题
import tempfile
import os
id = "/../tmp/test" # 恶意输入
tmp_file = tempfile.NamedTemporaryFile(prefix=id, delete=False)
file_name = tmp_file.name # 可能创建在/var/www/test_zdllj17
tmp_file.close()
5. Extended Zip Slip 攻击
5.1 基本攻击方式
import zipfile
def extract_zip(zip_file, extract_to):
with zipfile.ZipFile(zip_file, 'r') as zf:
zf.extractall(extract_to) # 直接解压所有文件(危险)
# 压缩包中包含"../../etc/passwd"等恶意路径
5.2 后缀检验绕过
def extract_html(request):
filename = request.FILES["filename"]
zf = zipfile.ZipFile(filename.temporary_file_path(), "r")
for entry in zf.namelist():
if entry.endswith(".html"): # 仅检查后缀
file_content = zf.read(entry)
with open(entry, "wb") as fp: # 仍可能路径遍历
fp.write(file_content)
zf.close()
6. 正则表达式绕过
6.1 re.search vs re.match
import re
def is_sql_injection(test_str):
pattern = re.compile(r".*(union)|(select).*")
return bool(re.search(pattern, test_str)) # 扫描整个字符串
def is_sql_injection_match(test_str):
pattern = re.compile(r".*(union)|(select).*")
return bool(re.match(pattern, test_str)) # 仅从开头匹配
test_a = "union xxxasd"
test_b = "xxxasd \n union ASDSDFF"
# re.search 结果
is_sql_injection(test_a) # True
is_sql_injection(test_b) # True
# re.match 结果
is_sql_injection_match(test_a) # True
is_sql_injection_match(test_b) # False
6.2 标志位影响
def is_sql_injection_match_fix(test_str):
pattern = r".*(union)|(select).*"
return bool(re.match(pattern, test_str, re.DOTALL)) # 匹配换行符
is_sql_injection_match_fix(test_b) # True (之前为False)
7. Unicode编码安全问题
7.1 Unicode标准化绕过
from unicodedata import normalize
from django.utils.html import escape
user_input = escape(request.GET["p"]) # 转义HTML
normalized = normalize("NFKC", user_input) # %EF%B9%A4 -> <
# 可能导致XSS绕过
7.2 Unicode大小写问题
email = request.GET["email"]
result = User.objects.filter(email__exact=email.upper()).first()
# foo@mıx.com -> FOO@MIX.COM
# foo@mix.com -> FOO@MIX.COM
# 可能导致账户枚举攻击
8. 反序列化安全
- pickle:存在代码执行风险,不应反序列化不可信数据
- pyyaml:同样存在安全风险,需谨慎处理
9. pip包管理安全
9.1 使用可信源
pip install --index-url=https://pypi.org/simple <package>
9.2 验证包完整性
pip install --require-hashes -r requirements.txt
requirements.txt 示例:
package==1.0.0 --hash=sha256:hashvalue
9.3 更新策略
- 非必要不更新,防止供应链攻击
- 确需更新时,验证新版本的安全性和来源
10. 总结与最佳实践
- 避免使用assert进行安全检查:改用显式条件检查
- 安全创建目录:
- 正确设置权限
- 验证输入路径
- 避免条件竞争
- 安全路径处理:
- 规范化路径
- 检查路径遍历
- 处理符号链接
- 安全解压文件:
- 验证压缩包内容
- 限制解压路径
- 正则表达式安全:
- 理解search/match区别
- 谨慎使用标志位
- 编码安全:
- 注意Unicode标准化
- 处理大小写转换
- 反序列化:
- 避免反序列化不可信数据
- pip安全:
- 使用可信源
- 验证包完整性
- 谨慎更新
通过遵循这些最佳实践,可以显著提高Python应用程序的安全性,减少潜在的安全漏洞。