《虚实之间》

感受

这本书是我2020年买的,2022年掏出来读。原因是听说他因为一些事被判入狱,读完全书后感觉32块定价的书可以听大佬讲述自己的亲身经历还是蛮值的,他优秀到让人妒忌,却又不乏有些惋惜。芮成钢在此书中记载了他在国外经历在达沃斯为国发声,对社会资源分配,奢侈品,中美关系等的一些看法。最喜欢的一句话是 ”人是环境的产物“ ,他的优秀很大部分是因为一个良好的家庭环境 (8亿人只看8个样板戏的年代,他父亲是其中一部的作者)。给子女创造好的环境或者是自己养成一种学习的氛围,这是我们后天每个人都能做到的。

mBART-50模型gRPC封装

背景

事情是这样的,我搬砖的地方每个月都会代理几百上万的海外素材,因为涉及到语言问题都是需要英文转中文的也就是翻译。 翻译是需要成本,我们的做法是做一个中英文的映射关系这样能节约成本但是副作用是丢失语义。

调研后发现 huggingface 有两款机器学习的模型比较试用所以就尝试封装成了一个小的服务。

省流

  1. 仅简单的封装了层gRPC没有深入的调整参数
  2. 基于机器学习效率吃算力,效果看模型。(我是不粘锅)
  3. 效果一般没商业化的翻译精准

效果展示

介绍

facebook/mbart-large-50-one-to-many-mmt 可以将英语翻译成下面提到的其他49种语言。要翻译成目标语言,目标语言id必须作为第一个生成的令牌。要强制将目标语言id作为第一个生成的令牌,请将forced_bos_token_id参数传递给generate方法。

Arabic (ar_AR), Czech (cs_CZ), German (de_DE), English (en_XX), Spanish (es_XX), Estonian (et_EE), Finnish (fi_FI), French (fr_XX), Gujarati (gu_IN), Hindi (hi_IN), Italian (it_IT), Japanese (ja_XX), Kazakh (kk_KZ), Korean (ko_KR), Lithuanian (lt_LT), Latvian (lv_LV), Burmese (my_MM), Nepali (ne_NP), Dutch (nl_XX), Romanian (ro_RO), Russian (ru_RU), Sinhala (si_LK), Turkish (tr_TR), Vietnamese (vi_VN), Chinese (zh_CN), Afrikaans (af_ZA), Azerbaijani (az_AZ), Bengali (bn_IN), Persian (fa_IR), Hebrew (he_IL), Croatian (hr_HR), Indonesian (id_ID), Georgian (ka_GE), Khmer (km_KH), Macedonian (mk_MK), Malayalam (ml_IN), Mongolian (mn_MN), Marathi (mr_IN), Polish (pl_PL), Pashto (ps_AF), Portuguese (pt_XX), Swedish (sv_SE), Swahili (sw_KE), Tamil (ta_IN), Telugu (te_IN), Thai (th_TH), Tagalog (tl_XX), Ukrainian (uk_UA), Urdu (ur_PK), Xhosa (xh_ZA), Galician (gl_ES), Slovene (sl_SI)

项目仓库

quick_start_mbart-50

调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
syntax = "proto3";

service MBARTLarge50 {
rpc InterpretE2C (EnglishRequest) returns (ChineseReply) {}
}

message EnglishRequest {
string message = 1;
}


message ChineseReply {
string message = 1;
}

k8s虚拟机环境部署

kubeadm

kubeadm 是 Kubernetes 社区提供的集群构建工具,它负责构建一个最小化可用集群并执行启动等必要的基本步骤,简单来讲,kubeadm 是 Kubernetes 集群全生命周期管理工具,可用于实现集群的部署、升级/降级及卸载等。

kubernetes集群的部署风格主要有2种

  1. 独立组件模式,手动官方下载二进制包
  2. 静态Pod 模式

kubeadm 是个官方安装器,可以方便实现第二种模式的安装,并且提供 init、join、upgrade、reset 等命令管理整个集群

安装先决条件

