洗澡时,我终于跑出来喊出了我的 Eureka

2018-12-14 13:10:06 +08:00
 ChristopherWu

来自我的公众号『 YongHao 写东西的 Cache 』 打个小广告,还是希望写的东西有人看🙊

洗澡时,我终于跑出来喊出了我的 Eureka

今天与一位帅气的同事一起解决了一下 ssh 的相关问题,在我装逼的提及不需要显式指定 identity key 的时候,顺道提及 known_hosts 也是一样的时候,说到了known_hosts的现象:

但是原理被含糊不清的略过去了———至少没有刻意提到,因为我是不大懂的。

在今晚洗澡时,回想了一下今天的事情,想到了这件事情,不禁尝试想清楚 kown_host 是啥东西,为什么需要它。

前几天看到知乎上,有一篇文章介绍了拉马努金自己尝试推导一切未知但已成结论的数学公式,作者学习此方法自己尝试推导出机器学习的论文。

不知道是不是潜意识的影响(我在那时肯定没想到这篇文章),我在结合以上已知 known_host 的两点现象,以及以前零散的 ssh 原理知识,尝试推导 ssh 为什么运作的。

RSA 的原理无需累述,就用我以前总结过的为介绍吧:

RSA 是非对称加密算法, 对称算法就是双方用同一个密钥加密。RSA 是基于对两个质数相乘容易,而将其合数 分解很难的这个特点进行的加密算法 生成公钥与私钥, 公钥加密而私钥解密, 或者相反都可以。 一般公钥公开到网上, 想发送信息给你的人用公钥加密, 而只有你拥有私钥可以解密, 这样确保了信息的保密。 或者你用私钥加密, 其他所有人都可以用公钥解密你的信息, 这样可以确保信息是由你所发出。 网上发邮件或者个人网站上所用到的签名, 就是使用此技术。

而 SSH 就是利用了这个原理,你可以从此方面尝试去推导出你如何做一个 ssh。

而我推导出的过程是这样的:

目的就是 server 要识别 client 就是 authorize_keys 里记录的 client

  1. 在 server 上的authorize_keys里添加 client 的公钥了(这步大家都知道)

  2. client 发起 ssh 连接到 server,发送公钥给 server

  3. server 用 client 发送的公钥对比 authorize_keys里的记录是否一致,认证 client 是否有权限

  4. 此时 server 发送一个字符串(如"generated by server")发送给 client,目的就是 client 用私钥加密后,发回去后,server 可以解密,与记录的字符串对比一致

  5. 此时可以确认 client 就是authorize_keys 里记录的 client 了

以上一切完成。

为什么需要known_host呢? 上述过程有一个问题就是,无法抵御中间人攻击。

假如在你以后链接 server 时,被中间人攻击了,中间人模仿 server 的行为与你进行 ssh 校验,你就会连上去,并且难以发现。

因此显然易见的一个方法就是,在第一次建立连接成功后,在一个文件里记录 IP,公钥这样的键值对,以后连接时对比一下与第一次连接的公钥是否一致即可。 而这个文件就被 ssh 命名为 known_hosts ,因此不一致时,拒绝了你的 ssh 连接,并且提示 中间人攻击。

那么保证第一次连接是对的话,就只有人工去对比了。 服务器自己公开公钥信息了,客户端自己去对比。


对比结果

事后对比,以上的做法是对的,只是没那么严谨。

有以下几个细节是不同的:

  1. 客户端应该是需要发送公钥到服务器的,目前没有看到有说明这个的地方,需要再查
  2. 发送的固定字符串,不是用明文,而是用客户端的公钥加密了
  3. 服务器发给客户端去做私钥加密时,生成的不是固定的字符串,而是随机字符串(这个是细节没有打磨,因为发送固定字符串,明显客户端私钥加密过的东西是固定的,就无法保密了)
  4. 最后对比这个随机字符串时,还用了SessionKey来做 md5,还没细查

感想

以上的文章,技术细节不怎么重要,重要的是背后的一些大家都知道道理:

对一切保持好奇心,尽量探寻其中的原理,这才对得住计算机科学。赫歇尔对好奇七色光实验为何会有额外的温度变化才发现不可见光(红外线,紫外线呢),法拉第不懈尝试各种材料才发现玻璃能帮助磁场让光改变路径,证实磁场与光有关联。 计算机也是基于黑盒上完整的生态圈,如 HTTP,TCP,CPU,PL 等,同样可以对他们保持好奇心,与用拉马努金的方法来推导构建此黑盒,与自己的对比,想必大有裨益。

