重定向与错误码应保留故事的完整性
在选择重定向或错误状态前,先检查方法、Location 头与缓存行为。
在选择重定向或错误状态前,先检查方法、Location 头与缓存行为。
两个小的只读 helper 把公共端点变成发布前和发布后都能检查的证据。
复盘是一张从检测到症状到验证修复的顺序图,由产生每个事实的命令支撑。
服务加固应该把一种明确不需要的操作变为被拒绝的操作,同时保留应用必须完成的工作。systemd 为文件系统视图、命名空间、权限和其他资源提供执行设置,但这些是边界各不相同的独立控制。添加四条熟悉的指令,并不意味着所有可读文件、可接触进程、继承的文件描述符或允许的系统调用都会消失。判断依据应是配置的真实语义与进程的实际行为。 坏掉的样子 ProtectSystem=strict 让服务挂载命名空间内的大部分文件系统层级变为只读。只读不代表不可读取,而且该设置有文档明确的例外,例如还需要单独控制的接口文件系统。服务仍然可能泄露它能够读取的信息,也仍然可以破坏可写目录中的数据。因此应该先使用专用服务身份,列清必要访问,再选择对应限制,而不是把一个只读开关当成覆盖所有资源的隔离墙。 PrivateTmp=yes 给服务提供私有临时目录。如果应用原本依赖另一个服务通过普通 /tmp 交换文件,这项设置可能直接打断协作。PrivateNetwork=yes 创建拥有独立回环接口的网络命名空间,因此宿主回环上的监听器不再是里面的同一个端点。需要直接连接数据库或公共接口的程序,若没有有意安排所需连接,就不适合直接套用这一设置。应先查真实调用路径,不能假定网络隔离不会影响正常功能。 NoNewPrivileges=yes 阻止执行程序时通过设置用户身份的二进制文件、文件能力等机制取得新的特权,并不删除进程已经拥有的权限。同样,单独写一条 IPAddressAllow,不意味着其他地址全部被拒绝:地址过滤有允许与拒绝的优先关系,还依赖内核功能支持。选项名称不是完整安全策略,每项控制都需要按其契约理解,尤其不能把未验证的限制写成已经成立的保证。 不同 systemd 控制拒绝选定操作,同时保留受管理状态与临时写入。 快速验证 这个实验要求一次性 Linux 系统中的 root 身份、作为 PID 1 的 systemd、可用的挂载与网络命名空间、位于 /usr/bin/python3 的 Python 3.8 或更新版本,以及用户管理工具。保持 Python 断言启用;生成的 worker 必须能被服务账号读取。早期记录报告 Debian 12、systemd 252.39;这里没有复现该次运行。脚本创建唯一命名的账号、运行时单元、状态目录与文件。前后两阶段使用同一个非 root 工作负载: ...
提前准备 TTL,观察权威与递归应答,并让两个端点在整个缓存窗口内都有效。
DNS TTL 表示一条资源记录通常可以在缓存中保留多久,之后需要刷新。修改权威记录会改变未来回答,却不会向所有曾经存储该数据的解析器发送失效通知。因此,一次迁移既包含权威更新,也包含一段客户端可能合法发现不同地址的时期。规划服务可用性时,需要同时考虑新答案和仍然存在的旧答案,而不是只看控制台保存成功。 图示表达事件先后,并非等比例时间轴。缓存可能保留不同代际;应用缓存和已有连接还有各自的生命周期。 坏掉的样子 在修改地址的同一时刻降低 TTL,并不会缩短此前缓存回答的寿命。保存了旧长 TTL 的解析器尚未获知新短 TTL。此时立即移除旧服务,可能让那些客户端失败,即使所有权威查询都已返回新地址。问题来自服务重叠期与尚未消失的发现状态不匹配;反复检查权威端的新值正确,并不能解决使用旧缓存的客户端请求。 回滚也具有同样的不对称性。把区域改回去,不会从已经学到新地址的缓存里撤回该地址。短暂正常的新目的地,可能在回滚命令完成后继续收到请求。应让回滚目标与刚发布过的目标在相关重叠期内都可用,或者明确客户端访问任何一个时如何获得可接受结果。DNS 回滚不是立即停止新地址流量的开关。 也不要把每层缓存的原始 TTL 简单相加,作为传播时间。普通转发缓存返回剩余寿命,下游再对收到的值继续计时;不同解析器群体则可能在不同时间填充缓存。应用自有缓存、长连接、权威同步延迟以及配置的陈旧回答策略,还会让单个 TTL 无法成为端到端完成保证。应把这些行为分别调查,不能用一个“传播中”笼统覆盖。 快速验证 将脚本保存为 check-dns-move.py,准备 Docker 后执行 python3 check-dns-move.py。固定环境以 BIND 9.18.49 为权威,以 dnsmasq 2.90 为一个转发缓存,二者运行在隔离容器回环接口上。程序只修改自己的临时区域,每次递增序列号并确认权威重载完成,再观察缓存。整个过程不改变公共 DNS,也不调整系统时间: ...
状态码需要放在请求方法的上下文里理解,它告诉客户端怎样解释本次 HTTP 响应。首位数字只能缩小类别,不能说明完整业务结果。例如,任务已经接受,仍可能没有完成;三开头的响应,也未必表示页面搬家。服务器应根据实际完成的事情选择具体状态,并提供相应响应头和内容,避免让一个看起来合理的数字承担它从未承诺的含义。 结合请求方法、正文、响应头和显式状态变化阅读这七次响应。200 状态读取可以返回仍在等待的任务,304 则不传输资源正文。调用方保留先前的资源字节;夹具不自动跟随重定向,也没有测试浏览器缓存,不能证明持久入队或最终完成。 成功不只有一种含义 二百表示请求按照相应方法的语义成功。成功读取任务状态资源,可以如实返回“任务仍在等待”的表示;这不代表任务本身已经结束。二零一表示创建了一个或多个资源,提供 Location 时,它用于识别主要的新建资源。接口需要说明客户端接下来应操作哪个资源,而不是把所有二开头的响应都解释成“用户最初想要的整个业务已经完成”。 二零二表示请求已经接受处理,但尚未完成,也不会对最终一定执行成功作出保证。应提供观察进度的途径,并定义最终成功与失败,否则客户端很难区分任务缓慢与任务丢失。二零四表示请求成功完成且没有响应内容;不能因为框架平常总是序列化 JSON,就给这种响应也附加正文。具体状态对应的消息约束需要贯穿最终输出。 三开头也可能是在验证已有表示 三零一与三零八表达永久重定向,三零二与三零七表达临时重定向,并具有不同的方法保留规则。三零三可以让调用方在处理步骤之后转而读取另一个资源。请求携带正文或具有副作用时,更要明确选择:可能改变方法的跳转,与必须保留方法的跳转,不能随意互换。客户端是否跟随,也应依据它实际要完成的动作判断。 ...
静态源是一道你能命名、能缓存、能回滚的边界。