''

Orien Daily

  1. 🔐 为什么 PKCE 能挡住 OAuth 授权码劫持很多人第一次接触 OAuth 2.0,会以为拿到授权码 authorization code 就已经很安全了,因为真正换 access token 还要再走一步

    🔐 为什么 PKCE 能挡住 OAuth 授权码劫持

    很多人第一次接触 OAuth 2.0,会以为拿到授权码 authorization code 就已经很安全了,因为真正换 access token 还要再走一步。问题就在这里:如果攻击者能在这“一步之隔”里偷到授权码,而服务端又没有额外绑定这个授权码到底属于谁,那他就能自己拿着这串 code 去换 token,等于把你的登录结果截胡了。这类问题最常见在移动端、桌面端、单页应用,或者 redirect_uri 校验做得很松的时候。

    PKCE 的核心不是“加密授权码”,而是给这次登录流程加一条只有发起者自己知道的暗号。客户端先生成一个随机字符串 code_verifier,再把它变成 code_challenge 发给授权服务器。等用户完成登录、服务器把 authorization code 发回来之后,客户端还必须拿出原始的 code_verifier 才能换 token。这样一来,攻击者就算在中途截获了 authorization code,没有最初那串 verifier,也换不到 token。你可以把它理解成:授权码只是取件号,真正能取走包裹的,是取件号加取件密码。

    这事为什么会发生?因为 OAuth 最早更多是给“有后端、能保管 client_secret 的 Web 应用”设计的,后来移动 App、SPA、桌面工具也大量使用同一套协议,但这些环境根本藏不住 secret。开发者如果还沿用“有 code 就能换 token”的思路,就会把本来应该在后端完成的信任关系,错误地暴露给不可信的客户端环境。PKCE 本质上是在承认现实:前端和原生客户端不值得被默认信任,所以必须给授权码再加一次绑定。

    现实里怎么防,关键不是“支持 PKCE”四个字,而是别把它做成摆设。第一,公开客户端 public client 一律强制 PKCE,别当成可选项。第二,code_verifier 必须足够随机,不能自己手搓一个短字符串糊弄过去。第三,优先使用 S256,不要退回 plain。第四,redirect_uri 要精确匹配,不能只按前缀比较,不然攻击者能把授权码送到他自己的地址。第五,授权码必须短时有效且一次性使用,用过立刻作废。第六,客户端别把 token 存在随便一个能被脚本读到的地方,不然前面防住了,后面自己又漏了。

    🧪 场景分析题:一家网站的移动 App 已经接入 OAuth 登录。安全测试时发现,App 使用 Authorization Code Flow,但 token 端点只校验 client_id 和 authorization code,没有要求 code_verifier。攻击者能在受害者手机上通过恶意应用劫持回调 URI,拿到这次登录返回的 code。问:攻击者此时能不能换到 access token,真正的问题出在哪?


    💡 核心记忆:PKCE 防的不是“授权码泄露”本身,而是“别人捡到授权码后也能直接换 token”这件事。

  2. 🔑 并查集为什么几乎总是够快并查集这个名字听起来像某种“高级数据结构”,但它真正解决的问题很朴素:有一堆元素,它们一开始彼此独立,后来你不断收到“把 A 和 B 归到一组”的指令,同时还要不停地问“X 和 Y 现在是不是同一组”

    🔑 并查集为什么几乎总是够快

    并查集这个名字听起来像某种“高级数据结构”,但它真正解决的问题很朴素:有一堆元素,它们一开始彼此独立,后来你不断收到“把 A 和 B 归到一组”的指令,同时还要不停地问“X 和 Y 现在是不是同一组”。如果每次都真的把整组元素搬来搬去,代价会越来越大,所以并查集的设计思路很直接:每个集合只认一个代表元,元素只需要沿着父指针一路找到这个代表元就行。

    问题在于,如果你什么都不管,父指针可能退化成一条长链。这样一来,查一次代表元就像顺着一根很长的绳子往上爬,越查越慢。并查集之所以好用,不是因为它会“合并”,而是因为它在合并和查询时偷偷做了两件事。第一件事叫 union by rank 或 union by size,本质就是别乱挂,把小树挂到大树下面,别反过来。第二件事叫 path compression,也就是路径压缩:当你终于找到根节点后,顺手把沿路所有节点都直接改成指向根。下次再查,这条路几乎就消失了。

    这就是它“几乎总是够快”的原因。它不是靠一次查询特别快,而是靠每次查询都顺手把未来的查询变便宜。很多初学者会把它想成一个静态结构,其实并查集很像带自我修复能力的森林。你查得越多,结构反而越扁,后面的操作越轻。算法分析里常说它的均摊复杂度接近常数,严格写法是和反阿克曼函数有关。这个名字看着吓人,但你可以把它理解成:在真实世界的数据范围里,它慢不到哪里去,基本可以当成 O(1) 用。

    并查集特别适合处理“连通性只会增加不会撤销”的场景,比如 Kruskal 最小生成树、社交网络分组、离线判断图中两点是否连通。它不擅长的地方也很明确:如果你想支持“删除一条关系”或者频繁拆分集合,并查集就不对路了,因为它只会把树压得更扁,不会帮你优雅地拆回来。很多人踩坑,不是代码写错,而是拿它去解决动态删除问题,那方向从一开始就偏了。

    🧪 课后一题:有 6 个点,初始各自独立。依次执行 union(1,2)、union(2,3)、union(4,5),然后问 find(1) == find(3) 和 find(1) == find(5) 的结果分别是什么?答案:

    💡 易混淆点:并查集判断的是“是否属于同一连通分量”,不是“1 和 3 之间是否存在一条直接边”。

  3. 📸 @XgkCIKyQg7FRiKV ×2厳しい暑さでしたね

    📸 @XgkCIKyQg7FRiKV ×2
    厳しい暑さでしたね。クーラーが効いていても、しっかり水分補給していきましょう!
    本日は少なめでしたが、大きな声で頑張りました😊
    基本組さん、しっかり振れるようになってきました♪今後が楽しみです!

    さぁ、土曜日は、待ちに待った合宿だ〜 #富田明心会 #剣道 #高槻 #木曜日稽古 #玉小
    原文 #剣道

  4. 📸 @shinji_marosan ×4皆様おはようございます😊今日も朝から暑いですねぇ🥵今日は伯母の告別式があるため移動中約4時間の大移動ということで、今日は 稽古はお休みなぜか、昇段審査前になると稽古できなくなるのはなぜ?(;´д`)トホホ…ド下手なのに(ノД`)シクシクあっ!黒靴下忘れた😨買わなきゃ #剣道原文 #剣道

    📸 @shinji_marosan ×4
    皆様おはようございます😊
    今日も朝から暑いですねぇ🥵
    今日は伯母の告別式があるため移動中
    約4時間の大移動
    ということで、今日は 稽古はお休み
    なぜか、昇段審査前になると稽古できなくなるのはなぜ?(;´д`)トホホ…
    ド下手なのに(ノД`)シクシク

    あっ!黒靴下忘れた😨
    買わなきゃ #剣道
    原文 #剣道

  5. 📸 @belleequipe1031 ×2久しぶりのSILENT HILL f新しい衣装でお狐とメロ狐の膝枕と頭ポンポンはヤバいかもしれない😂@cncnpi小夏さんのベストにやにやポイントはどこでしょうねw #加藤小夏 #深水雛子 #silenthillf原文 #加藤小夏

    📸 @belleequipe1031 ×2
    久しぶりのSILENT HILL f
    新しい衣装でお狐と
    メロ狐の膝枕と頭ポンポンはヤバいかもしれない😂
    @cncnpi
    小夏さんのベストにやにやポイントはどこでしょうねw #加藤小夏 #深水雛子 #silenthillf
    原文 #加藤小夏