有效令牌不代表拥有文档访问权
目标
把认证、权限和所有权分开,并用同样的 404 来隐藏资源是否存在。
为什么重要
已登录的用户只是改了地址里的文档编号,就读到了别的团队的文档。令牌有效这件事,与有权读取某份特定文档,是两回事。本实验用固定的令牌字典来代替认证服务器。它不是实现签发令牌或 JWT 签名的实验,而是实现认证结果之后的权限边界的实验。
步骤
- 在
/root/work/fa-ownership-lab/service.py中,bearer(header) 在头部恰好以 'Bearer ' 开头,且后面有一个不含空格的令牌时,返回该令牌。None、空令牌、其他 scheme、多余的空格都是 ValueError。
先做一次准备。已有的文件不会被覆盖。
mkdir -p /root/work/fa-ownership-lab
test -e /root/work/fa-ownership-lab/service.py || cp /opt/fixtures/ten_labs/fa-ownership-lab/service.py /root/work/fa-ownership-lab/service.py
cd /root/work/fa-ownership-lab
-
在
/root/work/fa-ownership-lab/service.py中,principal(token, users) 返回令牌字典中用户的 {id, scopes},但要把 scopes 列表也一并复制。不认识的令牌是 ValueError。 -
在
/root/work/fa-ownership-lab/service.py中,require_scope(user, scope) 在 scopes 中恰好含有 scope 字符串时返回 None,没有时抛出 PermissionError。read-all 不是 read。 -
在
/root/work/fa-ownership-lab/service.py中,visible(user, document) 只有在 document 不是 None,并且 owner 与 user 的 id 完全相同时才返回 True。 -
在
/root/work/fa-ownership-lab/service.py中,public_document(document) 是只含 id 和 title 的新字典。不包含 owner 或 internal_cost。 -
在
/root/work/fa-ownership-lab/service.py中,authenticate(header, users) 把 bearer 和 principal 连接起来。ValueError 要变成 HTTPException(401),并且 headers 中 WWW-Authenticate 的值是 Bearer。 -
在
/root/work/fa-ownership-lab/service.py中,read_document(user, documents, document_id) 在没有 read scope 时是 HTTPException(403),文档不存在或属于别人时是 HTTPException(404),否则就是 public_document 的结果。 -
在
/root/work/fa-ownership-lab/service.py中,create_app(users, documents) 返回一个 FastAPI 应用,它在 GET /documents/{document_id} 中接收 Authorization 头,并调用 authenticate 和 read_document。请用真实请求验证 200、401、403、404 以及非公开字段是否被去除。
参考
- 不联网、不安装软件包,在现有的 lab-dev 环境中进行。
- 每一步都在 45 秒的评分预算内运行。不要添加真实的 sleep 或网络调用。
- 评分会重新导入提交的模块,并用独立的输入和临时 DB 进行检查。请实现契约,而不要把预期值当作常量返回。
- FastAPI 官方文档 · pytest 官方文档 · Python sqlite3
- 局限:固定的令牌字典是教学用的输入。生产环境的认证,还需要过期、签名、撤销和安全保管。仅仅让 404 保持一致,也并不能消除通过响应时间或访问日志做出的所有推断。还要一并检查被拒绝的请求有没有连原始数据也改掉。
分离 Bearer 头
在 /root/work/fa-ownership-lab/service.py 中,bearer(header) 在头部恰好以 'Bearer ' 开头,且后面有一个不含空格的令牌时,返回该令牌。None、空令牌、其他 scheme、多余的空格都是 ValueError。
先做一次准备。已有的文件不会被覆盖。
mkdir -p /root/work/fa-ownership-lab
test -e /root/work/fa-ownership-lab/service.py || cp /opt/fixtures/ten_labs/fa-ownership-lab/service.py /root/work/fa-ownership-lab/service.py
cd /root/work/fa-ownership-lab
如果把头部随意切成多段,就可能把空格错误当成正常令牌接受下来。
保存后用 bash /opt/lab/checks/fa-ownership-lab/01-contract.sh 确认。
复制身份后再返回
在 /root/work/fa-ownership-lab/service.py 中,principal(token, users) 返回令牌字典中用户的 {id, scopes},但要把 scopes 列表也一并复制。不认识的令牌是 ValueError。
如果修改返回的 scopes 会连带改变原用户的权限,不同请求之间的权限就会混在一起。
保存后用 bash /opt/lab/checks/fa-ownership-lab/02-contract.sh 确认。
精确比较权限
在 /root/work/fa-ownership-lab/service.py 中,require_scope(user, scope) 在 scopes 中恰好含有 scope 字符串时返回 None,没有时抛出 PermissionError。read-all 不是 read。
子串比较会把更长的权限名称误认为另一种权限。
保存后用 bash /opt/lab/checks/fa-ownership-lab/03-contract.sh 确认。
单独确认所有权
在 /root/work/fa-ownership-lab/service.py 中,visible(user, document) 只有在 document 不是 None,并且 owner 与 user 的 id 完全相同时才返回 True。
把资源不存在和他人所有合并成同一个判定。
保存后用 bash /opt/lab/checks/fa-ownership-lab/04-contract.sh 确认。
用白名单挑选响应字段
在 /root/work/fa-ownership-lab/service.py 中,public_document(document) 是只含 id 和 title 的新字典。不包含 owner 或 internal_cost。
不要从原件中删除字段,而要组装新的响应。
保存后用 bash /opt/lab/checks/fa-ownership-lab/05-contract.sh 确认。
让错误符合 HTTP 契约
在 /root/work/fa-ownership-lab/service.py 中,authenticate(header, users) 把 bearer 和 principal 连接起来。ValueError 要变成 HTTPException(401),并且 headers 中 WWW-Authenticate 的值是 Bearer。
不要把认证失败和应用错误统统归成一个 500。
保存后用 bash /opt/lab/checks/fa-ownership-lab/06-contract.sh 确认。
固定拒绝的顺序
在 /root/work/fa-ownership-lab/service.py 中,read_document(user, documents, document_id) 在没有 read scope 时是 HTTPException(403),文档不存在或属于别人时是 HTTPException(404),否则就是 public_document 的结果。
即使认证之后,scope 和所有权也必须分别确认。
保存后用 bash /opt/lab/checks/fa-ownership-lab/07-contract.sh 确认。
在真实请求中封住边界
在 /root/work/fa-ownership-lab/service.py 中,create_app(users, documents) 返回一个 FastAPI 应用,它在 GET /documents/{document_id} 中接收 Authorization 头,并调用 authenticate 和 read_document。请用真实请求验证 200、401、403、404 以及非公开字段是否被去除。
即使函数各自都对,如果在路径中漏掉了调用,访问控制就不会生效。
保存后用 bash /opt/lab/checks/fa-ownership-lab/08-contract.sh 确认。