花絮

Why Eurekai ? Eureka – (希腊语:εὕρηκα;拉丁化:Eureka ;词义:“我发现了!”)

阿基米德在洗澡时发现浮力原理,高兴得来不及穿上裤子,跑到街上大喊:“Eureka!”

古希腊学者阿基米德 (Archimedes),有一天,他在洗澡的时候发现,当他坐进浴盆里时有许多水溢出来,这使得他想到:溢出来的水的体积正好应该等于他身体的体积,这意味着,不规则物体的体积可以精确的被计算,这为他解决了一个棘手的问题。阿基米德想到这里,不禁高兴的从浴盆跳了出来,光着身体在城里边跑边喊叫着 “尤里卡!尤里卡!”,试图与城里的民众分享他的喜悦。

So.. Eureka! Eureka!

在自己设计想清楚了 SSH 之后,我在寒冬不禁高兴的从浴室跳了出来,光着身体在客厅边跑边喊叫着 “ Molly,Molly ”, 跟女票论述了我此番的感想。

因为她对 ssh 原理心中一直有根刺,也很感兴趣,让我把 ssh 以及 RSA 的原理都给她说了一遍,草稿如下:


3,5,7,11,13,17。。。

191 (13,17)

公钥 《=》私钥

公钥暴露,别人无法暴力破解对比出私钥

=》私钥永远不能暴露,不能发送出去,只能放自己机器。

公钥 私钥

公钥放 GitHub 服务器

molly ssh 到 GitHub =》 molly 发起 ssh 链接 -》 发公钥给 GitHub -》 GitHub 就可以跟你放 GitHub 服务器的公钥做对比,校验你有没有权限 -》“随机生成的字符串” 发给 molly -》 molly 用私钥来加密随机生成的字符串 ,发给 GitHub -》 GitHub 用 molly 的公钥来解开这个内容,对比是否刚刚发给 molly 的随机字符串 =》一切都通了。

中间人 =》 你要想像中间随便有一个人可以监听你的网络

molly -- chalres -- github

  1. SSL
  2. ~/.ssh/known_hosts
8088 次点击
所在节点    程序员
64 条回复
ChristopherWu
2018-12-14 16:18:34 +08:00
@jadec0der 我确实不知道 『 你如果没有意识到 SSH 连接中有两套公私钥,其中一套专门用来认证 known host 的话』, 但不至于『这文章其实什么都没搞明白』吧。。。

我之后会再去看相关的东西的,不影响先做『自己的设计猜想』,再去对比的,所以不至于「思而不学则殆」啦。

我觉得我最大的问题是 学而不思。。写代码时,遇到 bug 时,遇到不清楚的技术细节时,通常都是看别人的说法,看书,而没有经过自己的日常思考,导致不牢固。
Neoth
2018-12-14 16:24:23 +08:00
计算机科学,所有内容都是人类自己编造出来的,这种事儿,还需要你 “尤里卡” ???
人家自然科学家发现了前无古人发现 的新自然规则,那才叫 “尤里卡”。

你这个不去看 RFC,自己蹲浴缸玩阿加莎克里斯蒂的,叫文青意淫
cxh116
2018-12-14 16:25:08 +08:00
你要的 ~/.ssh/known_hosts 里的公钥一般对应在 /etc/ssh 目录下的公钥.

为了保险,你可以手动把服务器的公钥添加到客户端的 ~/.ssh/known_hosts 文件里再去建立连接,就像把客户端的公钥手动添加到服务器 ~/.ssh/authorized_keys 目录一样..
或在连接时检查提示的公钥和服务器的公钥的指纹是否一致也行 (ssh-keygen -lf /etc/ssh/ssh_host_xxx_key.pub 查看指纹).
ChristopherWu
2018-12-14 16:29:50 +08:00
@Neoth 我觉得你有点误解了这篇文章了。。
Neoth
2018-12-14 16:32:28 +08:00
@ChristopherWu 木有误解,还是 “再造轮子” 的激情在鼓舞着你
hxndg
2018-12-14 17:05:23 +08:00
@Keyes
私钥并不能推导出公钥,这两者是密码学的概念即用其中一个加密,只能用另外一个解密。
很多情况下把公钥当成私钥,把私钥当成公钥,并非不可以,只不过是需要将原本的私钥公开,而原本的公钥不公开罢了。
Keyes
2018-12-14 17:15:15 +08:00
@hxndg 谢谢,感谢指点
Keyes
2018-12-14 17:16:32 +08:00
@msg7086 总之核心思想就是就是用一个来加密就只能用另一个解密,反之一样
msg7086
2018-12-14 18:03:11 +08:00
#41 @ChristopherWu 这块确实我看帖子的时候也看漏了。

