The Missing Semester - 第五讲 学习笔记(二)
第五讲(二) SSH入门
介绍完命令行环境后,这半节主要介绍的是ssh的有关入门知识。SSH是Secure Shell的简称。
课程视频地址:https://www.bilibili.com/video/BV1x7411H7wa
课程讲义地址:https://missing-semester-cn.github.io/2020/command-line/
本机学习使用平台:wsl1 && ubuntu20.04 + Windows10
通过如下命令,您可以使用 ssh 连接到其他服务器:
ssh [user name]@[target ip]
但是...目标服务器需要先安装ssh-server,才能进行正常的ssh交流!
配置虚拟机SSH
要想把一台机器作为服务器使用,就需要配置好相应的服务环境:
- 安装openssh-client:
sudo apt-get install openssh-client - 安装openssh-server:
sudo apt-get install openssh-server - 启动前可能需要对ssh服务器配置进行修改,例如修改端口,在下文有单独章节说明;
- 启动ssh-server:
sudo /etc/init.d/ssh restart(利用file命令可以看到这是一个一百多行的shell脚本文件,用来启动ssh服务) - 连接后,在主机使用
netstat确认ssh-server工作正常。(看到ssh连接的相应条目表示工作正常)
要注意的是,在客户端第一次对服务器进行连接时,会弹出一个提示,让你验证服务器的ssh密钥指纹(当前为ECDSA密钥):

如图,该提示意味着主机首次连接到这台服务器,SSH无法确认服务器的身份。该指纹使用的是SHA256加密格式,如果服务器是你自己的机器,可以使用ssh-keygen工具查看该机器的指纹,指纹存放在/etc/ssh/ssh_host_ecdsa_key.pub,即验证的是服务器的ECDSA公钥指纹。命令如下:
ssh-keygen -l -f /etc/ssh/ssh_host_ecdsa_key.pub
其中对命令参数的介绍如下:
-f [filename]
Specifies the filename of the key file.
-l Show fingerprint of specified public key file. For RSA and
DSA keys ssh-keygen tries to find the matching public key
file and prints its fingerprint. If combined with -v, a
visual ASCII art representation of the key is supplied with
the fingerprint.
输入命令查看得到服务器指纹,对比发现确实是一模一样的,放心连接啦!选择yes后,这将把服务器的密钥添加到你的本地SSH密钥列表中,并在以后的连接中自动验证。(加入-v参数可以看到赛博指纹)


输入正确的密码进行连接:

连接成功后主机的情况,已经可以操作服务器了:

服务器端使用netstat检验连接是否正常,最后可以使用ctrl-D断开ssh连接。

修改服务器配置文件
如果要在服务器上开启SSH服务,我们应该修改sshd_config配置文件,而不是ssh_config配置文件。
ssh_config文件是SSH客户端的配置文件,用于配置SSH客户端的行为和选项。sshd_config文件是SSH服务器的配置文件,用于配置SSH服务器的行为和选项。
但修改前要注意的是,里面已有的注释已经是默认选项,即你取不取消注释都没问题。
The commented out options in the
sshd_configare the defaults.
大多数Linux发行版中,sshd_config文件位于/etc/ssh/目录下。对于Windows上的OpenSSH,sshd_config文件多数位于C:\ProgramData\ssh\目录下;可以在sshd_config这里配置免密认证、修改 ssh 端口、开启 X11 转发等等,也可以为每个用户单独指定配置。
对于Linux系统,可以使用以下命令重新加载SSH服务器配置:
sudo systemctl reload ssh(对于systemd系统)sudo service ssh reload(对于非systemd系统)
基于密钥的认证机制
基于密钥的验证机制使用了密码学中的公钥,我们只需要向服务器证明客户端持有对应的私钥,而不需要公开其私钥。这样您就可以避免每次登录都输入密码的麻烦了。不过,私钥(通常是
~/.ssh/id_rsa或者~/.ssh/id_ed25519) 等效于您的密码,所以一定要好好保存它。
SSH采用的公私钥体系,简而言之,就是客户端给服务器提供公钥,服务器利用公钥认证登录的客户端(即证明客户端确实拥有登录私钥)。(此处有对ssh公私钥体系的知识讲解)
密钥有很多种,如ed25519 、EDCSA、RSA等等,这篇博客讲解了它们之间的区别,当前最好的还是ed25519。
生成密钥的工具为ssh-keygen,工具文档在此。
生成命令示例:
ssh-keygen -o -a 100 -t ed25519 -f ~/.ssh/id_ed25519
-o:指出私钥文件格式为 OpenSSH, OpenSSH 6.5版本引入。
-a:加密轮数。越高越难以BF破解。
-t:加密类型。 ed25519为其中一种加密方式,默认RSA加密。简略介绍见此。
-f:输出文件名称。