产考官方文档需要先执行一些配置

说明

宿主机: macos big sur
虚拟机: vmware / Linux 5.15.0-43-generic

1.hostname 重命名

由于 Kubernetes 使用主机名来区分集群里的节点,所以每个节点的 hostname 必须不能重名

1
sudo vi /etc/hostname

2.安装 Docker Engine

1
sudo apt install -y docker.io

3.cgroup -> systemd

目的:更改设置,令容器运行时和 kubelet 使用 systemd 作为 cgroup 驱动,以此使系统更为稳定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

cat <<EOF | sudo tee /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}
EOF

sudo systemctl enable docker
sudo systemctl daemon-reload
sudo systemctl restart docker

4.转发 IPv4 并让 iptables 看到桥接流量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

sudo modprobe overlay
sudo modprobe br_netfilter

# 设置所需的 sysctl 参数,参数在重新启动后保持不变
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF

# 应用 sysctl 参数而不重新启动
sudo sysctl --system

5.关闭 Linux 的 swap 分区

1
2
sudo swapoff -a
sudo sed -ri '/\sswap\s/s/^#?/#/' /etc/fstab

6.kubeadm 安装

官方文档产考

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
修改源

sudo apt install -y apt-transport-https ca-certificates curl

curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add -

cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF

sudo apt update


下载安装

sudo apt install -y kubeadm=1.23.3-00 kubelet=1.23.3-00 kubectl=1.23.3-00


锁死版本
sudo apt-mark hold kubeadm kubelet kubectl

7.下载组件镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//从国内的镜像网站下载然后再用 docker tag 改名

repo=registry.aliyuncs.com/google_containers

for name in `kubeadm config images list --kubernetes-version v1.23.3`; do