SSH 密钥连接有两个密钥对。一个是 SSH 密钥对,也就是服务器下 /etc/ssh/ 下面 ssh_host 开头的密钥,这个是用来证明服务器是服务器的,公钥会写在客户端的 known_hosts 里。另一个是登录密钥对,也就是客户端下 ~/.ssh/ 下面 id 开头的密钥,这个是用来证明你是你的,公钥会写在服务器的 authorized_keys 里。你写帖子的时候应该是把这两个东西搞混了。

再另外,为了达到完美向前安全性,现代的 SSH 都采用 DHE 起手做加密了,公钥私钥仅仅用来认证,而不会用于通讯加密了。DHE 方面你有兴趣也可以去看看,很有意思的。
msg7086
2018-12-14 18:03:58 +08:00
@Keyes 是的,他们的地位是对等的。一般软件里用的私钥文件已经包含私钥和公钥了。而公钥文件只有公钥。
ChristopherWu
2018-12-14 18:20:57 +08:00
@msg7086 对的,我完全不知道有服务器在 `/etc/ssh/ssh_host_rsa_key`有自己的公钥。
我猜是一台服务器上有多用户,都可以生成自己的公私钥,这个公钥不能作为服务器的公钥的。

所以服务器自身需要唯一的公钥,就是你说的这个,用来证明服务器是服务器的。
ChristopherWu
2018-12-14 18:25:23 +08:00
@msg7086 果然是我提前就特别关注的大佬
jadec0der
2018-12-14 18:40:53 +08:00
@ChristopherWu 从 SSH 的角度看,登录服务器分为两部分,第一步是利用服务器的公私钥建立安全的连接,第二步是用户向服务器证明自己的身份(通过用户的公私钥或者密码)。这就类似你用 https 登录 v2ex,你想的那个密钥是你的用户名密码,实际上 known host 是 HTTPS 证书,完全驴头不对马嘴,我觉得说你什么都没搞明白不过分。

从信息安全的角度看,公钥完全是公开信息,比如 github 会要求你上传公钥,比如你可以在 keybase.io 公布公钥,比如 R.Stallman 会在网站上公布自己的公钥供大家验证他的身份。你想的因为服务器知道你的公钥,所以它就是真的服务器,可以说是莫名其妙。

言尽于此,
ChristopherWu
2018-12-14 18:51:47 +08:00
@jadec0der 我现在知道你的意思了。

但是你可以看看 @msg7086 在 #49 的回复,我觉得他理解了我说了什么,哪里说错了。。

『莫名其妙』不至于。。。
msg7086
2018-12-15 01:12:43 +08:00
@ChristopherWu 嗷过奖了。
网络上大家说话可能比较随便,有时候语气会重一些,就不要太在意啦,背后实际上是没有恶意的。
20015jjw
2018-12-15 05:10:13 +08:00
只能说 eureka 家的汉堡太好吃
petelin
2018-12-15 06:43:58 +08:00
@jadec0der 大佬就是大佬,一小段话就看懂了。不知道楼主要干啥,就不能看看书?
p1gd0g
2018-12-15 11:38:02 +08:00
@msg7086 弱弱的问一句,在公钥密码体制下哪一个密码学算法中私钥不能“推导”出公钥?

另外,“向前安全性”->“前向安全性”。

把俺一个密码学硕士看懵逼啦。。。
FrankD
2018-12-15 13:21:33 +08:00
@ChristopherWu “确保信息是由你所发出”,目的是防抵赖。加签验签来干这事儿的,不是加密解密。加密那是为了信息隐匿。
MrLonely
2018-12-15 15:22:52 +08:00
RSA 只支持别人用公钥加密你用私钥解密确保只打算给你看的内容不会被别人看去了,Elliptic curve 才是你用私钥加密别人用公钥解密让别人能确定这条信息是你发的不是别人假冒你发的。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/517517

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX