组件选型
组件 | 说明 |
---|---|
sftp-client lib | 依赖ssl crypto 等加密库 |
scp shell | 仅与系统shell相关 |
以前曾经论述过,如果我们借用一些开源组件,应(Should
)尽量使用依赖库少的;而对于存在依赖库,而依赖又是加密相关的库,则更是要慎之又慎之。
加密库,不同于libc
库,库API在版本间变化比较大,而且经常存在兼容性问题。
所以,在引用sftp-client
库进行客户端和服务器间的文件拷贝时,特别在非性能相关的场景,我的建议是使用更简单的scp shell
命令进行替代!
使用scp首先遭遇的问题
用scp
替换第一个遇到的问题,就是对于命令调用中密码的输入问题。
- 笔者粗略研究了下免密的处理
当然,这里最安全的免密做法,是通过ssh-keygen
和ssh-copy-id
的命令族进行配置非对称加密证书。
次之,则选用sshpass
或expect
组件,进行免交互处理。
但是,按照前面所述的原则,因为expect
组件的依赖众多,虽然expect
是一个更通用的免交互输入框架,但是,对于我们所要替代的sftp-client
组件使用场景,优势没有那么大。
部分shell命令区分从标准输入获取参数和命令参数
- 部分命令可以从标准输入获取参数,以及区分和从命令中获取参数,例如,
here document
和here string
语法。
sshpass研究
此组件相对较小,源码仅main.c
一个源文件,也没有杂七杂八的依赖。
ssh
和scp
命令即使你通过exec
提前替换了标准输入,两个命令依然倔强地
向终端设备输出密码输入提示。
通过,阅读sshpass
的源码,你就知道sshpass
规避的办法,就是自身创建伪终端进行环境模拟
ssh之scp模式
由于scp
命令,并不能够拿标准输入作为输入源,所以,在客户端和服务器间的文件拷贝,实际上利用到的是ssh
命令的scp
模式
# 简洁
ssh root@remote "cat > remotefile" < localfile
# 另外一种语法
cat localfile | ssh root@remote "cat > remotefile"
# 中间文件方式
tar cvf local.tar.gz fileOrDir [...] && scp local.tar.gz root@remote:/path/to/dir/remotefile.tar.gz
免压缩中间文件远程拷贝
# 将文件压缩结果导向标准输出
tar czf - fileOrDir [...] | ssh root@remote:/path/to/dir "cat > remotefile.tar.gz"
scp的运行栈研究
如果通过pstree
观察scp
在提示输入密码时的进程树结构,实际上scp
底层继续调用了ssh
命令,非常有意思