diff --git a/posts/app-defaults-2023.md b/posts/app-defaults-2023.en.md
similarity index 100%
rename from posts/app-defaults-2023.md
rename to posts/app-defaults-2023.en.md
diff --git a/posts/app-defaults-2023.zh.md b/posts/app-defaults-2023.zh.md
new file mode 100644
index 00000000..ff254e79
--- /dev/null
+++ b/posts/app-defaults-2023.zh.md
@@ -0,0 +1,79 @@
+---
+title: "我的默认应用"
+date: "2023-12-03"
+description: "My default apps in 2023. https://defaults.rknight.me/"
+modified: "2023-12-17"
+tags: app, life, 2023
+---
+
+最近看到很多博主在 [App Defaults](https://defaults.rknight.me/) 中分享了他们的默认应用程序。以下是我自己的:
+
+- 📨 邮件客户端
+ - Apple 邮件
+ - [Skiff 邮件](https://go.lawrenceli.me/skiff) `hi@lawrenceli.me`。
+- 📮 邮件服务器
+ - Outlook(中国大陆可用)
+ - [Skiff 邮件](https://go.lawrenceli.me/skiff)。 很遗憾该服务尚不支持 POP3/IMAP。
+- 📝 注释
+ - Apple Notes(使用 [montaigne.io](https://montaigne.io),可以将 Apple Notes 成为一个静态网站)
+- ✅ 待办事项
+ - Apple 提醒
+- 📷 iPhone 照片拍摄
+ - Apple 相机
+- 🟦 照片管理
+ - Apple 照片与 iCloud 同步
+- 📆 日历
+ - 服务:iCloud 日历
+ - 客户端:Apple 日历
+- 📁 云文件存储
+ - iCloud 云盘 (iCloud+)
+ - [阿里云盘](https://www.aliyundrive.com/)(适用于 Apple TV)
+- 📖 RSS
+ - 客户端:iOS/macOS 上的 [Reeder](https://reederapp.com/)
+ - 服务端:自托管 [FreshRSS](https://freshrss.org/index.html),出色的 PWA 和 Web 推送。
+- 🙍🏻♂️ 通讯录
+ - N/A,没有联系人。
+- 🌐 浏览器
+ - Mac 上的 Chrome
+ - iOS 上的 Safari
+- 💬 聊天
+ - [微信](https://www.wechat.com/)(中国必备应用)
+ - [Microsoft Teams](https://apps.apple.com/ph/app/microsoft-teams/id1113153706)(上班用)
+- 🔖 书签
+ - [Instapaper](https://www.instapaper.com/)
+- 📑 稍后阅读
+ - Reeder + Instapaper
+- 📜 文字处理
+ - [ONLYOFFICE](https://www.onlyoffice.com/)(开源 Office,与微软完全兼容)
+ - [Obsidian](https://obsidian.md/)(流行的 Markdown 编辑器,可通过 iCloud 同步)
+- 📈 电子表格
+ - ONLYOFFICE(开源 Office)
+- 📊 演示
+ - [Slidev](https://sli.dev/)(通过 Markdown 生成幻灯片)
+- 🛒 购物清单
+ - 在 Apple 提醒共享提醒列表
+- 🍴 膳食计划
+ - 无
+- 💰 预算和个人理财
+ - 以前用过 [iOS 的 Finances 2](https://hochgatterer.me/finances/ios/),目前正在尝试 [BeanWise](https://apps.apple.com/us/app/beanwise/id6446314789?ref=https://lawrenceli.me)
+- 📰 新闻
+ - [Solidot](https://solidot.org) (中文版的 [slashdot](https://slashdot.org))
+ - [路透社](https://www.reuters.com/)
+ - [Hacker News](https://news.ycombinator.com/)
+- 🎵 音乐
+ - [Apple Music](https://music.apple.com/)(学生订阅只需每月 6 元)
+ - [网易云音乐](https://music.163.com/)(作为 Apple Music 的补充)
+- 🎤 播客
+ - [Apple Podcast](https://www.apple.com/apple-podcasts/) 推荐泛用型播客客户端,无内容审查
+- 🔐 密码管理
+ - iCloud KeyChain
+ - [Google 身份验证器](https://apps.apple.com/us/app/google-authenticator/id388497605) 多因素身份验证
+
+## 额外默认设置
+
+- 🚀 自托管
+ - [Cloudflare](https://lawrenceli.me/blog/cloudflare)(用于 CDN 和 DNS)、[Vercel](https://vercel.com)、[Cloudflare Workers](https://developers.cloudflare.com/workers/), [fly.io](https://fly.io)
+- 🤖 自动化
+ - [IFTTT](https://ifttt.com),Apple 快捷指令(前 Workflow)
+- 🛜 网络工具
+ - [Tailscale](https://tailscale.com/)、[Cloudflare WARP](https://1.1.1.1)、[MerlinClash](https://mcreadme.gitbook.io/mc/)
diff --git a/posts/apple-tv.md b/posts/apple-tv.md
index 0ae7f38d..2a397ee8 100644
--- a/posts/apple-tv.md
+++ b/posts/apple-tv.md
@@ -2,14 +2,12 @@
title: "Apple TV"
date: "2023-01-21"
description: " 小巧玲珑的电视盒子"
-image: https://lawrenceli.me/images/apple-tv/tv.jpg
tags: apple, tv
-visible: false
---
过年回老家看电视,运营商送的网络电视盒子主屏幕花花绿绿,我一个程序员都费了好久才找到地方卫视的直播频道。
-索性去电商平台搜搜看有没有更好的硬件、翻看各种测评文章和视频。清晰了需求定位后,我果断找了一家有现货的店铺下单了一款美版 Apple TV 2022。
+索性去电商平台搜搜看有没有更好的硬件、翻看各种测评文章和视频。清晰了需求定位后,我果断找了一家有现货的店铺下单了一款美版 Apple TV 2022 (4K)。

@@ -17,8 +15,18 @@ visible: false
由于购买之前就已经熟悉了大部分使用细节,所以安装、使用的时候毫不费力;像是把玩过很久的玩具一样自然流畅。
-用美区 Apple ID 购买了 OBOX,添加了电视直播源就看起了 CCTV。比期待的画质高出不少。遥控器的金属质感像第一次摸到棱角分明的 iPhone 5S 一样爱不释手!还用它和我爸玩了一局桌球游戏。
+用美区 Apple ID 购买了很多付费应用,主要都是一些国内独立开发者的作品。
-种种体验让我想起知乎上一个回答:
+- Alplayer
+- APTV
+- IIVA
+- Miao Projects
+- VidHub
+
+很难想象不少开发者会为国内极其小众的平台开发上架了如此小而美的 tvOS App。
+
+搜集一些电视直播源,我就反常地看起了 CCTV。比期待的画质高出不少。遥控器的金属质感像第一次摸到棱角分明的 iPhone 5S 一样爱不释手!还用它和我爸玩了一局桌球游戏。
+
+种种体验让我想起[知乎上一个回答](https://www.zhihu.com/question/477077785/answer/2425144012):
> 长这么大,听过最清晰的《义勇军进行曲》是在 Apple Music。
diff --git a/posts/chat-ops.md b/posts/chat-ops.md
index 553f73e4..d4085762 100644
--- a/posts/chat-ops.md
+++ b/posts/chat-ops.md
@@ -46,7 +46,7 @@ tags: devops, golang, chatops, ci
我们按照 [Kubernetes Prow 的设计语言](/blog/prow),用一个 `/` 来作为 Tag,形式如同 `/test xxx` .
-因此这里必然需要做字符串处理了。除了判断 Tag 的存在之外,要取 Tag 后面的参数。项目用 Go 实现,很简单。贴其中一工具函数的代码,各位猜猜这是做什么的:
+因此这里必然需要做字符串处理了。除了判断 Tag 的存在之外,要取 Tag 后面的参数。项目用 Go 实现,很简单,贴其中一工具函数的代码:
```go
func StringIndexOf(originalArray []string, wordToFind interface{}) []int {
@@ -56,11 +56,11 @@ func StringIndexOf(originalArray []string, wordToFind interface{}) []int {
interfaceArray[i] = v
}
var indexArray []int
- for i:=0 ; i < length; i++ {
- if strings.Compare(wordToFind.(string), originalArray[i]) == 0 {
- indexArray = append(indexArray, i)
- }
- }
+ for i:=0 ; i < length; i++ {
+ if strings.Compare(wordToFind.(string), originalArray[i]) == 0 {
+ indexArray = append(indexArray, i)
+ }
+ }
return indexArray
}
```
@@ -165,6 +165,6 @@ Robot 回复: 当前支持指令列表, 带 * 需要特定人员发起
最近一次更新,让机器人支持了多个仓库,直接在 `/tag` 最后加一个可选参数 `[repo]`,然后 SDK 的参数做出相应的变动就实现了。
-相关链接:
+此项实践已作为 ThoughtWorks 员工构建的知识体系 Ledge DevOps 对 ChatOps 这一模式的展示案例:
- [Pattern#ChatOps from Ledge —— DevOps knowledge learning platform](https://devops.phodal.com/pattern#chatops)
diff --git a/posts/cloudflare.md b/posts/cloudflare.md
index 0b6d2b8d..f2256ddc 100644
--- a/posts/cloudflare.md
+++ b/posts/cloudflare.md
@@ -1,5 +1,5 @@
---
-title: "CloudFlare"
+title: "Cloudflare"
themeColor: "#f88100"
date: "2023-06-11"
modified: "2023-11-29"
@@ -7,7 +7,7 @@ description: "一家免费提供 DDoS 防护的 CDN 厂商。"
tags: cloudflare, network, cdn, company, ddos, tls
---
-CloudFlare 是一家在业内比较知名的 CDN 服务商,提供包含 DNS 解析、WAF 防火墙、CDN 加速、DDoS 防护,后续推出了一系列比较方便开发人员的许多功能:CloudFlare Workers、KV、Zero Trust Tunnel、WARP... 一切都是为了提供一个安全、快速的互联网环境。如果说 Vercel 给前端开发人员提供了基础设施,那 CloudFlare 则为数千万网站后端流量提供了基础设施。
+Cloudflare 是一家在业内比较知名的 CDN 服务商,提供包含 DNS 解析、WAF 防火墙、CDN 加速、DDoS 防护,后续推出了一系列比较方便开发人员的许多功能:Cloudflare Workers、KV、Zero Trust Tunnel、WARP... 一切都是为了提供一个安全、快速的互联网环境。如果说 Vercel 给前端开发人员提供了基础设施,那 Cloudflare 则为数千万网站后端流量提供了基础设施。
今年年初,[Cloudflare 缓解了破纪录的 7100 万个请求/秒的 DDoS 攻击](https://blog.cloudflare.com/zh-cn/cloudflare-mitigates-record-breaking-71-million-request-per-second-ddos-attack-zh-cn/)。
@@ -15,24 +15,24 @@ CloudFlare 是一家在业内比较知名的 CDN 服务商,提供包含 DNS
三年前,我把我的博客从 WordPress 迁移到了 [Vercel](https://vercel.com),老用户们或许都记得,那时候的域名可还都是 `*.now.sh`。初次使用 Vercel 的感受可以说是如获至宝,在今天看来可能显得很幼稚了——如果不是自己知道如何从 0 到 1 申请域名去部署一个全栈的 Web 项目的话,很难理解 Vercel 这种平台背后做了哪些复杂工作。这是我所理解的美国公司的一贯作法 —— 他们总是把庞大、精密、复杂的技术或基础设施掩盖在简约、优雅的产品外观之下。而我每次都会保持警惕和观察力,如果换我做,我怎么来实现?后来我便学习起了 Kubernetes。
-说回 CloudFlare。从我第一次买域名(2015 年)一直到现在,我全部把解析权安排在 CloudFlare 上。归因于 [Vercel 的一次网络问题](https://isdown.app/integrations/vercel/incidents/50745-errors-accessing-from-china),国内的网络受某种不可抗力在 2021 年的时候突然无法访问 Vercel 的部分域名了,尽管我的博客每天仅有为数不多的访客,但作为一个以中文为主的博客,还是有必要保持国内网络访问的畅通。根据官方提供的新的 CNAME 值,我在 CloudFlare 上更换了解析记录,也算顺利解决。也就在当时,我才注意到 DNS Records 控制台之前一个一直忽视的选项:
+说回 Cloudflare。从我第一次买域名(2015 年)一直到现在,我全部把解析权安排在 Cloudflare 上。归因于 [Vercel 的一次网络问题](https://isdown.app/integrations/vercel/incidents/50745-errors-accessing-from-china),国内的网络受某种不可抗力在 2021 年的时候突然无法访问 Vercel 的部分域名了,尽管我的博客每天仅有为数不多的访客,但作为一个以中文为主的博客,还是有必要保持国内网络访问的畅通。根据官方提供的新的 CNAME 值,我在 Cloudflare 上更换了解析记录,也算顺利解决。也就在当时,我才注意到 DNS Records 控制台之前一个一直忽视的选项:
Proxied
-我好奇地把它启用了,即从灰色 `DNS only` 换成了这个橙色的 `Proxied`,那时我还没意识到,其实 CloudFlare 从那刻起已经完全接管了我的网站的全部流量并进行任播 (Anycast);换句话说,我在现有的 Vercel CDN 之上,又套了一层 CloudFlare CDN。是的,这迎来了两个问题:
+我好奇地把它启用了,即从灰色 `DNS only` 换成了这个橙色的 `Proxied`,那时我还没意识到,其实 Cloudflare 从那刻起已经完全接管了我的网站的全部流量并进行任播 (Anycast);换句话说,我在现有的 Vercel CDN 之上,又套了一层 Cloudflare CDN。是的,这迎来了两个问题:
1. Vercel 后台警告 CNAME 解析异常
2. 缓存时间问题
-3. 客户端 IP 全部被识别 CloudFlare IP,所有发往 Vercel 的请求都会从 CloudFlare 数据中心发出
+3. 客户端 IP 全部被识别 Cloudflare IP,所有发往 Vercel 的请求都会从 Cloudflare 数据中心发出
-不可能没人像我这样做吧?事实上,[Vercel 并不推荐在其基础上使用另一层 CDN](https://vercel.com/guides/why-running-another-cdn-on-top-of-vercel-is-not-recommended)。后续我也依次找寻到了解决方案:对于 CNAME 来说,Vercel 会定时访问网站跟路径下的 `.well-known` 路径下的资源来识别包括 CNAME、HTTPS 证书这类配置验证网站控制权信息,因此我们可以直接在 CloudFlare 的 WAF 中,把这类路径作为白名单让 WAF 跳过其他安全规则直接放行。对于客户端 IP,可以参考 [Available Managed Transforms](https://developers.cloudflare.com/rules/transform/managed-transforms/reference/),将一些客户端原始信息置于请求头中。缓存时间方面,还是要熟悉 MDN 上的一些标准 HTTP 协商协议,细粒度地对不同资源设置不同的 TTL,尽可能发挥 CloudFlare CDN 和浏览器自身缓存的优势 - 一个博客而已,是不是有点大炮打蚊子了?
+不可能没人像我这样做吧?事实上,[Vercel 并不推荐在其基础上使用另一层 CDN](https://vercel.com/guides/why-running-another-cdn-on-top-of-vercel-is-not-recommended)。后续我也依次找寻到了解决方案:对于 CNAME 来说,Vercel 会定时访问网站跟路径下的 `.well-known` 路径下的资源来识别包括 CNAME、HTTPS 证书这类配置验证网站控制权信息,因此我们可以直接在 Cloudflare 的 WAF 中,把这类路径作为白名单让 WAF 跳过其他安全规则直接放行。对于客户端 IP,可以参考 [Available Managed Transforms](https://developers.cloudflare.com/rules/transform/managed-transforms/reference/),将一些客户端原始信息置于请求头中。缓存时间方面,还是要熟悉 MDN 上的一些标准 HTTP 协商协议,细粒度地对不同资源设置不同的 TTL,尽可能发挥 Cloudflare CDN 和浏览器自身缓存的优势 - 一个博客而已,是不是有点大炮打蚊子了?
-CloudFlare 的整体防御从 L3 到 L7,遍布了所有能覆盖的防御范围。一个请求进入 CloudFlare 所代理的网站流量会经历顺序由上到下:
+Cloudflare 的整体防御从 L3 到 L7,遍布了所有能覆盖的防御范围。一个请求进入 Cloudflare 所代理的网站流量会经历顺序由上到下:
-| Traffic Sequence in CloudFlare |
+| Traffic Sequence in Cloudflare |
| :----------------------------: |
| DDoS |
| URL Rewrites |
@@ -48,35 +48,35 @@ CloudFlare 的整体防御从 L3 到 L7,遍布了所有能覆盖的防御范
| Access |
| Workers |
-这些流量经过内部的层层筛选,以及我们自己定义的一些 Rule,最终反代到源站。因此,在决定使用任何 CDN 产品的时候,有必要将服务端源站 IP 妥善隐藏,尽可能不暴露任何历史解析值,否则一切防御都是徒劳。如果源站 IP 已经暴露,只能及时更换新的地址。在新的规则录入好后,CloudFlare 的全球网络会立刻应用规则并实时生效,这里或多或少要归功于大佬 [agentzh 章亦春](https://mp.weixin.qq.com/s/xfphy67PTbtjeggo7LpjSA) 开源的高性能网关 [OpenResty](https://openresty.org/cn/)。
+这些流量经过内部的层层筛选,以及我们自己定义的一些 Rule,最终反代到源站。因此,在决定使用任何 CDN 产品的时候,有必要将服务端源站 IP 妥善隐藏,尽可能不暴露任何历史解析值,否则一切防御都是徒劳。如果源站 IP 已经暴露,只能及时更换新的地址。在新的规则录入好后,Cloudflare 的全球网络会立刻应用规则并实时生效,这里或多或少要归功于大佬 [agentzh 章亦春](https://mp.weixin.qq.com/s/xfphy67PTbtjeggo7LpjSA) 开源的高性能网关 [OpenResty](https://openresty.org/cn/)。
-## CloudFlare Workers & Serverless
+## Cloudflare Workers & Serverless
我们可以将一个个「函数」部署在公有云的「边缘计算节点」之上,并暴露 Socket 给这些节点上的函数,来实现无需忽略底层服务器,直接部署可随意伸缩的 HTTP 服务的能力。当然,这要求这些函数尽可能无状态。在没有任何请求,闲置一定时间时,这些函数进程会直接消失以腾出计算资源,直到下次事件驱动它们迅速重新启动并继续提供服务。这便是老生常谈的 Serverless。
-初次了解 Serverless 也是非常惊讶。AWS Lambda 竟能将 function 如此商业化 (FaaS),Vercel 在此之上也做到了开箱即用。借助 CloudFlare 现有的数据中心,CloudFlare 也推出他们的 Serverless 解决方案 - [CloudFlare Workers](https://blog.cloudflare.com/introducing-cloudflare-workers/)。不同的是,CloudFlare Workers 相比原始的 Vercel Serverless Function 而言能够做 Server Sent Event、WebSocket 这类支持长连接的请求。尽管后续 Vercel Edge Function 也能实现,但是它能支持的 Node.js Module 实在太少了。(作者注:后来我才了解到 Vercel Edge Function 其实构建于 CloudFlare Workers 之上)
+初次了解 Serverless 也是非常惊讶。AWS Lambda 竟能将 function 如此商业化 (FaaS),Vercel 在此之上也做到了开箱即用。借助 Cloudflare 现有的数据中心,Cloudflare 也推出他们的 Serverless 解决方案 - [Cloudflare Workers](https://blog.cloudflare.com/introducing-cloudflare-workers/)。不同的是,Cloudflare Workers 相比原始的 Vercel Serverless Function 而言能够做 Server Sent Event、WebSocket 这类支持长连接的请求。尽管后续 Vercel Edge Function 也能实现,但是它能支持的 Node.js Module 实在太少了。(作者注:后来我才了解到 Vercel Edge Function 其实构建于 Cloudflare Workers 之上)
-前不久,CloudFlare [开源了 Workers 运行时 workerd](https://blog.cloudflare.com/workerd-open-source-workers-runtime/)。
+前不久,Cloudflare [开源了 Workers 运行时 workerd](https://blog.cloudflare.com/workerd-open-source-workers-runtime/)。
-CloudFlare Workers 有许多应用场景。比如实现一个简单的[短 URL 重定向服务](https://lucjan.medium.com/free-url-shortener-with-cloudflare-workers-125eaf87b1ec)、[GitHub Proxy](https://github.com/hunshcn/gh-proxy)、以及一大堆各自实现的 ChatGPT API Proxy...方便了太多国内用户。
+Cloudflare Workers 有许多应用场景。比如实现一个简单的[短 URL 重定向服务](https://lucjan.medium.com/free-url-shortener-with-cloudflare-workers-125eaf87b1ec)、[GitHub Proxy](https://github.com/hunshcn/gh-proxy)、以及一大堆各自实现的 ChatGPT API Proxy...方便了太多国内用户。
Node.js 作者 Ryan Dahl 这几年给 JavaScript 写的另一个全新运行时 [Deno 也有类似的 Serverless 服务](https://dash.deno.com),体验也很友好,同样[支持 Web Standard API](https://twitter.com/la3rence/status/1642798082294251520)。
为了实现 Serverless 的更多数据持久化功能,他们也各自推出了自家的 KV 存储实现服务,或者说是 Serverless 数据库。
-## CloudFlare 在 TLS 协议上的努力
+## Cloudflare 在 TLS 协议上的努力
### Client Hello - SNI
-再来谈谈技术方面的一些进展。很多读者都知道 Server Name Indication(服务器名称指示,SNI)的存在,它是 TLS/SSL 协议在最初的 Client Hello 阶段由客户端发往服务端的一个字段,内容是网站的主机名或域名。引用 CloudFlare 的形象解释:
+再来谈谈技术方面的一些进展。很多读者都知道 Server Name Indication(服务器名称指示,SNI)的存在,它是 TLS/SSL 协议在最初的 Client Hello 阶段由客户端发往服务端的一个字段,内容是网站的主机名或域名。引用 Cloudflare 的形象解释:
> SNI 有点像邮寄包裹到公寓楼而不是独栋房子。将邮件邮寄到某人的独栋房子时,仅街道地址就足以将包裹发送给收件人。但是,当包裹进入公寓楼时,除了街道地址外,还需要公寓号码。否则,包裹可能无法送达收件人或根本无法交付。许多 Web 服务器更像是公寓大楼而不是独栋房子:它们承载多个域名,因此仅 IP 地址不足以指示用户尝试访问哪个域名.....当多个网站托管在一台服务器上并共享一个 IP 地址,并且每个网站都有自己的 SSL 证书,在客户端设备尝试安全地连接到其中一个网站时,服务器可能不知道显示哪个 SSL 证书。这是因为 SSL/TLS 握手发生在客户端设备通过 HTTP 指示连接到某个网站之前。
-有点类似于 HTTP 协议中的 `Host` 请求头(如果在同一台服务器上用 Nginx 配置过多个虚拟主机应该都熟悉),但是 SNI 是作用在 L4,而且在 TCP 握手前完成。起初它并不是 TLS 协议的一部分,最早在 2003 年作为扩展字段增加到 TLS 协议中 ([RFC 6066](https://datatracker.ietf.org/doc/html/rfc6066#section-3))。现代浏览器等客户端都早已支持这个字段。我们会发现一个细节问题,对基于同一 CDN 的网站的 HTTPS 请求,我们传入的 TLS `SNI` 和 HTTP Header `Host` 会有不一致的情况,在不严格校验 SNI 的情况下,这类请求有可能被路由到 `Host` 所定义的主机上,本质也就无视了 `SNI`,因此对于某些防火墙来说,由于它们能通过 SNI 来侦测到用户所请求的 HTTPS 站点,它们无法得到后续 TLS 握手后的 HTTP 报文内容,在客户端更换了 Header `Host` 后,实际返回的 HTTP 报文内容其实已被调包 —— 这种攻击方式,或者说叫伪装方式被称为[域前置(Domain Fronting)](https://zh.wikipedia.org/zh-cn/%E5%9F%9F%E5%89%8D%E7%BD%AE)技术。CloudFlare、CloudFront 都会校验二者的一致性返回 403,但依然有部分 CDN 对这一做法采取保留,比如 Fastly。
+有点类似于 HTTP 协议中的 `Host` 请求头(如果在同一台服务器上用 Nginx 配置过多个虚拟主机应该都熟悉),但是 SNI 是作用在 L4,而且在 TCP 握手前完成。起初它并不是 TLS 协议的一部分,最早在 2003 年作为扩展字段增加到 TLS 协议中 ([RFC 6066](https://datatracker.ietf.org/doc/html/rfc6066#section-3))。现代浏览器等客户端都早已支持这个字段。我们会发现一个细节问题,对基于同一 CDN 的网站的 HTTPS 请求,我们传入的 TLS `SNI` 和 HTTP Header `Host` 会有不一致的情况,在不严格校验 SNI 的情况下,这类请求有可能被路由到 `Host` 所定义的主机上,本质也就无视了 `SNI`,因此对于某些防火墙来说,由于它们能通过 SNI 来侦测到用户所请求的 HTTPS 站点,它们无法得到后续 TLS 握手后的 HTTP 报文内容,在客户端更换了 Header `Host` 后,实际返回的 HTTP 报文内容其实已被调包 —— 这种攻击方式,或者说叫伪装方式被称为[域前置(Domain Fronting)](https://zh.wikipedia.org/zh-cn/%E5%9F%9F%E5%89%8D%E7%BD%AE)技术。Cloudflare、CloudFront 都会校验二者的一致性返回 403,但依然有部分 CDN 对这一做法采取保留,比如 Fastly。
我们可以用 WireShack 抓包获取到 `SNI` 字段。应用这个过滤条件 `ssl.handshake.extensions_server_name`,尝试抓包发送一次 TLS 请求
@@ -86,7 +86,7 @@ openssl s_client -connect lawrenceli.me:443 -servername lawrenceli.me -state -de

-可以从结果看出,SNI 确实使用了明文进行传输,这就导致了前文提到的一个问题 - 就算经过 TLS/HTTPS 加密的流量,仍然明文地暴露了我们在访问的域名。「这又如何?DNS 不也暴露了嘛?」好问题 - DoH 解决了 DNS 请求的明文风险 ([RFC 8484](https://datatracker.ietf.org/doc/html/rfc8484))。因此,实际上 TLS 目前唯一在数据上有泄密风险的就只有这个字段了。CloudFlare 先后搬出了两个解决方案:[ESNI](https://www.cloudflare-cn.com/learning/ssl/what-is-encrypted-sni/) 以及 [ECH](https://blog.cloudflare.com/encrypted-client-hello/)。
+可以从结果看出,SNI 确实使用了明文进行传输,这就导致了前文提到的一个问题 - 就算经过 TLS/HTTPS 加密的流量,仍然明文地暴露了我们在访问的域名。「这又如何?DNS 不也暴露了嘛?」好问题 - DoH 解决了 DNS 请求的明文风险 ([RFC 8484](https://datatracker.ietf.org/doc/html/rfc8484))。因此,实际上 TLS 目前唯一在数据上有泄密风险的就只有这个字段了。Cloudflare 先后搬出了两个解决方案:[ESNI](https://www.cloudflare-cn.com/learning/ssl/what-is-encrypted-sni/) 以及 [ECH](https://blog.cloudflare.com/encrypted-client-hello/)。
我们可以使用 Chrome 的开关 `chrome://flags/#encrypted-client-hello` 来开启浏览器 ECH 的客户端支持。通过 Chrome DevTool 的 Security Tab 能够查看 HTTPS 流量的安全性信息。我们可以通过[这个链接](https://crypto.cloudflare.com/cdn-cgi/trace)来测试客户端对这个方案的支持情况,当然,这些需要服务端做相应的配置才能完全启用。话题就此结束,我不能再细说了。
@@ -102,30 +102,30 @@ Updated:[2023 年 9 月底,Cloudflare 宣布向所有基于 TLS 1.3 的代
-简而言之,TLS 握手过程中客户端发送的字节数组,也就是 Client Hello 阶段的一些字段和扩展名,通过固定方式拼接,基于摘要 MD5 来生成一个唯一的字符串,称为 JA3 指纹。不同的浏览器或 TLS 客户端有不同指纹。在大量的数据采样中,CloudFlare 就能够基于此数据 (JA3 & JA3S,后者包含了 Server Hello 阶段的服务端指纹) 统计出哪些请求来自于僵尸网络、机器人爬虫、Python 库还是正常用户的浏览器、或者手机访问。这也就解释了很多同学写爬虫时,利用 HTTP 协议更换 `User-Agent` 这一请求头无效的情况,因为 CloudFlare 的防御处在更底层的 L4 TLS 阶段。ChatGPT 的 Web 端也部署了 [CloudFlare 的 TLS JA3 指纹鉴定 WAF (仅限 Enterprise 账户)](https://developers.cloudflare.com/bots/concepts/ja3-fingerprint/);GitHub 上我也找到了相关的代码实现通过更换 TLS Client 的方式来绕过这一防御。对于多数人来说,这已经有很大的防爬门槛了;而且 CloudFlare 可以随时更换 WAF 策略让旧的指纹失效。
+简而言之,TLS 握手过程中客户端发送的字节数组,也就是 Client Hello 阶段的一些字段和扩展名,通过固定方式拼接,基于摘要 MD5 来生成一个唯一的字符串,称为 JA3 指纹。不同的浏览器或 TLS 客户端有不同指纹。在大量的数据采样中,Cloudflare 就能够基于此数据 (JA3 & JA3S,后者包含了 Server Hello 阶段的服务端指纹) 统计出哪些请求来自于僵尸网络、机器人爬虫、Python 库还是正常用户的浏览器、或者手机访问。这也就解释了很多同学写爬虫时,利用 HTTP 协议更换 `User-Agent` 这一请求头无效的情况,因为 Cloudflare 的防御处在更底层的 L4 TLS 阶段。ChatGPT 的 Web 端也部署了 [Cloudflare 的 TLS JA3 指纹鉴定 WAF (仅限 Enterprise 账户)](https://developers.cloudflare.com/bots/concepts/ja3-fingerprint/);GitHub 上我也找到了相关的代码实现通过更换 TLS Client 的方式来绕过这一防御。对于多数人来说,这已经有很大的防爬门槛了;而且 Cloudflare 可以随时更换 WAF 策略让旧的指纹失效。
JA3 由来自 salesforce 的三位工程师共同实现:John Althouse, Jeff Atkinson & Josh Atkins。看到这里,想必你也知道为什么 JA3 叫 `JA3` 了。
## 盈利模式
-和 Vercel,Netlify 如出一辙,Cloudflare 采用「免费试用,付费增值」的商业模式。CloudFlare CEO Matthew Prince 曾在 StackOverflow 上回答过这个问题:「[How can CloudFlare offer a free CDN with unlimited bandwidth?](https://webmasters.stackexchange.com/questions/88659/how-can-cloudflare-offer-a-free-cdn-with-unlimited-bandwidth)」:
+和 Vercel,Netlify 如出一辙,Cloudflare 采用「免费试用,付费增值」的商业模式。Cloudflare CEO Matthew Prince 曾在 StackOverflow 上回答过这个问题:「[How can Cloudflare offer a free CDN with unlimited bandwidth?](https://webmasters.stackexchange.com/questions/88659/how-can-cloudflare-offer-a-free-cdn-with-unlimited-bandwidth)」:
- 更多的免费用户意味着更多的数据,这些数据能更好地帮助保护付费用户
-- 很多大客户的来源正是由于这些公司的员工是 CloudFlare 的免费用户,他们在工作中向公司推荐了 CloudFlare
+- 很多大客户的来源正是由于这些公司的员工是 Cloudflare 的免费用户,他们在工作中向公司推荐了 Cloudflare
- 免费这一举措就是在做宣传,可以减少招聘成本,能雇到全球最厉害的工程师
- 免费用户体验新功能的同时也能就帮助了这个新功能的测试,缩短了迭代周期
- 带宽成本的鸡生蛋、蛋生鸡问题:用户数量庞大才能在面对全球各地的电信营运商时有议价权
-2019 年,CloudFlare 在纽交所上市,股票代码:NET。发行价 US $15,目前 US $63,上涨了 320%。画外音:现在买它还来得及吗?
+2019 年,Cloudflare 在纽交所上市,股票代码:NET。发行价 US $15,目前 US $63,上涨了 320%。画外音:现在买它还来得及吗?
-在中国目前和京东云合作,仅限企业用户。500 强企业中目前有三分之一使用 CloudFlare,还有很多上升空间。OpenAI 的 [ChatGPT](https://chat.openai.com) 上线后,CloudFlare 获得了大量曝光,防御了大量滥用用户和潜在威胁请求。
+在中国目前和京东云合作,仅限企业用户。500 强企业中目前有三分之一使用 Cloudflare,还有很多上升空间。OpenAI 的 [ChatGPT](https://chat.openai.com) 上线后,Cloudflare 获得了大量曝光,防御了大量滥用用户和潜在威胁请求。
## 价值观
-CloudFlare 因坚持网络中立原则受到了一些批评。
+Cloudflare 因坚持网络中立原则受到了一些批评。
-比较典型的一件事是 CloudFlare 因舆论和法律的压力[终止对 8chan 的服务](https://blog.cloudflare.com/zh-cn/terminating-service-for-8chan-zh-cn)。CloudFlare 声称自己是一家私营公司,并且 CloudFlare 半数营收来自于美国之外的地区,可以不受美国宪法第一修正案的约束,其服务的客户对象是整个互联网市场。由于业务量大,有些包含恐怖主义、仇恨言论的网站也免不了会使用其服务。这也是大多数大型互联网公司所面临的问题。和快播王欣事件类似,他们都不愿扮演内容仲裁者。互联网诞生至今,法律的步伐总是跟不上技术的发展。
+比较典型的一件事是 Cloudflare 因舆论和法律的压力[终止对 8chan 的服务](https://blog.cloudflare.com/zh-cn/terminating-service-for-8chan-zh-cn)。Cloudflare 声称自己是一家私营公司,并且 Cloudflare 半数营收来自于美国之外的地区,可以不受美国宪法第一修正案的约束,其服务的客户对象是整个互联网市场。由于业务量大,有些包含恐怖主义、仇恨言论的网站也免不了会使用其服务。这也是大多数大型互联网公司所面临的问题。和快播王欣事件类似,他们都不愿扮演内容仲裁者。互联网诞生至今,法律的步伐总是跟不上技术的发展。
## 尾声
-OpenAI 的 ChatGPT 对 CloudFlare 作了一次很好的展示,我向读者推荐 CloudFlare。一方面是因为它一直提供永久的个人免费服务,另一方面是它的易用性以及全球视野。我也用过国内某厂商的 WAF 产品,界面纷繁错乱,一看账单都不知道为什么收费,套路太深,价格高昂(可能怪我太穷)。
+OpenAI 的 ChatGPT 对 Cloudflare 作了一次很好的展示,我向读者推荐 Cloudflare。一方面是因为它一直提供永久的个人免费服务,另一方面是它的易用性以及全球视野。我也用过国内某套路厂商的 WAF 产品,界面纷繁错乱,一看账单都不知道为什么收费,套路太深,价格高昂(可能怪我太穷)。
diff --git a/posts/how.md b/posts/how.md
index 90739039..c114027b 100644
--- a/posts/how.md
+++ b/posts/how.md
@@ -20,7 +20,7 @@ tags: markdown, example, guide, jamstack, ssg, vercel, nextjs
博客相关的信息配置,如标题、作者等可在 `lib/config.mjs` 文件中配置。
-推荐使用 [pnpm](https://pnpm.io/zh/) 来作为 node.js 的依赖管理工具。
+推荐使用 [pnpm](https://pnpm.io/zh/) 来作为 node.js 的依赖管理工具(相比官方 npm,pnpm 拥有非常大的优势: 速度更快,且节省空间)。
```shell
pnpm install
@@ -32,9 +32,11 @@ pnpm dev
通过 `pnpm build` 来打包,`pnpm start` 则用于生产环境的启动。
通过 `pnpm fmt` 来将所有代码和文本进行格式化。
+这篇文章展示了此博客项目所能展示的一切媒体信息,比如代码引用、表格展示、图片、视频、豆瓣卡片等等。
+
## 技术细节
-此站点由 `Next.js` 框架和 `TailwindCSS` 样式构成。前者是一项基于 React 的 SSG/SSR 开源项目,后者是一个目前流行的原子化 CSS 库,让不太会写 CSS、基础薄弱的我也能快速的写出灵活的样式。
+此站点由 Vercel 公司开源的 `Next.js` 框架和 `TailwindCSS` 样式构成。前者是一项基于 React 的 SSG/SSR 开源项目,后者是一个目前流行的原子化 CSS 库,让不太会写 CSS、基础薄弱的我也能快速的写出灵活的样式。
Next.js 会主动调用我们写好的一些函数 (`getStaticProps()`),让组件得到数据的输入,从而**在构建阶段**将 React 组件提前渲染完成。`remark` 库可以将原生的 markdown 语法编译成 html 对应的 dom - 在此项目中,我们让它固定遍历 `posts` 文件夹下的 markdown 文件,依次编译,让其作为 `[id].js` 的动态路由页面的 `props`,从而渲染出博客文章:
@@ -88,16 +90,14 @@ Result:
### Images
-
-
-~~我被横线划过。~~
+
### Video
-Same as the movie component:
+可以直接通过 `