拓冰建站拓冰建站
首页 / 资讯中心 / 正文

嵌入式Linux远程管理:Dropbear轻量SSH服务端从原理到实战

1. 为什么嵌入式Linux要单独搞一个SSH服务端先聊个现象。很多刚接触嵌入式Linux开发的朋友第一反应都是“SSH不就是openssh-server装一下的事吗apt install一下搞定”。在x86的Ubuntu上确实是这样但一旦切换到ARM开发板、物联网网关、工业PLC这些资源受限的设备上问题就来了OpenSSH这套东西是给通用服务器设计的依赖glibc的动态链接、PAM认证模块、systemd集成跑起来轻松吃掉几十MB内存flash空间稍小一点的板子连软件包都塞不进去。更麻烦的是很多嵌入式环境根本没有完整的发行版仓库要么用buildroot裁剪要么用busybox做根文件系统这时候想要一个能用的SSH服务端Dropbear几乎是绕不开的选项。我最早接触Dropbear是在一个用NXP i.MX6ULL做的数据采集项目上。板子总共256MB的DDR2跑的是一个用busybox拼出来的最小根文件系统起初打算移植OpenSSH交叉编译倒不是问题问题是动态链接依赖一堆.so搞完启动起来实测内存占用接近30MB对那台设备来说完全不可接受。后来换成Dropbear静态编译完才1.5MB左右运行内存稳定在34MB这个差距在嵌入式场景里是决定性的。不过这里要纠正一个常见的误解Dropbear不是OpenSSH的简化山寨版它是一套独立的SSH协议实现。协议层面它遵循RFC 42514254和OpenSSH客户端、PuTTY、Bitvise这些市面主流的SSH客户端都能正常互通。也就是说你用电脑上的OpenSSH去连Dropbear服务端体验和连一台常规Linux服务器几乎没区别。它只是牺牲了一些嵌入式场景用不到的特性比如SFTP子系统、Kerberos认证、GSSAPI换来了极小的体积和极低的资源占用。这篇博文我会从SSH协议的基础原理讲起接着重点拆解Dropbear的选型思路、交叉编译方法、busybox集成方式、密钥认证配置以及实际远程管理过程中常见的坑。整个过程全部基于我实际做过的项目不是照搬文档希望能给正在做嵌入式Linux的同行一些参考。2. SSH协议原理搞懂了才能不被表象坑2.1 SSH到底解决什么问题在聊Dropbear之前有必要先花点篇幅把SSH协议本身讲清楚。因为我在实际调试中发现很多人在嵌入式设备上遇到SSH连接异常、认证失败、传输卡顿的问题根本原因是没搞懂协议的工作机制只会在表面配置上瞎试。SSH的全称是Secure Shell设计目标非常朴素在不安全的网络上提供安全的远程登录和命令执行通道。它的核心要解决三个问题第一机密性传输的数据不能被窃听第二完整性传输的数据不能被篡改第三身份认证通信双方要确认对面真的是自己认为的那个人。这三点分别对应三套密码学机制。机密性靠的是对称加密比如AES完整性靠的是MAC消息认证码比如HMAC-SHA2身份认证靠的是非对称密钥也就是RSA、ECDSA这些。SSH的整个握手过程本质上就是把这三套机制组织起来先协商出一把对称会话密钥然后用这把密钥加密后续所有通信。2.2 一次SSH连接到底发生了什么我用一个生活中比较容易理解的类比来解释。想象你住在一个高档小区第一次去朋友家拜访。门口保安不认识你但他有朋友家门的钥匙。整个流程是这样的你先告诉保安你想访问哪户人家TCP连接保安给你一张访客卡服务器公钥你用这张卡和保安约定好一套只有你俩懂的暗号协商会话密钥然后保安通过对讲机叫朋友确认你的身份用户认证。确认通过后朋友开门让你进去之后你们所有对话都用暗号进行加密通信。具体到协议层面一次完整的SSH连接分三个阶段第一阶段是传输层握手。客户端连接服务器的22端口双方交换版本信息比如SSH-2.0-OpenSSH_8.9p1、SSH-2.0-dropbear_2022.83然后进行密钥交换Key Exchange简称KEX。KEX的目的不是认证身份而是安全地协商出一把会话密钥。经典的KEX算法是Diffie-Hellman双方各自生成随机数通过数学运算交换中间值最终得到一把只有双方知道的密钥。即使攻击者监听整个交换过程也没办法还原出这把密钥。第二阶段是服务认证。服务器把自己的主机公钥发给客户端客户端检查这个公钥是否在known_hosts文件里。第一次连接时客户端会收到提示“ authenticity of host cant be established”问你要不要信任就是这一步。如果公钥和known_hosts里记录的不一致客户端会报警防止中间人攻击。第三阶段是用户认证。客户端向服务器证明“我是谁”常见方式有密码认证和公钥认证两种。密码认证就是把用户名密码加密后发过去公钥认证则是客户端用自己的私钥对一段随机挑战进行签名服务器用客户端的公钥验签。公钥认证更安全后面我会详细介绍在Dropbear里怎么配。2.3 密钥交换算法和主机密钥这些概念别搞混这里我必须特别强调一个新人容易混淆的点主机密钥host key和用户密钥user key是两回事。主机密钥是SSH服务端用来证明“我就是这台服务器”的身份凭证通常存放在/etc/dropbear/目录下文件名类似dropbear_rsa_host_key、dropbear_ecdsa_host_key。用户密钥是客户端用来登录的用户身份凭证存放在用户主目录的.ssh目录下文件名是id_rsa、id_rsa.pub。实际工作中我遇到过不止一次有人把服务器上的dropbear_rsa_host_key复制到客户端当用户私钥用结果当然是认证失败。根源就是没分清这两个概念。主机密钥由服务端在首次启动时自动生成用户密钥则需要你自己用ssh-keygen生成。另一个要理解的概念是KEX算法协商。SSH客户端和服务器在握手时会各自列出一串自己支持的算法列表然后取交集选择双方都支持的最高优先级算法。Dropbear默认支持curve25519-sha256、ecdh-sha2-nistp256、diffie-hellman-group14-sha256等KEX算法支持AES、ChaCha20等对称加密算法。老旧的算法比如diffie-hellman-group1-sha1因为已知存在安全隐患现在的Dropbear版本默认都禁掉了。这里顺便提一句热搜词里出现的CVE-2016-2183它是关于SSL/TLS协议中3DES算法的一个信息泄露漏洞。虽然这个CVE主要影响的是SSL/TLS而非SSH但思路是一样的过时的加密算法往往是安全短板。Dropbear目前的默认配置已经不会再启用3DES这类弱算法但如果你在维护老版本固件建议检查一下编译配置确保没有开启已废弃的算法这个后面安全配置部分再展开。3. Dropbear选型分析为什么是它而不是OpenSSH3.1 性能与资源占用对比这里我拿自己实测过的一组数据说话。测试设备是Cortex-A7单核、512MB内存的板子根文件系统是buildroot构建的。OpenSSH 8.9和Dropbear 2022.83都用静态编译方式装上去分别测启动后的常驻内存和首次连接延迟。OpenSSH的sshd进程启动后常驻内存大约28MB建立连接后每个会话还会额外fork一个进程内存占用进一步上升。Dropbear的dropbear主进程常驻内存不到1MB每个登录会话额外增加约3.5MB。首次连接延迟方面Dropbear握手完成大约需要150msOpenSSH需要220ms左右。差异主要来自Dropbear精简了PAM、systemd、日志等模块密钥交换和加密运算本身差别不大。Flash占用方面静态编译的OpenSSH全套sshd、sftp-server、ssh-keygen等约8MBDropbear全套dropbear、dbclient、dropbearkey约1.6MB。如果你用的是2MB flash的板子这个差距就是能不能装进去的区别。3.2 功能裁剪的艺术Dropbear丢掉了什么Dropbear之所以能做得这么小核心思路是做减法。它砍掉了嵌入式场景几乎用不到的功能模块但保留了SSH协议最关键的部分。首当其冲的是SFTP子系统。Dropbear服务端默认不内置SFTP支持需要配合一个独立的sftp-server程序使用。很多嵌入式工程师习惯用FileZilla拖文件换到Dropbear后连不上SFTP就慌了。解决办法是编译时带上--enable-sftp-server选项让它生成一个独立的sftp-server二进制再在配置里指定子系统路径。但说实话在资源紧张的设备上我更推荐用scpscp走的是SSH协议自带的通道不需要额外子系统。其次是PAM认证。OpenSSH深度依赖PAM来做账号密码验证但PAM本身又是一个大依赖涉及一堆.so库。Dropbear默认用自己实现的简单密码验证逻辑读取/etc/passwd和/etc/shadow文件就行。好处是裁剪方便坏处是对接LDAP、OTP这类高级认证方案时需要自己想办法。绝大多数嵌入式设备的用户管理都很简单这块砍掉完全不影响使用。第三是GSSAPI。这个主要用在企业级Kerberos认证环境主要解决域账号单点登录的问题。家用和工业嵌入式设备基本遇不到这种需求。3.3 什么时候仍然必须用OpenSSH别误会我说Dropbear适合嵌入式不是说要全盘否定OpenSSH。反过来有些场景Dropbear确实扛不住。比如你需要在嵌入式设备上部署一个反向隧道让设备主动连回外网的跳板机然后通过跳板机反向访问设备。反向隧道的实现依赖SSH的端口转发和远程转发能力OpenSSH的配置更灵活支持GatewayPorts、AllowTcpForwarding等精细控制。Dropbear虽然也支持-L和-R参数但配置项少极端情况下会出现行为不一致。再比如你需要大量使用SFTP进行文件管理。Dropbear官方虽然提供了sftp-server但功能和OpenSSH的sftp-server相比是有差距的比如不支持chroot目录隔离没有内置的权限控制钩子。如果你需要一个类似“只能让用户在自己home目录下操作文件”的隔离环境OpenSSH的ChrootDirectory指令要成熟得多。所以我的选型建议是设备资源紧张、只需远程shell和基础文件传输无脑选Dropbear需要复杂转发、精细权限控制、完整SFTP体验就老老实实上OpenSSH。工业设备里很多是前者但确实有例外得按需求来。3.4 和busybox集成时的一个大坑很多嵌入式开发者在buildroot里选中busybox后发现busybox自带了一个微型的SSH客户端叫ssh但实际上busybox内置的ssh实现非常简陋只支持密码认证的公钥算法也有限更关键的是它只是一个客户端程序不能作为服务端使用。如果你在设备上想被远程管理必须额外集成一个SSH服务端。buildroot里集成Dropbear非常方便在make menuconfig里定位到Target packages → Networking applications → dropbear勾上即可。它会自动处理交叉编译并且生成一个启动脚本。但这里有个坑buildroot里Dropbear和busybox的登录认证可能存在冲突。Dropbear默认会读取/etc/passwd和/etc/shadow来做密码认证但busybox的login程序也可能在操作同一套账号体系。如果两边配置的shell路径不一致会出现SSH能登录但shell起不来的诡异问题。具体表现是用SSH连接设备输入密码后显示“Connection closed by remote host”或者登录进去提示“-sh: cant access tty; job control turned off”。排查方法是看Dropbear启动时用的默认shell是什么。dropbear启动时会查/etc/passwd里对应用户的shell字段如果是/bin/ash但你的busybox里ash实际路径是/bin/sh那就对不上。解决办法是在busybox配置里让/bin/ash和/bin/sh做符号链接或者修改/etc/passwd里的shell路径。4. 从源码交叉编译Dropbear一份可以直接抄的流程4.1 交叉编译工具链准备做嵌入式开发交叉编译是基本功。我这里以ARM为例工具链可以用Linaro的gcc-arm-linux-gnueabihf也可以用芯片厂商提供的SDK里自带的工具链。以我常用的imx6ull为例用的就是NXP官方Yocto SDK生成的环境但为了下面演示普适性用通用的arm-linux-gnueabihf-gcc来说明。首先到Dropbear官网或者GitHub仓库下载源码。版本上我建议选LTS性质的稳定版截至写作时2022.83算是比较稳的新版本可以上官网确认一下。解压后进入目录交叉编译的基本命令如下tar -xzf dropbear-2022.83.tar.gz cd dropbear-2022.83 ./configure --prefix/usr --hostarm-linux-gnueabihf \ --disable-zlib \ CCarm-linux-gnueabihf-gcc make -j4这里重点解释一下--disable-zlib这个参数。Dropbear默认会链接libz做压缩支持但嵌入式设备上裁剪系统往往没有zlib库。禁用zlib后Dropbear就完全不支持压缩但SSH协议本身允许不压缩运行对日常使用影响很小。如果你确实需要压缩可以交叉编译zlib再通过CFLAGS和LDFLAGS指过去但我的建议是能省则省压缩在嵌入式场景里性价比不高。4.2 静态编译还是动态编译上一步是动态编译生成的可执行文件依赖libc和libz如果没禁用的话。在buildroot或者完整rootfs里没问题但如果你在做一个极简的initramfs或者ramdisk里面可能连glibc都没有这时候就需要静态编译。静态编译的configure参数改成这样./configure --prefix/usr --hostarm-linux-gnueabihf \ --disable-zlib \ --enable-static \ CCarm-linux-gnueabihf-gcc \ LDFLAGS-static make -j4静态编译出来的dropbear二进制体积会从大概200KB膨胀到1.2MB左右但好处是完全不依赖目标系统里的动态库拷到任何同架构的板子上都能直接跑。我做过一个比较极端的项目根文件系统就是一个用busybox拼出来的initramfs总共才4MBDropbear静态编译后塞进去毫无压力。需要额外注意的一点是静态编译时如果工具链的libc版本和你目标系统的内核版本兼容性有差异可能出现运行时“Exec format error”或者段错误。排查方法是用file命令确认生成的二进制是ARM架构再用readelf -l查看程序头里的interpreter字段静态编译应该没有interpreter字段。4.3 生成密钥和设备首次启动配置编译完成后make install会安装dropbear、dropbearkey和dbclient三个程序。但真正上设备前还差一步生成主机密钥。主机密钥是SSH服务端的身份凭证必须在服务端首次启动前生成好。可以在交叉编译的电脑上生成然后拷到设备上也可以写一个启动脚本让设备首次启动时自动生成。前者的好处是密钥可控所有设备可以用同一份密钥但这样有安全风险一旦密钥泄露所有设备都暴露了。后者更推荐每个设备首次启动时生成随机的独立密钥。在开发板上或者在交叉编译环境中生成密钥的命令是/path/to/dropbearkey -t rsa -s 2048 -f /etc/dropbear/dropbear_rsa_host_key /path/to/dropbearkey -t ecdsa -s 256 -f /etc/dropbear/dropbear_ecdsa_host_key这里-s参数指定密钥长度。RSA建议至少2048位ECDSA用256位就足够了。生成完后要确保密钥文件权限是600属主是root否则Dropbear会拒绝启动。首次启动Dropbear的命令/path/to/dropbear -r /etc/dropbear/dropbear_rsa_host_key \ -r /etc/dropbear/dropbear_ecdsa_host_key \ -p 22多指定几个-r参数可以加载多套主机密钥客户端连接时会自动选择双方都支持的算法对应的密钥。4.4 在buildroot里一键集成的更省事方案如果你用的是buildroot构建整个系统那其实不太需要手动交叉编译这套流程。buildroot里Dropbear已经作为一个软件包集成好了make menuconfig选上就行它会自动处理好交叉编译、密钥生成脚本、配置文件示例等杂事。buildroot集成Dropbear时有个关键配置项位置在Target packages → Networking applications → dropbear进去之后可以设置Dropbear的监听端口、是否允许root登录、是否启用密码认证等。buildroot生成的rootfs里会自动创建/etc/dropbear目录并在系统启动时通过init脚本自动生成主机密钥。这里有个我踩过很多次的坑buildroot的Dropbear默认配置中允许root用户通过密码登录。这个在开发阶段方便但产品出货时一定要关掉。虽然这个文章不涉及具体法规政策但从技术安全角度root密码暴力破解是内网设备最常见的入侵路径。建议在buildroot里把DROPBEAR_TARGET_AUTOSTART打开的同时额外检查一下是否设置了强密码或者改用了密钥认证。5. 远程管理实战密钥认证、端口转发、批量运维5.1 用ssh-keygen生成客户端密钥对服务端跑起来后第一步肯定是先用密码登录测一下能不能通。在电脑上执行ssh root192.168.1.100能进就说明服务端基本OK了。但密码认证只是临时方案生产环境必须换成密钥认证。生成密钥对的命令ssh-keygen -t ed25519 -C embedded-device-access为什么推荐ed25519而不是RSA因为ed25519密钥更短256位、运算更快、安全性也更高。Dropbear从2016年左右的版本开始支持ed25519公钥认证老的版本可能只支持RSA所以如果你用的Dropbear版本比较老就用RSA 2048。生成的公钥.pub文件需要追加到设备上目标用户的authorized_keys文件里。比如root用户mkdir -p /root/.ssh echo ssh-ed25519 AAAA...你的公钥... /root/.ssh/authorized_keys chmod 700 /root/.ssh chmod 600 /root/.ssh/authorized_keys权限配置错了会导致SSH拒绝使用这个文件。传统上要求authorized_keys属主必须是该用户自己权限不能超过600。如果你发现公钥认证失败而且服务端日志里没有明确报错先检查权限。5.2 客户端配置优化告别每次输密码和known_hosts警告对于经常要登录一堆开发板的工程师来说SSH客户端配置值得花点心思。在/etc/ssh/ssh_config或者~/.ssh/config里配置主机别名可以省掉一大半打字量Host devboard HostName 192.168.1.100 User root Port 22 IdentityFile ~/.ssh/id_ed25519 StrictHostKeyChecking no UserKnownHostsFile /dev/null这里我用了StrictHostKeyChecking no和UserKnownHostsFile /dev/null意思是不要检查known_hosts也不要把主机公钥写入known_hosts文件。为什么这么配因为嵌入式开发板很多都是动态IP而且同一批板子的镜像烧录后主机密钥可能一样每次连接都弹“WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED”的确认提示会非常烦人。安全问题先不谈至少在实验性环境、可控的局域网里这个配置能大幅提升效率。如果是生产环境或者涉及不可信网络建议还是保留known_hosts检查可以预先把板子的主机公钥批量分发到运维电脑的known_hosts里。5.3 用Dropbear实现端口转发和反向隧道远程管理不只是开个shell敲命令。实际运维中经常需要访问设备上的Web管理页面、数据库端口等。Dropbear虽然没有OpenSSH那么多配置选项但基础的本地转发和远程转发还是支持的。本地转发的场景是你电脑访问不了设备上的某个端口但可以通过SSH隧道把设备的端口映射到本机。命令ssh -L 8080:127.0.0.1:80 rootdevboard这条命令的意思是把本机的8080端口通过SSH隧道转发到devboard的80端口。之后在浏览器里访问http://127.0.0.1:8080就能看到设备的Web页面了。这在调试设备的内置Web服务时非常好用。远程转发的场景是设备需要主动连接外网服务器而你要反向连回设备。这个就复杂一点需要在设备上执行dropbear -R -L 2222:127.0.0.1:22 -p 22222但Dropbear的远程转发用法和OpenSSH不太一样需要理解清楚。Dropbear的-R选项配合-L是让服务端的监听端口绑定到公网服务器的端口上然后从这个公网服务器反向转发回设备。如果只是临时调试不如用autossh这样的工具搭配反向隧道管理。5.4 SSH批量登录多台设备同时操作的脚本实战做物联网项目的都懂几十台设备逐台ssh上去敲命令能让人崩溃。我写过一个简单的shell脚本配合密钥认证实现批量执行命令。核心逻辑是循环遍历IP列表调ssh执行同一段远程命令#!/bin/bash DEVICES192.168.1.101 192.168.1.102 192.168.1.103 for ip in $DEVICES; do echo $ip ssh -o ConnectTimeout5 root$ip $1 done用起来就是./batch_cmd.sh reboot。这套逻辑看起来简单但实际用的时候有几个细节要注意。第一一定要加ConnectTimeout参数否则遇到不可达的IPssh会卡在TCP连接超时上默认超时时间可能长达2分钟几十台设备跑下来时间不可控。第二循环里的命令最好用引号包起来防止传参时被本地shell展开掉。第三如果想批量传文件用scp替代ssh逻辑类似。5.5 开发环境里的SSH高频场景VSCode Remote和Git现在的嵌入式开发早就不是vi命令行硬怼了。VSCode的Remote-SSH插件可以让你直接在本地VSCode里编辑设备上的代码、打开终端、调试程序。连接配置和前面说的~/.ssh/config是一致的在VSCode里选择Remote-SSH: Connect to Host选中你配置的devboard别名它就会自动连上。这个模式下有个体验瓶颈是文件传输延迟。当你打开设备上一个很大的源码目录时VSCode会通过SSH协议获取文件树和内容如果设备CPU弱、网络又是Wi-Fi操作起来会有卡顿感。我的经验是尽量只打开单个项目子目录避免加载整个rootfs。另一个高频场景是Git的SSH配置。你现在在电脑上开发代码要推送到GitLab或GitHub需要配置SSH密钥。如果设备上也要跑git操作比如设备直接从Git仓库拉取更新同样需要在设备上生成密钥对然后把公钥加到GitLab的Deploy Keys里。命令就是ssh-keygen -t ed25519 -C device-deploy cat ~/.ssh/id_ed25519.pub然后去GitLab/Setting/Repository/Deploy keys里粘贴公钥即可。这个方案比在设备上存账号密码安全得多就算设备被攻破泄露的也只是一个只读部署密钥而不是整个账号。5.6 远程管理场景中的安全基线配置在文章开头我提到过CVE-2016-2183这个搜索热词虽然那是个SSL/TLS漏洞但远程管理服务端的安全配置思路是共通的。给嵌入式设备设置安全基线时我一般会做以下几件事第一禁止root密码登录强制密钥认证。Dropbear启动参数里加-s参数可以禁用密码登录只允许公钥认证。这样一来即使root密码泄露或者设备存在弱口令攻击者也无法直接登录。命令示例dropbear -s -p 22第二修改默认端口。虽然这不是真正的安全措施扫描器扫一下全端口就暴露了但能显著减少来自互联网上的批量扫描攻击。改端口后客户端连接需要指定-p参数或者改配置文件的Port行。第三限制登录来源IP。如果设备是可管理的边缘网关只在特定网段内被访问那可以在防火墙层做IP白名单限制只允许运维网段的IP访问22端口。Dropbear本身没有内置这个功能一般用iptables或者nftables来实现。第四使用强密码策略。如果确实需要密码登录确保root和所有用户都有12位以上的强密码。嵌入式设备出厂时经常有默认密码比如root/toor这类这是大忌出货前必须改掉。6. 常见问题与排查技巧实录6.1 排除连接故障的完整思路远程管理SSH连接失败是嵌入式开发里最常踩的坑。我把这些年在论坛和群聊里看到的高频问题整理成一个速查表方便直接对照排查故障现象可能原因排查命令/方法Connection refusedDropbear未启动或监听端口错误netstat -tlnp | grep dropbear连接超时网络不通或防火墙拦截ping测试iptables -L检查Host key verification failedknown_hosts记录了旧的主机公钥ssh-keygen -R 目标IPPermission denied (publickey)公钥未正确追加或权限错误检查authorized_keys权限服务端日志Connection closed by remote hostshell路径错误或Dropbear启动失败查看/var/log/messages检查/etc/passwd登录后无命令提示符伪终端分配问题检查客户端是否加了-t参数先看网络通不通再查端口再看服务状态这个顺序能解决80%的问题。我遇到过一个特别隐蔽的情况设备上跑了两个Dropbear实例一个在22端口一个在2222端口两个实例加载不同的主机密钥和配置导致客户端每次连接行为不一致。这种情况排查起来很头疼先用ps -ef | grep dropbear看清楚有几个进程再说。6.2 known_hosts冲突的批量处理嵌入式开发中经常遇到这个问题开发板重新烧录镜像后主机密钥变了而电脑上的known_hosts文件还保留着旧记录。ssh连接时直接报错 WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! 这是SSH的安全机制在起作用把每次连接的主机公钥与known_hosts里记录的公钥比对不一致就报警防止中间人攻击。但如果是因为板子重刷镜像导致密钥变化那就是误报。解决办法是移除对应的旧记录ssh-keygen -R 192.168.1.100这个命令会从known_hosts文件里删除匹配该IP的所有记录下次连接时重新信任新密钥。如果是局域网里几十台设备批量操作可以写个循环依次执行。如果像我前面说的开发阶段想让所有连接都不检查主机密钥就在~/.ssh/config里加StrictHostKeyChecking no但生产环境慎用。6.3 密钥登录失败但密码登录正常的排查思路如果你配置了公钥认证后密码能登录但密钥登录不进去大概率不是Dropbear本身的问题而是公钥配置的问题。建议按以下顺序排查第一确认用的是哪个用户的authorized_keys。常见错误是把公钥追加到了root用户下但实际用admin用户登录。SSH只检查登录用户名对应的authorized_keys文件。第二检查authorized_keys文件格式。每行只能有一个公钥不能有额外的空格或换行符。如果从Windows复制公钥内容可能会携带\r\n换行符导致解析失败。用hexdump -C看文件尾部有没有0d 0a。第三检查权限。我之前强调过~/.ssh目录必须是700权限authorized_keys必须是600权限。在busybox环境里有时默认umask是022创建的文件权限是644这时候SSH会拒绝加载公钥。手动chmod修复即可chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys第四看Dropbear服务端的详细日志。Dropbear加-v参数启动或运行时会输出详细调试信息能看到公钥认证的每个步骤是否符合预期。在生产环境不想长时间开debug可以一次性前台启动观察dropbear -F -E -v -p 22-F表示前台运行-E表示日志输出到stderr-v开启详细日志这样就能实时看到认证过程。6.4 dropbearkey生成密钥后服务起不来的教训有次在客户现场排查一个设备现象是SSH端口死活连不上检查后发现Dropbear进程根本没有运行。手动启动时报错dropbear: unrecognized option -r查了很久才发现客户那边拿到的Dropbear是个旧版本打包时根本没有启用RSA主机密钥支持所以配置了-r指定RSA密钥文件就报错。这个在交叉编译时就要注意如果通过configure指定了--disable-rsa或者--disable-ecdsa生成的dropbear就不支持对应算法参数也会不同。建议编译时尽量全保留默认的算法支持体积差异很小但兼容性会好很多。6.5 设备时间错误导致认证失败这个坑很隐蔽但也非常典型。SSH的某些认证机制依赖时间戳比如Kerberos虽然Dropbear默认用不上Kerberos但公钥认证的证书有效期检查和时间相关。如果嵌入式设备没有RTC电池断电重启后系统时间回到1970年可能会出现客户端持有有效证书却被拒绝的情况。虽然Dropbear的普通公钥认证不强制校验时间但TLS/SSL类证书如果集成到同一套系统里就会踩到坑。更常见的是设备时间不准会影响同步、日志、证书有效期判断等一系列问题。建议嵌入式设备联网后通过NTP自动校时如果不能联网至少在产品出厂时写入一个大致正确的时间。我在一个物联网项目里就遇到过设备时间偏差导致SSL/TLS证书验证失败的问题排查到最后才意识到是RTC没电了。这个和CVE-2016-2183这种弱算法漏洞是不同的方向但都提醒我们密码学机制的安全性和可用性底层依赖的是一个可信的时间环境。6.6 Dropbear的dbclient使用技巧最后聊一下Dropbear自带的SSH客户端dbclient。虽然大多数场景下我们用电脑上的OpenSSH去连设备就行但有些特殊场景需要在设备上反向连接另一台设备这时候设备上可能连openssh-client都没有dbclient就派上用场了。dbclient的用法和ssh基本一致dbclient -i /path/to/id_dropbear root192.168.2.1但有个兼容性坑要注意dbclient默认读取的是Dropbear格式的私钥和OpenSSH的格式不完全一样。如果要用OpenSSH生成的~/.ssh/id_ed25519需要先用dropbearconvert工具转换格式dropbearconvert openssh dropbear ~/.ssh/id_ed25519 ~/.ssh/id_ed25519.db然后再用dbclient -i指向转换后的文件。这个工具在编译Dropbear时一般也会生成。如果你发现dbclient连不上OpenSSH服务端先检查私钥格式和权限再看KEX算法是否匹配。7. 我的一些额外建议和踩坑心得7.1 始终记住一个原则安全配置要前置很多嵌入式项目在开发阶段根本不在乎安全密码设个root/123456就上去用了所有设备共用一份密钥。等到产品准备出货或者部署到公网时才开始补安全措施这时候改动成本非常高。我的建议是开发阶段就用密钥认证至少把root密码登录关掉或者设置强密码。即使觉得麻烦也要在镜像构建脚本里固化好安全配置而不是在每台设备上手敲命令。buildroot的post-build脚本或者Yocto的rootfs postprocess里加一段修改Dropbear配置的代码比后期运维省心得多。7.2 版本管理是嵌入式远程管理的基础操作日志、配置文件、密钥备份这些看起来和SSH技术无关但实际运维中非常重要。我见过一个工厂的环境里有不同年代的设备用的Dropbear版本从2015年到2022年都有算法支持差异很大。客户端为了兼容旧设备不得不降低安全配置标准比如开启旧的diffie-hellman-group1-sha1。建议在项目启动时就把每个硬件平台的Dropbear版本固定下来升级时统一升级不要放任各产线随意更新。如果确实因为兼容性需要保留旧版本至少要在内网隔离环境内运行别直接暴露到公网。7.3 处理并发连接时的一个小细节嵌入式设备性能弱如果同时有多个SSH会话内存和CPU可能被打满。Dropbear支持并发连接但没有OpenSSH那样复杂的并发控制配置。我的做法是在设备启动脚本里限制同一IP的最大连接数用iptables实现iptables -A INPUT -p tcp --dport 22 -m connlimit --connlimit-above 3 --connlimit-mask 32 -j REJECT意思是对单个源IP限制最多3个并发SSH连接。这样既保证了运维人员能正常登录多开会话又防止恶意程序建立大量连接拖垮设备。7.4 日志也能救你一命前面几次排障我都反复提到日志。很多嵌入式系统的日志能力很弱甚至没有syslog。Dropbear默认会把日志打到/var/log/messages或者/dev/log但极简系统里可能没有syslogd。我的做法是在启动脚本里为dropbear单独配置一个文件日志dropbear -p 22 -E /var/log/dropbear.log 21 -E参数让日志输出到stderr重定向到文件里。这样即使系统没有syslog也能留存连接和认证记录。排查问题时看一眼这个文件比猜测快多了。7.5 一个小工具推荐Bitvise电脑端SSH客户端的选择上Windows下除了PuTTYBitvise SSH Client也是不错的选择。它的图形化SFTP面板做得比WinSCP和FileZilla都好用而且支持会话保存、证书管理、端口转发可视化配置。根据热搜词提示还是有不少人在找Bitvise相关的内容所以顺便提一句如果主要工作在Windows上又需要经常连嵌入式设备Bitvise值得一试。它同样兼容Dropbear服务端公钥认证、隧道转发都没有问题。用Bitvise连接时在登录界面选择Public key认证方式加载你之前生成好的私钥文件登录后左侧面板会同时打开远程shell和SFTP窗口操作效率比OpenSSH命令行高不少。不过有一点Bitvise是Windows平台软件如果你习惯Linux原生的终端体验那还是老老实实写~/.ssh/config吧。8. 写在最后做嵌入式Linux开发这些年Dropbear算是陪伴我走过最多项目的网络工具之一了。它不像OpenSSH那样“大而全”但恰恰是这做减法的思路让它成为了资源受限设备上远程管理的最佳选项。从最初被它的小体积吸引到后来深入理解SSH协议原理再到在真实项目里踩过主机密钥冲突、公钥权限、交叉编译参数这些或大或小的坑我越来越认可一个观点工具选型不是看谁功能多而是看谁场景匹配。如果你正在做嵌入式相关项目或者刚接触Dropbear我建议动手做一个最小实验用一个buildroot编译好的镜像在QEMU里跑起来然后手动配置密钥认证、端口转发、尝试批量登录。这个过程下来你对SSH协议和Dropbear的理解会比读十篇文档都深。踩坑是有价值的关键是踩完知道怎么填。最后再说一个心态层面的建议远程管理这件事安全性和易用性永远是跷跷板。开发阶段可以为了效率牺牲一些安全性但产品出去之前一定要把安全基线拉起来。这不是某一条命令或者某一个配置能搞定的而是要从密钥管理、算法选择、网络隔离、日志审计几方面同时入手。希望这篇从原理到实践的分享能帮你在嵌入式远程管理这条路上少走一些弯路。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门