第九站练习答案
python
from django.test import Client, TestCase
from django.urls import reverse
class CsrfTests(TestCase):
def test_post_without_csrf_is_rejected(self):
client = Client(enforce_csrf_checks=True)
client.force_login(self.user)
response = client.post(
reverse("tickets:edit", args=[self.ticket.pk]),
{"title": "changed", "priority": 3},
)
self.assertEqual(response.status_code, 403)python
class CspTests(TestCase):
def test_report_only_policy_is_present(self):
response = self.client.get(reverse("health"))
policy = response["Content-Security-Policy-Report-Only"]
self.assertIn("default-src 'self'", policy)运行:
bash
python manage.py test tickets.tests.CsrfTests tickets.tests.CspTests专题二核对
python
from django.core.files.uploadedfile import SimpleUploadedFile
small = SimpleUploadedFile("proof.txt", b"ok", content_type="text/plain")
oversized = SimpleUploadedFile("large.txt", b"x" * (2 * 1024 * 1024 + 1), content_type="text/plain")分别断言合法文件通过、超限文件进入表单错误。上传先落隔离区,扫描失败保持 quarantined 且不可下载。异常日志保留 request ID、版本和稳定错误码,删除 Cookie、Authorization、表单正文和文件内容。
深水边界
如果视图需要登录,未带 CSRF 的匿名请求可能先被重定向;测试必须构造能真正到达写路径的身份和 URL。安全测试要验证威胁路径,不只是状态码快照。
开放练习(不提供答案)
在反向代理后验证 SECURE_PROXY_SSL_HEADER、HTTPS 重定向、安全 Cookie 和 Host 校验;记录错误信任代理头如何让应用误判连接安全。
加码题解:安全测试与上传边界
python
def safe_name(name):
import uuid
suffix = name.rsplit('.', 1)[-1].lower()
if suffix not in {'png', 'jpg', 'jpeg'}:
raise ValueError('unsupported extension')
return f'{uuid.uuid4().hex}.{suffix}'关键推理
存储 key 不沿用用户文件名,扩展名只作为初筛,内容扫描仍需在后续状态机完成。
可替代方案
把文件放入对象存储隔离区,扫描通过后再生成可下载 URL。
典型错误
相信 Content-Type 或扩展名就直接公开文件;日志中记录完整 token 和请求体。
复盘时请把状态码/事务/权限/资源清理中的至少一项写成自动化测试,而不是只截图成功页面。