单点登录作为成熟标准已经二十多年,可 SAML 至今仍是那个拖住成交、或者逼你去联系销售的条目。本文讲述企业级认证如何变成一项高价增售,是谁建起了这个世界,又是谁早早发出过警告;那道护城河究竟有多宽、由什么筑成,以及正在悄悄抽干其中一半的那股力量。
监控是一种只在灾难发生时才运行的代码,而那正是你最承受不起它出故障的时刻。于是我们搭建了一套测试装置:为每一条告警规则注入真实信号,并且必须等到通知真正抵达一个捕获中继后才算通过。第一次运行就发现,我们最核心的错误率告警早已彻底失灵;紧接着又发现了更糟的事:一个保留期设置悄悄给日志盖上了即时过期的印记,于是在数据摄取看起来一切正常的同时,整整一类告警其实是在空无一物上做判断。
一百兆字节的文档截图迁移到了 Cloudflare R2,藏在一个由应用在运行时根据自身主机名推导出来的 CDN 基址之后。在浏览器里一切正常,却丝毫没有改变源站的流量,因为爬虫看到的页面是在 127.0.0.1 上预渲染的,而在那里主机名什么都说明不了。修复办法是一个占位符:HTML 把它带出构建,边缘再按每个请求把它填上,而之所以只能这样,是因为一个只读文件系统。
即时预配默认是开启的,因此一个联合身份提供方只要声称某个人存在,就能在客户的租户中创建账户。关闭这个默认值只是改一个词。难点在于关闭它的同时,不悄悄改变每一个已存储连接的行为,而这些连接从来没有写入过那个列,这才是真正的问题,而解决它的技巧也说明了为什么默认值就是 API 表面的一部分。
backend-for-frontend 把 OAuth 令牌移出浏览器,只留给它一个不透明的 cookie。用一个 BFF 服务多个租户,大体上只是接线的活儿,直到后端通道登出登场:一个服务器到服务器的 POST,没有 cookie,没有会话,也没有浏览器,而唯一能标识租户的,是一个你尚未验证的令牌里的一个声明。
我们给 Kubernetes 集群加了一个校验签名的准入 webhook,好让未签名的镜像永远无法运行。几个小时后,一个 Deployment 竟有 2,242 个 ReplicaSet,每三秒就新生一个,而且没有一个可用的 pod。webhook 的日志显示,它对每一个请求都放行。真正的破坏,来自 "mutating admission webhook" 里那个我们早已不再细看的词。
每一次,回访用户在登录页面出现之前,都要盯着 "Loading…" 整整十秒。这个整数就是线索:我们的 SSO 库对一个返回 X-Frame-Options: DENY 和 frame-ancestors 'none' 的认证主机打开了一个隐藏的静默续期 iframe,于是这个 frame 永远无法加载、永远不会报错,而库就一直等到它的完整超时结束。防点击劫持与 OIDC 静默续期,两者各自都正确,却卡在了它们之间的接缝里。
我们对所有邮箱地址做了静态加密,管理后台的搜索框却悄悄不再自动补全了,没有报错,也没有日志。盲索引可以在密文上恢复精确匹配查询,但 HMAC 的全部使命就是摧毁前缀搜索所依赖的顺序性。本文讲述我们如何找回即输即搜:把每个前缀都作为独立的值来建索引,以及沿途踩中的三个陷阱,它们让我们明白,可搜索加密是一个系统问题,而不是密码学问题。
我们把 JWT 签名从 RS256 迁移到 ES256,签发的每一个令牌在密码学上都是有效的,却全部被拒绝。这样的事发生了三次,原因各不相同:JWS 要原始 R‖S 时却拿到了 DER、每 128 个令牌就失败一个的整数填充问题,以及在我们脚下悄然改变的 base64 方言。本文教你如何解读被弄坏的字节,并仅凭签名长度就点出肇事的那一层。
一个服务要验证我们的一个 JWT,需要读取两份文档——discovery 文档和 JWKS——它们是我们所提供的东西里请求量最大、也最不需要保密的,而过去每一次抓取都要一路回到源站。把它们缓存到 Cloudflare 上是简单的那部分。难的那部分在于:一个陈旧的公钥缓存,绝不能拒绝一个有效的令牌——本文要讲的,就是那套能让被激进缓存的 JWKS 依然安全的、对轮换友好的执行次序。
Duende 的 LITE 档定价 $5,750/yr,却把客户端应用限制在 2 个,而且完全不带 SAML。一旦你需要企业级 SSO,或者要上第三个应用,就得升级到 $12,500 的 STANDARD 档。本文算一算 Duende 对一款真实产品到底要花多少钱,以及那笔没人提醒你的、按应用数量收的税。
我们认证服务器签发的每一个令牌,都由同一把私钥签名。它一生中搬过两次家:出生在进程内部,后来被流放到一座它再也无法离开的保险库中,最后彻底转世成了一种截然不同、更小也更快的密钥。每一次迁移,都发生在一个仍在运行、令牌仍在流转的签发方上。本文讲的是:托管方式与算法的变更究竟要付出什么,以及一次借着“更安全”的提交悄悄溜进来的静默回归。
你的 SP 验证了 assertion 签名,固定了证书,让用户登录成功。每一项检查都通过了。可我依然重放了一个一小时前捕获的登录。诀窍不在于攻破签名,而在于删掉一个签名从未覆盖的字段。
我们在登录页面上要求了第二因素验证,却从未在 token endpoint 重新检查。于是一个有效密码加一条手改的 return URL 就直接绕过了 MFA。修复方案,以及它教会我们的规则:MFA 是你签发的会话的一个属性,而不是登录界面里的一个步骤。
SCIM 是一套标准化的 CRUD API,它最重要的那个动词,是把离职员工账号停用的那一个。厂商给它的定价是每条连接每月 $125,或者把它和 SSO 一起锁进企业版套餐。本文算一算一条 SCIM 连接的真实服务成本,以及为什么对取消预配收费,就是对安全收费。
Azure Table Storage 和 DynamoDB 没有删除标记,被删的行就这样凭空消失,这意味着你的增量备份根本看不到这次删除。恢复那份备份,你已办完离职的用户就回来了,还带着你早已轮换掉的旧密码。本文讲清楚为什么删除必须是一等公民,以及让它成为一等公民的那一张表。
我们的速率限制器和账户锁定计数器都以客户端 IP 为键。在 nginx 后面,这个 IP 来自一个客户端自己就能设置的 header,于是只要轮换这个 header,每个请求都能拿到一个全新的 IP,所有按 IP 的防护全部失效。本文讲这个一行就能完成的伪造,以及在 Kubernetes 上比看起来更麻烦的修复。
Azure Table Storage 只给你一个分区键、一个行键,此外几乎什么都没有。没有连接查询,没有拿得出手的二级索引,没有自增。我们偏偏在它上面跑了一套多租户认证系统。让它跑起来的那些模式,以及相比 SQL 你要放弃的东西。
一个未经身份验证、没有针对每个邮箱的速率限制的密码重置端点,不只是你的麻烦。把它对准别人的收件箱,你就把自己的重置表单变成了一门垃圾邮件大炮,而账单记在你的发件人信誉上。修复方法在这里,而且不会泄露哪些邮箱注册了账户。
大多数身份认证厂商把 SSO、SCIM、MFA 和审计日志圈进 Enterprise 套餐才肯放行。我们把它们全部放进了 $0 档。免费送功能为什么送得起?这里是背后的单位经济学:真正的墙从来不是功能,而是活跃用户和支持服务。
单点登录意味着信任身份提供方。我们对它多信了一件事:我们用断言中的电子邮件来解析回访的联合用户,于是任何一个连接都能声称别人的地址,从而落到对方的账户上。修复之道不是更多的校验,而是把身份的连接键从电子邮件改为按提供方划分、断言方无法伪造的 subject。
Azure Container Apps 承诺让我们不再为闲置的认证集群付费。我们认真核算了迁移成本,然后放弃了它。原因不是价格,也不是冷启动,而是 serverless 缺少带领导者选举的认证背板真正需要的那个唯一数字。
把"功能税"变成一张真实的账单。三个买家场景(第一笔企业级交易、少数几个客户、SSO 成为基本门槛)按每家厂商的公开价目计算。外加一笔没人提醒你的隐性附加费:集成进行到一半时 OAuth 客户端用完了。
一个三副本的集群不断与自己产生分歧。原因就在我们自己的代码里:对等节点发现例程里有一个 catch 块,当 multicast 失败时它会禁用发现,而在托管的 Kubernetes 上 multicast 总是失败。本文讲述我们为何彻底删除 gossip,转而用 blob lease 选举出一个 leader,以及为何一份能在 Storage Explorer 里打开查看的成员列表,胜过一份你只能去推断的成员列表。
登录功能是一个周末就能搞定的事。账单是之后才来的:签名校验、SCIM 注销配置、MFA、审计日志、密钥轮换、数据泄露责任,以及为一个零级关键系统随时待命。一篇诚实的自建对采购分析,包括什么时候自建才是对的。
OIDC 还是 SAML?你很少有选择权。两种协议各自是什么、各自在什么场景下胜出、让 SAML 难以自行实现的 XML 签名陷阱,以及为什么一款 B2B 产品最终两者都需要。
Authagonal 的支持系统:实时消息、无需刷新,双向透明的 AI 翻译,从客户的第一条消息起就被锁定,整段对话即使转到邮件也始终保持翻译。简单、好看,而且是真的能打。
我们有两个租户,悄悄地其实是同一个租户:同一个数据库,同一把令牌签名密钥,只是名字不同。罪魁祸首是一个一行的辅助函数,它通过去掉连字符来清洗 slug,把一个唯一标识符变成了不唯一的标识符。下面讲述一次有损的字符串变换如何演变成跨租户接管,以及为什么我们抢在你之前发现了它。
我们卖的是身份认证,所以我们最重要的测试是一个会变成客户的测试:一次单独的 Playwright 运行,它注册一个租户、配置每一项功能、把一个真实应用指向它、让一个真实用户带着正确的 claim 登录,然后备份、恢复并删除自己。详尽的端到端测试如何为我们赢得了上线的信心。
我们的员工控制台通过 Authagonal 自己来认证,由 Entra SSO 和 SCIM 负责 provisioning。成为自己的客户,会暴露出任何测试套件都想不到要去写的边界情况。下面就是那些真正重要的。
你的 Terraform state 是整个云环境的完整地图,外加一堆密钥,而默认情况下它就摆在一个公网端点后面。本文讲讲我们如何从零开始引导远程 state、把它藏到私有端点后面,并通过零信任连接器去访问它,既不用交那笔 VPN 网关税,也没有把自己锁在门外。
"人人都重置密码"是一种迁移选择,并非物理定律。如何在更换身份提供商时把用户现有的密码哈希一并带过去,让切换悄无声息,以及真正做不到的那唯一一种情形。
身份认证行业按许可收费,而不是按成本收费。它把 SSO、MFA 和用户预配锁在不同档位和按连接计费的门后,而这些功能的提供成本几乎为零。这正是定价页面但愿你永远不会划出的那条界线。
从自托管的 Duende IdentityServer 迁移到托管式认证:从 SQL 配置和 ASP.NET Identity 中真正会迁移的内容,以及你不必再承担的运维成本。
实用地看看一次 Auth0 迁移真正涉及什么:哪些容易,哪些繁琐,以及 Auth0 实实在在不会给你的那一样东西。