生成的密钥会问你是否需要设置一个passphrase,这是为了防止别人能够轻易获取你的私钥。但是,这也会在你想要利用公钥认证登录时,需要再次输入保存该密钥的passphrase。那这还算什么免密登录呢???幸好,我们有ssh-agent帮我们解决这个麻烦,在这里先不提,先把流程走一遍先。
生成ed25519密钥后,可以利用管道输入ssh服务器配置文件authorized_keys(authorized_keys文件的格式在sshd手册中有介绍):
# windows作主机也可以进行这样的管道操作
cat .ssh/id_ed25519.pub | ssh user_name@remote 'cat >> ~/.ssh/authorized_keys'
或者可以用tee工具完成这个工作:
cat .ssh/id_ed25519.pub | ssh user_name@remote tee ~/.ssh/authorized_keys
如果支持 ssh-copy-id 的话,可以使用下面这种更简单的解决方案:
ssh-copy-id -i .ssh/id_ed25519.pub user_name@remote
在这里比较推荐使用ssh-copy-id。因为单纯的管道操作不会给你验证你的输入文件到底是公钥还是私钥,而ssh-copy-id则给了这个防御性措施。(如果你错误地使用了私钥文件,还可能会暴露)
Windows没有ssh-copy-id,则可以编写相应功能的脚本来完成这一工作:
function ssh-copy-id([string]$userAtMachine, $args){
$publicKey = "$ENV:USERPROFILE" + "/.ssh/id_rsa.pub"
if (!(Test-Path "$publicKey")){
Write-Error "ERROR: failed to open ID file '$publicKey': No such file"
}
else {
& cat "$publicKey" | ssh $args $userAtMachine "umask 077; test -d .ssh || mkdir .ssh ; cat >> .ssh/authorized_keys || exit 1"
}
}
配置好客户端公钥后,即可进行“免密”的公钥认证登录,无需再次输入登录用户的密码(但仍需要passphrase)。
但是要注意的是,服务器端必须开启公钥认证!在/etc/ssh/sshd_config文件中进行修改,并且记得重启服务器端的sshd。
# 是否允许公钥身份验证,默认为yes
PubkeyAuthentication yes
# 认证公钥文件,默认情况就是我们之前所做的那样
AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2
#是否允许密码身份验证,默认为yes,当我们使用密钥可以成功登陆后,可以改为no
PasswordAuthentication no
而且要注意的是,公钥登录似乎对密钥文件权限要求特别严格..最好把服务器端的.ssh目录设为700,authorized_keys文件设为644。对于客户端:私钥必须为600权限或者更严格权限 (400), 一旦其他用户可读, 私钥就不起作用 (如640), 表现为系统认为不存在私钥; 对于服务器端:要求必须公钥其他用户不可写, 一旦其他用户可写 (如660), 就无法用key登录, 表现为:Permission denied (publickey).
参考的博文这样写:
~/.ssh/authorized_keysmust have644permission- Private key file i.e.
~/.ssh/id_rsashould be600, the name of the key may be different as per user environment- Public key file i.e.
~/.ssh/id_rsa.pubshould be644, the name of the key may be different as per user environment- The
~/.sshdirectory must not be world readable/writable so you can keep it with700permission
注意:如果你使用的是RSA加密的密钥,并且发现sshd_config文件没有RSAAuthentication这个配置选项,这是一个很有趣的坑,可能会让你无法进行密钥登录..详细原因见此博文。(所以还是用回其它加密方式的密钥吧)
如果你发现公钥认证登录失败,可以在登录时尝试利用登录参数-v打印debug信息。注意,v的个数上限为3个。
或者利用sshd的debug模式:先停掉ssh服务,然后在确保拥有755权限的/run/sshd文件夹的情况下,使用命令:sudo /usr/sbin/sshd -d开启debug模式的ssh服务器端。