src_name=${name#k8s.gcr.io/}
src_name=${src_name#coredns/}

docker pull $repo/$src_name

docker tag $repo/$src_name $name
docker rmi $repo/$src_name
done

安装Master

1
2
3
4
5

sudo kubeadm init \
--pod-network-cidr=10.10.0.0/16 \
--apiserver-advertise-address=192.168.233.128 \
--kubernetes-version=v1.23.3

依次执行

1
2
3
mkdir -p $HOME/.kube 
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

保存

1
2
kubeadm join 192.168.233.128:6443 --token r0ew6o.vdveyxypwco4it1p \
--discovery-token-ca-cert-hash sha256:c41d777b8339d8ba1a8f04698847675a7bf241802c64a401340bfe100888edee

查看节点状态

1
kubectl get node

发现网络状态异常缺少网络插件,集群的内部网络还没有正常运作

安装 Flannel

GitHub: https://github.com/flannel-io/flannel/

我们先下载 flanneld 二进制文件然后修改 配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
修改 

/opt/bin/flanneld => "自己的文件路径"
10.244.0.0/16 => 10.10.0.0/16


---
kind: Namespace
apiVersion: v1
metadata:
name: kube-flannel
labels:
pod-security.kubernetes.io/enforce: privileged
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: flannel
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- apiGroups:
- ""
resources:
- nodes
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes/status
verbs:
- patch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: flannel
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: flannel
subjects:
- kind: ServiceAccount
name: flannel
namespace: kube-flannel
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: flannel
namespace: kube-flannel
---
kind: ConfigMap
apiVersion: v1
metadata:
name: kube-flannel-cfg
namespace: kube-flannel
labels:
tier: node
app: flannel
data:
cni-conf.json: |
{
"name": "cbr0",
"cniVersion": "0.3.1",
"plugins": [
{
"type": "flannel",
"delegate": {
"hairpinMode": true,
"isDefaultGateway": true
}
},
{
"type": "portmap",
"capabilities": {
"portMappings": true
}
}
]
}
net-conf.json: |
{
"Network": "10.10.0.0/16",
"Backend": {
"Type": "vxlan"
}
}
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: kube-flannel-ds
namespace: kube-flannel
labels:
tier: node
app: flannel
spec:
selector:
matchLabels:
app: flannel
template:
metadata:
labels:
tier: node
app: flannel
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/os
operator: In
values:
- linux
hostNetwork: true
priorityClassName: system-node-critical
tolerations:
- operator: Exists
effect: NoSchedule
serviceAccountName: flannel
initContainers:
- name: install-cni-plugin
#image: flannelcni/flannel-cni-plugin:v1.1.0 for ppc64le and mips64le (dockerhub limitations may apply)
image: docker.io/rancher/mirrored-flannelcni-flannel-cni-plugin:v1.1.0
command:
- cp
args:
- -f
- /flannel
- /opt/cni/bin/flannel
volumeMounts:
- name: cni-plugin
mountPath: /opt/cni/bin
- name: install-cni
#image: flannelcni/flannel:v0.19.0 for ppc64le and mips64le (dockerhub limitations may apply)
image: docker.io/rancher/mirrored-flannelcni-flannel:v0.19.0
command:
- cp
args:
- -f
- /etc/kube-flannel/cni-conf.json
- /etc/cni/net.d/10-flannel.conflist
volumeMounts:
- name: cni
mountPath: /etc/cni/net.d
- name: flannel-cfg
mountPath: /etc/kube-flannel/
containers:
- name: kube-flannel
#image: flannelcni/flannel:v0.19.0 for ppc64le and mips64le (dockerhub limitations may apply)
image: docker.io/rancher/mirrored-flannelcni-flannel:v0.19.0
command:
- /root/flanneld
args:
- --ip-masq
- --kube-subnet-mgr
resources:
requests:
cpu: "100m"
memory: "50Mi"
limits:
cpu: "100m"
memory: "50Mi"
securityContext:
privileged: false
capabilities:
add: ["NET_ADMIN", "NET_RAW"]
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: EVENT_QUEUE_DEPTH
value: "5000"
volumeMounts:
- name: run
mountPath: /run/flannel
- name: flannel-cfg
mountPath: /etc/kube-flannel/
- name: xtables-lock
mountPath: /run/xtables.lock
volumes:
- name: run
hostPath:
path: /run/flannel
- name: cni-plugin
hostPath:
path: /opt/cni/bin
- name: cni
hostPath:
path: /etc/cni/net.d
- name: flannel-cfg
configMap:
name: kube-flannel-cfg
- name: xtables-lock
hostPath:
path: /run/xtables.lock
type: FileOrCreate

安装 Flannel 网络

1
kubectl apply -f kube-flannel.yml

再看下网络状态正常

安装worker节点

1
2
sudo kubeadm join 192.168.233.128:6443 --token r0ew6o.vdveyxypwco4it1p \
--discovery-token-ca-cert-hash sha256:c41d777b8339d8ba1a8f04698847675a7bf241802c64a401340bfe100888edee

检查运行状态

1
kubectl get node

产考文档

https://xie.infoq.cn/article/8a4003999a03ebae0e325c412

https://kubernetes.io/zh-cn/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/

https://time.geekbang.org/column/article/534762

大型网站技术架构

说两句

这本书其实是我3年前读过的一本书,用它来进行第一次视频专栏的尝试其实本质原因是因为我感觉经过3年的知识储备后我有能力讲好它。

2019年的读书笔记

目录

名称 文档 链接 更新时间
介绍 文稿 视频 2022-06-14 12:59:29
演化历程 文稿 视频 2022-06-14 13:32:05
架构套路 文稿 视频 2022-06-16 00:49:29
性能的定义 文稿 视频 2022-08-07 14:16:40

ps:道歉断更了,原因如下

其实我做短视频没多久,断断续续去更新目前700来粉。并没有带来什么经济价值,并且在平台上讲话要小心翼翼,这不是我想要的我是个口无遮拦的人没法时时刻刻的唱赞歌。道歉!

又拍云上传文件漏洞

背景

客服小姐姐突然告诉我,我们网站域名下有一段带颜色的视频。比较奇怪,网站上好像没有开放用户上传MP4的口。排查下来发现是又拍的一个 文件上传漏洞(其实也怪自己没仔细读文档),找了公司对接的又拍售后给到的答复大概意思是 影响大无法修改

知识扩展

上传漏洞定义

文件上传漏洞是指用户上传功能没有做好检验或者过滤不严,用户上传了可执行脚本或者未经约定的文件类型。以往的定义中此类漏洞要一直完成到提权才算一次完整的渗透注入,个人认为只要用户行为与我们约定的行为相违背就可以称为一次成功的操作不一定是需要提权。拿本次事件举例,我们使用CDN并没有提权一说但是公司可能面临管局约谈的风险,并且攻击者达到了自己的目的。

常见手段

限制方法 绕过方法
服务端设置blaklist 寻找list以外的扩展名别名或者混淆大小写
filename后缀白名单 双重后缀 xxx.png.php
MIME类型检测 修改上传http包content-type值
头文件内容检测 修改头部那几个字节让它看着像正常的

又拍上传漏洞复现

我们先计算出form api 需要的 policyauthorization

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?php
function sign($key, $secret, $method, $uri, $date, $policy=null, $md5=null)
{
$elems = array();
foreach (array($method, $uri, $date, $policy) as $v)
{
if ($v)
{
$elems[] = $v;
}
}
$value = implode('&', $elems);
//echo $value."\n";
$sign = base64_encode(hash_hmac('sha1', $value, $secret, true));
return 'UPYUN ' . $key . ':' . $sign;
}
function main()
{
$key = '操作员名';
$secret = '密码';
$uri = '/服务空间';
$method = 'POST';
$date = gmdate('D, d M Y H:i:s \G\M\T');
$md = md5($secret);
$mybucket = "phpzjj"; //空间名
$mytime = time() + 600;
$mykey = '/opinion/1.png'; //详情看官方文档
$allow = 'jpg,jpeg,png';//文件类型限制
$limit = 1024000 * 3;//大小限制
$leng = "0,{$limit}";
$option = array('x-upyun-meta-ttl'=>1,'bucket'=>$mybucket,'expiration'=>$mytime,'save-key'=>$mykey,'allow-file-type'=>$allow,'content-length-range'=>$leng,'date'=>$date);
$option = json_encode($option,JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
$policy = base64_encode($option);
// 上传,处理,内容识别有存储
echo sign($key, md5($secret), $method, $uri, $date,$policy) . "\n";
echo $policy;
}
main();

然后用 CURL 上传不同的文件

1
2
3
4
5
curl http://v0.api.upyun.com/phpzjj \
-F authorization="UPYUN blogtest:JxWvy+4Wi/THxzpMzW2v6U/vSxg=
" \
-F file=@黑产 \
-F policy=eyJ4LXVweXVuLW1ldGEtdHRsIjoxLCJidWNrZXQiOiJwaHB6amoiLCJleHBpcmF0aW9uIjoxNjU5MjUyMTM1LCJzYXZlLWtleSI6Ii9vcGluaW9uLzEucG5nIiwiYWxsb3ctZmlsZS10eXBlIjoianBnLGpwZWcscG5nIiwiY29udGVudC1sZW5ndGgtcmFuZ2UiOiIwLDMwNzIwMDAiLCJkYXRlIjoiU3VuLCAzMSBKdWwgMjAyMiAwNzoxMjoxNSBHTVQifQ==

正常情况下


符合预期

传一个html试试

符合预期

我们把html换成jpg再看下

已经上传成功并且在又拍的控制台也识别为了html文件(浏览器打开也是html)

当时黑产也是利用这种方式给我们挂了个小黄页,打开这个html文件发现不仅是我们这样的小站,像小红书这样的大站也没幸免 m3u8的播放list就放他们的CND上

这里我找过又拍的企业对接技术,他告诉我们是通过filename的方式来限制文件上传类型的,表示理解但是,既然是filename区分我也确实限制死了文件后缀类型。为什么去掉后缀依然能上传???

不过又拍也是积极响应修改了文档并且增加了 file-ext-required 作为弥补措施

我事后也仔细阅读了又拍的文档

https://help.upyun.com/knowledge-base/form_api/#_2

好的,严格上说起来除了无后缀可上传外其他的好像是我们的问题 :-(

修复建议

对于这个只需要传图的业务场景修复方案其实很简单

  1. 走后端上传,先服务器判断下上传类型 (我都用form api干嘛还要传到自己服务器?
  2. 顺便加个图片处理参数比如 x-gmkerl-quality 又拍会去强验证是否是一张图片(推荐)
  3. 只让上传一种图片格式并且写死content-type

总结

事后我对比其他做CND的厂商,他们的做法其实大体和又拍差不多。唯一不同的是他们有些策略降低了程序员对安全方面的心智负担,个人认为在做一个需求时除非对安全方面知识腌制入味要不很难从文档中读出什么影响安全的猫腻,特别是我这种蹩脚的三流野生PHPER。

oss 测试

1
2
3
policy

{"expiration":"2022-07-31T15:47:50Z","conditions":[["content-length-range",0,20971520],["starts-with","$key","ips_user_asset\/16\/59\/25\/36\/40\/78\/788028ff7b085391fee5967bd982d500.jpg"]]}

不过值得一提的是比如阿里的oss虽然在用户上传时候可以通过修改后缀的方式成功上传一个恶意源文件,但是它返回的content-type头是根据后缀来的而不是读头文件,这样避免了恶意文件被用户直接打开。其实常见的媒体头也没多少,我们做个返回时后缀匹配content-type就可以在大多场景下解决这个问题。

1
2
3
4
5
6
text/html : HTML格式
text/plain :纯文本格式
text/xml : XML格式
image/gif :gif图片格式
image/jpeg :jpg图片格式
image/png:png图片格式

文件后缀 优先级 大于读文件头这种方式更适合直觉,毕竟jpg的后缀给 html的content-type是不合理的。

《自控力》

感受

从我感觉自己有严重的学生综合征起就会有意识的提高自己的自控力,但苦于方式方法是顺从直觉去完成的始终事与愿违。读了这本书后受到了蛮多启发,很多提高自控力的行为都是反自觉的(如书中提到的原谅自己之前的行为及时止损注意以后的行为,白熊测试等)。

《边城》

感受

读它的背景是在上海封闭隔离的第30天。《边城》很忠实的记载了故事的地理人文历史,生动的刻画出湘西边境小山区的人民的淳朴形象,它是一个凄凉的爱情故事能激发很多感叹,同时沈老的文字也把最近在魔都愤愤不平的我带到了一个民风淳朴的小山村缓解了些许心理上的不适。

《Go语言底层原理剖析》

感受

这本书我会再重新看一次并且整理出视频专栏,因为讲得太好了!

个人感觉写得很好的一本书,断断续续读了不止一个月,书的内容和书名一样就是剖析Go的实现和底层的一些原理。每小节都分成了两部分 使用实战和实现讲解。读完全书收益颇多,印象最深的是对基础类型的讲解(字符串,数组,切片,哈希表),反射的使用 GMP的调度机理 线程进程协程的区别

笔记

点开GO子树

《UNIX网络编程_卷1》

感受

放在工位的一本书,看了前面8章,打算后面再通读一遍做下笔记。不管是出于兴趣爱好或者是在现在内卷的环境下对基本功的提升这本书都是值得静下心来安安静静的阅读并且实践的一本书,书厚是因为讲得真的很细,即使这厚但是涉及到其中的关键字也需要后续自己再去进一步了解

笔记

网络部分

《钝感力》

感受

书前半部分很有意思,全书就一个论点降低敏感度是有益的不管是从进化过程和机理反应。后面几节就有点牵强了有点强行凑数的感觉。钝感力有点像之前读的反脆弱,我也更偏向于反脆弱,不是用阿Q法去治愈或者忽略伤害带来的痛苦而是靠强大的自愈能力去加强巩固自身变得更强大

请我喝杯咖啡吧~