我自己使用sshd启动debug模式,在公钥验证时出现过"postponed publickey" 的log,这里有一篇博文讲了这方面debug的方法:SSH fails with postponed publickey error,非常非常棒的博文!
关于添加公钥后,登录仍需密码?有关这类问题社区有提问:SSH Still Asks for Password with Public Key Setup——对这个问题做了一些以前出现过的问题的归纳。
我有一段时间一直搞不定windows10免密登录wsl1的ubuntu20.04,连wsl自己免密登录localhost也不行,一直是" Permission denied (publickey)"。但是在virtualbox上的Ubuntu18.04就能在ssh-copy-id后直接进行公钥登录……使用ssh-add也添加不上私钥认证,也找不出原因。
最后温度上来了把自己.ssh目录清空,将自己旧的ed25519密钥对删掉生成一个新的,然后从头来一遍,wsl登录localhost却可以了……而且win到wsl不行的原因更离谱。。竟然是采用管道输入的公钥在authorized_keys的格式不对(用cat命令输出,或者用vim打开都可以看到),前面多了一个/feff/符,可能是编码格式的问题。(Linux下文件开头的feff的问题)
类似wsl的ssh登录失败问题:Passwordless SSH login into WSL2 failing
关于ssh密钥格式不对可能产生的问题:SSH Key Format Issues and Fixing the “invalid format” Error
ssh-agent和ssh-add
您可以为密钥设置密码(passphrase),防止有人持有您的私钥并使用它访问您的服务器。
如教案中所言,ssh-agent存在的意义就是帮助你解决passphrase验证的过程,这需要ssh-add的帮助。
ssh-agent 是一个密钥管理器,用来管理一个多个密钥,并为其他需要使用 ssh 密钥的程序提供代理(即帮忙验证passphrase,不用每次都要自己输入)。在使用ssh-add前,先要保证ssh-agent正在运行。
利用echo $SSH_AGENT_PID来检查是否有ssh-agent进程在运行。如果没有,则需要启动。
不同操作系统中的ssh-agent的启动方式是不同的。在 Linux中: ssh-agent 在 X会话 或 **登录会话 **之初就已经启动;在Windows中: 计算机管理 -> 服务 -> OpenSSH Authentication Agent 设置为自动启动。
也可以手动启动ssh-agent:
ssh-agent $SHELL
另一种命令:eval
shell-agent, 在windows中为eval $(ssh-agent): 它并不会启动一个子shell,而是直接启动一个 ssh-agent 进程;此时当我们退出当前 bash 后,ssh-agent 进程并不会自动关闭。我们可以在当前bash退出之前,使用ssh-agent -k,或者在当前 bash 退出之后,使用kill命令,关闭对应的 ssh-agent 进程。
如果在Windows中手动启动失败,遇到error:1058问题,这里有一个关于windows10 ssh-agent启动服务失败的问题:Starting ssh-agent on Windows 10 fails: "unable to start ssh-agent service, error :1058"。
ssh-agent启动成功后,就可以开始着手passphrase的代理验证添加了:
在默认情况下,ssh-agent使用的是用户目录下.ssh目录里面保存的密钥。ssh-add在缺省情况下,会将~/.ssh/id_rsa, .ssh/id_dsa, ~/.ssh/id_ecdsa, ~/.ssh/id_ed25519, 和 ~/.ssh/identity都添加到ssh-agent里面。通过ssh-add添加私钥认证后,ssh-add -l可以看到当前ssh-agent可以访问的私钥列表。
ssh-add -l显示"The agent has no identities."的情况:ssh-add command does not add my identity to ssh-agent——大概率也是密钥文件权限问题导致的。
这一节参考博文:ssh agent详解
通过 SSH 复制文件
使用 ssh 复制文件,即在主机与远程机之间传输文件有很多方法:
ssh+tee, 最简单的方法是执行ssh命令,然后通过这样的方法利用标准输入实现cat localfile | ssh remote_server tee serverfile。回忆一下,tee命令会将标准输出写入到一个文件;scp:当需要拷贝大量的文件或目录时,使用scp命令则更加方便,因为它可以方便的遍历相关路径。语法如下:scp path/to/local_file remote_host:path/to/remote_file;rsync对scp进行了改进,它可以检测本地和远端的文件以防止重复拷贝。它还可以提供一些诸如符号连接、权限管理等精心打磨的功能。甚至还可以基于--partial标记实现断点续传(课上展示了-avP参数)。rsync的语法和scp类似。
ssh的dotfile——config文件
我们每次进行ssh登录,都需要输入一长串的string……太麻烦了!
教案里面给出了一个很简单粗暴的方法:为它们创建一个alias。
alias my_server="ssh -i ~/.id_ed25519 --port 2222 -L 9999:localhost:8888 user_name@remote_server"
不过,更好的方法是使用dotfile。我们可以使用config文件,它的默认位置为~/.ssh/config,和.vimrc,.bashrc一样,它是属于ssh的dotfile。
# 这样登录只需要输入 ssh vm 就可以了
Host vm
User foobar
HostName 172.16.174.141
Port 2222
IdentityFile ~/.ssh/id_ed25519
LocalForward 9999 localhost:8888
# 在配置文件中也可以使用通配符
Host *.mit.edu
User foobaz
这么做的好处是,使用 ~/.ssh/config 文件来创建别名,类似 scp、rsync和mosh的这些命令都可以读取这个配置并将设置转换为对应的命令行选项。
教案的tips:
注意,
~/.ssh/config文件也可以被当作配置文件,而且一般情况下也是可以被导入其他配置文件的。不过,如果您将其公开到互联网上,那么其他人都将会看到您的服务器地址、用户名、开放端口等等。这些信息可能会帮助到那些企图攻击您系统的黑客,所以请务必三思。
端口转发
该节为教案内容,课程中并没有提及。
很多情况下我们都会遇到软件需要监听特定设备的端口。如果是在您的本机,可以使用 localhost:PORT 或 127.0.0.1:PORT。但是如果需要监听远程服务器的端口该如何操作呢?这种情况下远端的端口并不会直接通过网络暴露给您。
此时就需要进行 端口转发。端口转发有两种,一种是本地端口转发和远程端口转发(参见下图,该图片引用自这篇StackOverflow 文章)中的图片。
本地端口转发

远程端口转发

常见的情景是使用本地端口转发,即远端设备上的服务监听一个端口,而您希望在本地设备上的一个端口建立连接并转发到远程端口上。例如,我们在远端服务器上运行 Jupyter notebook 并监听 8888 端口。 然后,建立从本地端口 9999 的转发,使用 ssh -L 9999:localhost:8888 user_name@remote_server 。这样只需要访问本地的 localhost:9999 即可。
杂项
连接远程服务器的一个常见痛点是遇到由关机、休眠或网络环境变化导致的掉线。如果连接的延迟很高也很让人讨厌。Mosh(即 mobile shell )对 ssh 进行了改进,它允许连接漫游、间歇连接及智能本地回显。
有时将一个远端文件夹挂载到本地会比较方便, sshfs 可以将远端服务器上的一个文件夹挂载到本地,然后您就可以使用本地的编辑器了。(不过现在sshfs已经是一个orphaned的项目了……)
The Missing Semester - 第五讲 学习笔记(二)的更多相关文章
- The Missing Semester - 第一讲 学习笔记
The Missing Semester - 第一讲 学习笔记 第一讲 课程概览与 shell 课程视频地址: https://www.bilibili.com/video/BV1Eo4y1d7KZ/ ...
- The Missing Semester - 第二讲 学习笔记
第二讲 Shell 工具和脚本 课程视频地址: https://www.bilibili.com/video/BV1Vv411v7FR 本机学习使用平台:虚拟机ubuntu18.04.6 主题一:Sh ...
- The Missing Semester - 第三讲 学习笔记
第三讲 Vim 课程视频地址:https://www.bilibili.com/video/BV1Dy4y1a7BW 课程讲义地址:https://missing-semester-cn.github ...
- ES6学习笔记<二>arrow functions 箭头函数、template string、destructuring
接着上一篇的说. arrow functions 箭头函数 => 更便捷的函数声明 document.getElementById("click_1").onclick = ...
- WPF的Binding学习笔记(二)
原文: http://www.cnblogs.com/pasoraku/archive/2012/10/25/2738428.htmlWPF的Binding学习笔记(二) 上次学了点点Binding的 ...
- AJax 学习笔记二(onreadystatechange的作用)
AJax 学习笔记二(onreadystatechange的作用) 当发送一个请求后,客户端无法确定什么时候会完成这个请求,所以需要用事件机制来捕获请求的状态XMLHttpRequest对象提供了on ...
- [Firefly引擎][学习笔记二][已完结]卡牌游戏开发模型的设计
源地址:http://bbs.9miao.com/thread-44603-1-1.html 在此补充一下Socket的验证机制:socket登陆验证.会采用session会话超时的机制做心跳接口验证 ...
- JMX学习笔记(二)-Notification
Notification通知,也可理解为消息,有通知,必然有发送通知的广播,JMX这里采用了一种订阅的方式,类似于观察者模式,注册一个观察者到广播里,当有通知时,广播通过调用观察者,逐一通知. 这里写 ...
- java之jvm学习笔记二(类装载器的体系结构)
java的class只在需要的时候才内转载入内存,并由java虚拟机的执行引擎来执行,而执行引擎从总的来说主要的执行方式分为四种, 第一种,一次性解释代码,也就是当字节码转载到内存后,每次需要都会重新 ...
- Java IO学习笔记二
Java IO学习笔记二 流的概念 在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成. 程序中的输入输 ...
随机推荐
- ConcurrentHashMap是如何实现的?
众所周知 ConcurrentHashMap 是 HashMap 的多线程版本,HashMap 在并发操作时会有各种问题,比如死循环问题.数据覆盖等问题.而这些问题,只要使用 ConcurrentHa ...
- 自从用了 Kiali 以后才知道,配置 Istio 的 流量管理 是如此容易
在生产环境中,直接登录服务器是非常不方便的,我们可以使用Kiali配置Istio的流量管理. 本文以Istio官方提供的Bookinfo应用示例为例,使用Kiali配置Istio的流量管理.Booki ...
- 如何更快的烹饪出美味的MOJO系列教程🔥之初识MOJO
MOJO基础入门<概述> 一,什么叫TMD的MOJO Mojo是一种编程语言,它与Python一样易于使用,但具有C++和Rust的性能.此外,Mojo提供了利用整个Python库生态系统 ...
- tryhackme-OWASP
tryhackme-OWASP Top 10部分记录 敏感信息泄露 在assets目录中 可以看到到一个sqlite数据库的webapp.db文件 使用sqlite3 webapp.db .table ...
- hugp-MemE关键美化
配置front matter 使用vscode snippet快捷生成front matter 参考博客:vs-code-workflows-for-hugo. markdown-snippets-n ...
- Android string.xml与Excel的互相转换
Notice 使用以下脚本需要安装 openpyxl 和 lxml 两个库. string.xml转成Excel文件 """ 将 Android string.xml 文 ...
- S32DS---make: *** No rule to make target 'clean'. Stop和make: *** No rule to make target 'all'. Stop的一个解决方法
问题: 最近在用S32DS调试代码的时候,遇到一个稀奇古怪的问题: and 折腾了半天,发现从这个页面导入工程编译就不会出现这个问题???? file-->import projects fro ...
- 驱动开发:内核RIP劫持实现DLL注入
本章将探索内核级DLL模块注入实现原理,DLL模块注入在应用层中通常会使用CreateRemoteThread直接开启远程线程执行即可,驱动级别的注入有多种实现原理,而其中最简单的一种实现方式则是通过 ...
- 当使用POI打开Excel文件遇到out of memory时该如何处理?
摘要:本文由葡萄城技术团队于博客园原创并首发.转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 当我们开发处理Excel文件时,Apache POI 是许多人 ...
- 探秘高逼格艺术二维码的制作过程-AI绘画文生图
前几天看到几个逼格比较高的二维码,然后自己动手做了一下,给大家看看效果: 1.文生图(狮子): 2.文生图(城市): 下边将开始介绍怎么做的,有兴趣的可以继续读一读. 这里使用的AI绘图工具是Stab ...