
搞嵌入式的都懂这个场景板子已经焊进机柜了现场连个显示器都没有改一个配置参数要背着调试线跑几十公里。给设备加个SSH服务是刚需但真拿OpenSSH去移植的时候又会被体积和依赖劝退——OpenSSH背后挂着OpenSSL、PAM、Kerberos一堆库静态编译出来轻松破4MB对动不动只有16MB Flash的嵌入式Linux设备实在太奢侈。Dropbear就是来解决这个问题的一个目标就是把SSH服务器压缩到KB级别同时保持OpenSSH客户端的兼容性让PC上用Putty、Xshell、Bitvise或者命令行ssh都能直接连进去。这篇文章我会把Dropbear从协议裁剪逻辑、交叉编译、rootfs集成到日常远程运维的完整链路拆开讲一遍适合正在给嵌入式Linux设备加远程管理能力又不想被OpenSSH体积逼疯的开发者和系统集成工程师。1. 为什么嵌入式Linux项目普遍用Dropbear而不是OpenSSH1.1 资源占用这笔账越早算越省事很多刚开始做嵌入式Linux的人第一反应是“OpenSSH不是现成的吗直接编译进去不就行了”。真动起手来就不是那么回事了。OpenSSH为了保证桌面和服务器场景的功能完整代码里塞了大量嵌入式设备根本用不上的特性GSSAPI认证、Kerberos票据、PAM可插拔认证、SFTP子系统、X11转发、多种报文压缩算法……每一项特性背后都是一坨代码和动态库依赖。我们实测过一个常见组合OpenSSH 9.x静态编译加上libcrypto、libssl、libz这些依赖ssh、sshd、sftp-server三个二进制放一起体积轻松超过4MB运行起来RSS内存占用在3MB到6MB之间浮动。而Dropbear 2022.83静态编译后dropbear、dropbearkey、dbclient三个文件加起来不到1MB动态编译更是只有三四百KBRSS内存占用在1MB上下。在Flash和RAM都要按字节抠的嵌入式设备上这个差异直接决定了方案能不能落地。对比项OpenSSH 9.xDropbear 2022.83完整服务端静态体积4MB以上800KB到1MB动态依赖OpenSSL、zlib、PAM等可选zlib默认可全部内置运行期RSS3MB到6MB约1MB启动速度依赖库加载较多偏慢秒级甚至毫秒级配置方式sshd_config配置文件命令行参数1.2 功能裁剪背后的取舍逻辑Dropbear之所以能做到这么小根本原因是它的密码学和SSH协议实现不走OpenSSL而是内置了libtomcrypt和libtommath。这两个库是专门为资源受限环境设计的只保留Dropbear用得到的算法不需要额外装庞大的OpenSSL。代价是它不支持OpenSSL里那些五花八门的加密套件但对嵌入式场景来说真正需要用到的也就是Ed25519/RSA密钥、AES-CTR/ChaCha20加密、Curve25519密钥交换这些Dropbear全都有。这个取舍逻辑很清晰SSH连接的本质就三件事——身份验证、传输加密、远程命令执行把这三点做好做稳其余功能都是锦上添花。Dropbear砍掉的是堡垒机、跳板机、企业级认证中心这类场景需要的东西保住的是“人在PC前远程能登进板子执行命令、传文件”这个核心诉求。也要说清楚如果你的设备需要做多因子认证、接AD域、做细粒度的用户权限审计那Dropbear真的不合适老老实实上OpenSSH。选型不是越轻越好而是刚好够用最好。2. SSH协议在Dropbear里被裁掉了什么一次连接要走的完整流程2.1 从TCP握手到进入ShellSSH连接有几个必须经过的关卡要理解Dropbear为什么能这么轻得先看看SSH连接到底做了什么。我习惯把整个过程拆成几个阶段每一阶段都会协商一堆参数这些参数的数量直接影响代码量和内存。先是TCP连接建立这个没什么可省的。然后是版本协商服务器返回SSH-2.0-dropbear_2022.83客户端返回自己的版本字符串双方确认都用SSH 2.0协议。接着是算法协商双方各自发一份支持的算法清单包括密钥交换算法、主机密钥算法、对称加密算法、MAC算法、压缩算法然后取交集作为本次会话的最终配置。OpenSSH的清单密密麻麻列一大串Dropbear的清单就精简很多比如对称加密默认重点保留AES-CTR和ChaCha20-Poly1305不带CBC系列的老弱算法省了代码也安全。算法协商完之后是密钥交换这一步用Diffie-Hellman或Curve25519协商出会话密钥同时客户端会拿到服务器的主机公钥验证自己连的确实是目标设备而不是中间人。最后才是用户认证阶段客户端用密码、公钥或键盘交互方式证明身份认证通过后进入会话阶段就可以执行shell、跑命令或者发起SFTP请求了。2.2 认证能力和转发能力被精简到什么程度认证层面Dropbear保留两种主流方式公钥认证和密码认证。键盘交互keyboard-interactive在部分版本里也提供支持用来兼容一些老客户端的密码输入流程。OpenSSH那套基于PAM的复杂认证链在Dropbear默认编译里是完全没有的这也意味着密码策略、账户锁定、登录告警这些企业级能力都需要你在上面另做方案。端口转发方面Dropbear支持本地转发和远程转发也就是常说的-L和-R参数X11转发也支持。但很多嵌入式设备默认连X11都没有所以实际使用中这功能基本用不上。做安全加固时可以用-j和-k参数把本地/远程转发关掉进一步缩小暴露面。我用一个形象点的类比OpenSSH像精装修公寓每间房功能齐全代价是物业费高Dropbear是清水房开发商只把墙刷白、水电通好你要在哪面墙挂什么画自己看着办。嵌入式环境里清水房反而更踏实。3. 交叉编译Dropbearconfigure参数逐个解释产物只有三个文件3.1 编译选项怎么选直接决定依赖和体积Dropbear的交叉编译在嵌入式Linux圈子里算是非常友好的不依赖什么奇特的构建系统一个configure脚本加make搞定。以2022.83 LTS版本为例下载源码后直接解压就能开始配。wget https://matt.ucc.asn.au/dropbear/releases/dropbear-2022.83.tar.bz2 tar xjf dropbear-2022.83.tar.bz2 cd dropbear-2022.83 ./configure --hostarm-linux-gnueabihf \ --disable-zlib \ --disable-pam \ --disable-shadow \ --disable-lastlog \ --disable-utmp \ --disable-wtmp \ --disable-utmpx \ --disable-wtmpx \ --enable-static make PROGRAMSdropbear dropbearkey dbclient -j4逐个解释一下这些选项。--disable-zlib很关键很多精简rootfs没有zlib库这时OpenSSH那种非要压缩的会直接崩Dropbear则允许你把压缩彻底关掉代价仅仅是传输带宽稍微多占一点。如果你的设备有zlib并且经常通过慢速无线链路传数据可以考虑保留压缩但编译时要链接zlib并把它一起打包进rootfs。--disable-pam是让Dropbear不依赖PAM的开关。嵌入式设备多数没有PAM机制用户管理和密码校验直接走/etc/passwd和/etc/shadow就够了。--disable-shadow也一样如果rootfs里没有shadow文件就必须关掉否则登录时会去读一个不存在的文件导致认证异常。--disable-lastlog、--disable-utmp、--disable-wtmp这一系列都是去掉登录记录相关的utmp/wtmp日志嵌入式设备通常没有这些系统级日志文件留着编译会报错。--enable-static就是我前面说的静态编译开关产物在目标板上不需要额外库直接能跑。注意不同版本的configure选项可能有细微差异编译前先./configure --help确认一下当前版本支持的选项名称避免出现“未知选项”的告警。编译选项不同体积差异很大建议实际项目里以configure动态生成的结果为准做一个版本和选项的对应表存档方便后续复现。3.2 产物只有三个文件每个都是干什么的编译完成后你会得到三个核心二进制。dropbear是SSH服务器端也就是设备上常驻监听22端口那个进程。dropbearkey是密钥生成工具专门用来生成服务器主机密钥和用户公钥认证所需的私钥/公钥对。dbclient是便于嵌入式互连调试用的轻量级SSH客户端功能比OpenSSH的ssh命令少但嵌入式设备之间互相管理时够用了。如果要用SFTP编译时把sftp-server也加进PROGRAMS列表它会生成一个SFTP服务器端程序客户端发起SFTP请求时由Dropbear动态拉起。编译完第一件事不是直接跑而是先给服务器生成主机密钥。主机密钥相当于设备的“身份证”客户端第一次连接时看到的就是它。命令如下./dropbearkey -t ed25519 -f /etc/dropbear/dropbear_ed25519_host_key ./dropbearkey -t rsa -s 2048 -f /etc/dropbear/dropbear_rsa_host_key为什么建议同时生成ed25519和rsa两把因为新版OpenSSH客户端对ed25519支持非常好默认算法也排在前面而一些老旧的嵌入式客户端或自动化脚本只认rsa。两把都生成服务器在算法协商时能给不同客户端都找到合适的选项。生成完毕记得把这两把密钥文件备份到开发机存档一旦设备丢失或Flash损坏还能用备份恢复出原来的身份。4. rootfs集成启动参数、busybox联动、端口放行三件事4.1 没有sshd_configDropbear的配置全在命令行参数里用惯了OpenSSH的人第一次用Dropbear会有点懵配置文件呢实际上Dropbear设计原则就是“跑起来只需要一条命令”所有配置都通过命令行参数传递需要持久化时把参数写进启动脚本就行。这个设计让它理论上不需要解析配置文件代码量自然小。我常用的一套启动参数是这样dropbear -p 2222 \ -r /etc/dropbear/dropbear_ed25519_host_key \ -r /etc/dropbear/dropbear_rsa_host_key \ -s \ -g \ -F -E-p 2222指定监听端口生产环境建议不要用默认22至少能把大量的扫描攻击流量挡在外面。-r指定主机密钥路径可以写多次把ed25519和rsa都加载进来。-s表示禁用密码登录只允许公钥认证。-g表示禁止root用户的密码登录但公钥登录不受影响。-F让Dropbear以前台模式运行方便调试时直接看日志输出-E把日志输出到stderr而不是syslog配合前台模式用非常顺手。正式部署时去掉-F和-E让Dropbear进入daemon模式后台运行。嵌入式设备没有systemd也常见老式busybox环境就写一个启动脚本放到/etc/init.d/下面比如S50dropbear#!/bin/sh case $1 in start) echo Starting Dropbear SSH server... /usr/sbin/dropbear -p 2222 \ -r /etc/dropbear/dropbear_ed25519_host_key \ -r /etc/dropbear/dropbear_rsa_host_key \ -s -g ;; stop) killall dropbear ;; esac4.2 busybox环境下的集成套路很多嵌入式Linux的rootfs本身就是busybox搭起来的Dropbear和busybox的集成方式其实很简单把编译好的dropbear、dropbearkey、sftp-server放到目标板的/usr/sbin或/usr/bin目录把主机密钥放到/etc/dropbear目录启动由busybox的init脚本拉起就行。busybox自带的service命令和rcS机制都可以用来执行上面那个启动脚本。如果你的板子用inetd来管理网络服务也可以用另一种更“抠”的思路让inetd监听2222端口收到连接请求时动态拉起dropbear这样空闲时完全不占内存。但这个方案我实际用下来感觉没那么省因为SSH连接本身就是长连接每次连接都走inetd中转多一层fork开销反而心里不踏实。所以大多数项目还是选择让dropbear常驻后台。4.3 端口放行和绑定地址集成完别急着连先确认设备自己的防火墙有没有把端口放出去。用iptables的话加一条iptables -A INPUT -p tcp --dport 2222 -j ACCEPT如果设备有多个网口我强烈建议把Dropbear绑定到管理网口的内网IP上不要所有接口都监听。命令只需要在-p参数后面带地址就行dropbear -p 192.168.10.2:2222这样即使另一张网卡暴露在公网环境攻击者也连不到SSH端口等于白捡了一层安全保险。5. 远程管理实战从密钥分配到scp与SFTP文件传输5.1 密钥登录配置别再靠密码了嵌入式设备上密码登录其实是个很尴尬的东西设备维护周期长密码很容易泄露而且很多设备根本没有把失败次数限制做到位暴力破解光靠一个弱密码就能开门。所以我在项目里都是直接上公钥认证密码登录在完成初期配置后立刻关掉。在开发机上生成一对密钥ssh-keygen -t ed25519 -C developeroffice-pc生成后把公钥内容放进目标设备的~/.ssh/authorized_keys。有ssh-copy-id的话最省事ssh-copy-id -p 2222 -i ~/.ssh/id_ed25519.pub root192.168.10.2没有这个命令就手动执行cat ~/.ssh/id_ed25519.pub | ssh -p 2222 root192.168.10.2 mkdir -p ~/.ssh chmod 700 ~/.ssh cat ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys这里有个非常容易踩的坑.ssh目录的权限必须是700authorized_keys文件必须是600很多rootfs默认umask比较宽松一旦权限不对Dropbear会直接忽略这个文件表现就是密钥明明放进去了却一直提示认证失败。每次配完可以用-v参数在客户端跑一遍看到Server accepts key才算真成功。5.2 传文件用scp别打包绕远路设备接入网络后我最常用的操作除了登录敲命令就是传文件。Dropbear没有像OpenSSH那样自带sftp-server但源码编译时带上之后scp命令可以直接用SFTP客户端也能连。SCP传文件时OpenSSH客户端会自动识别远端是Dropbear完全透明scp -P 2222 -i ~/.ssh/id_ed25519 ./app_update.bin root192.168.10.2:/tmp/注意scp指定端口用的是大写-P而ssh指定端口用的是小写-p这两个参数写法在同一个工具链里来回切换我一开始可没少被坑。从设备往回拉文件也是一样scp -P 2222 -i ~/.ssh/id_ed25519 root192.168.10.2:/var/log/messages ./messages_backup如果要用SFTPPC端Win10以上系统自带OpenSSH客户端直接支持Bitvise SFTP、WinSCP这类图形工具也能连接。连接时选SFTP协议端口填2222认证方式选公钥和连OpenSSH服务器没什么区别。服务端会自动拉起之前编译进去的sftp-server不需要额外配置。5.3 dbclient设备之间互连的备用手段有些场景需要设备主动去连另一台设备比如远程运维脚本要从一台网关设备跳转到另一台采集设备。这时目标板上如果也装了dbclient就能在设备上直接发起SSH连接dbclient -i /etc/dropbear/client_key -p 2222 root192.168.10.3它的参数风格和OpenSSH的ssh很像但功能少一些比如不支持X11转发的完整链路也没有ControlMaster那套连接复用机制。不过用于嵌入式设备之间的点对点管理已经够了。6. 嵌入式安全基线禁root密码登录、限定用户组、hostkey持久化6.1 影响安全的三个关键参数每个都必须知道Dropbear的几个启动参数直接决定暴露面大小。-s禁用掉所有密码登录这是一个“一刀切”的加固动作。一旦启用任何没有私钥的人都进不来包括那些拿默认密码字典扫端口的脚本机器人。代价是私钥管理要跟上开发机丢了等于设备失守所以私钥建议放在带密码保护的本地存储里。-g单独禁掉root的密码登录但保留root的密钥登录。这个参数的好处是即使某次操作失误导致/etc/shadow里有弱密码root也没法通过网络用密码登录减少被撞库成功的概率。注意它不影响普通用户的密码登录普通用户依然可以密码登录后再su或sudo切换。两个参数叠加的效果是任何用户都不能用密码登录root只能通过密钥登录。这在设备上电后没有任何人维护的场景下是相对合理的安全基线。纯内网调试环境可以适当放宽但建议至少保留-g。6.2 限制登录用户组Dropbear没有AllowGroups怎么办OpenSSH的sshd_config里有AllowGroups、AllowUsers这些简单直接的配置Dropbear没有这个机制。如果设备上同时存在多个系统账号你又不希望每个账号都能SSH进来常见做法有两条路。一条是把不需要远程登录的账号的shell字段改成/sbin/nologin。Dropbear在用户认证通过后会检查用户的shell是否在/etc/shells里不在就拒绝进入。配合busybox的adduser创建账号时指定shell能比较轻量地实现“只有运维账号能登录”。另一条是编译时打开PAM支持然后通过/etc/pam.d/sshd引用pam_access.so用/etc/security/access.conf配置允许的组和用户。这条链路更接近企业级做法但会引入PAM依赖体积和复杂度都上去了嵌入式项目里除非有合规要求否则不推荐。6.3 hostkey持久化别让设备重启后“变脸”这是我踩过最深的坑之一。一块NAND Flash根文件系统是只读挂载的Dropbear的主机密钥放在/etc/dropbear下面设备一重启密钥文件就没了。Dropbear启动时发现没有指定-r的密钥就直接现场生成一把临时主机密钥。从客户端看就是设备的指纹每次重启都变频繁弹出REMOTE HOST IDENTIFICATION HAS CHANGED你第一反应是设备被中间人攻击了其实是它把自己的“身份证”丢了。解决办法分几步。先确保主机密钥目录挂载在可写分区比如/data/dropbear启动参数用-r /data/dropbear/dropbear_ed25519_host_key。然后在批量生产时统一生成一套密钥烧录阶段写进设备的可写分区或者做OTA升级时检测到密钥缺失就自动用dropbearkey生成并备份。还有个细节如果你先刷了一版镜像启动过一次Dropbear然后再烧录一个包含相同hostkey的新镜像客户端known_hosts就会报警。遇到这种情况不用怀疑设备有问题先把本机known_hosts里旧设备对应的那行删掉重新连一次同时确认新镜像里的密钥确实是沿用旧的再继续。7. 排错实录Dropbear连接失败的三条典型排查链路7.1 客户端报算法不匹配先查hostkey类型和版本基线用新装好的Ubuntu笔记本去连一台老设备可能会直接看到类似no matching host key type found或者Unable to negotiate with ... port 2222: no matching key exchange method的报错。这个问题的根源是OpenSSH新版本出于安全考虑默认禁用了ssh-rsa也就是SHA-1签名的RSA而老设备上的Dropbear只生成了rsa类型的主机密钥两边算法取交集时发现一个都不匹配。排查时先加-v跑一遍看协商日志卡在哪一步ssh -vvv -p 2222 root192.168.10.2日志里会明确写出客户端支持的算法和服务端返回的算法。搞清楚是hostkey不匹配还是kex算法不匹配后最稳妥的解决方法不是客户端强行放行旧算法而是到设备端用dropbearkey生成ed25519主机密钥重启服务。ed25519是新旧OpenSSH都默认支持的一劳永逸。如果设备端没法改只能在客户端做临时放行Host 192.168.10.2 HostKeyAlgorithms ssh-rsa PubkeyAcceptedAlgorithms ssh-rsa注意这相当于降低了客户端安全基线只建议在调试老设备时临时用别写进所有机器的全局配置。7.2 密码明明正确却一直登录失败先查rootfs裁剪有没有漏掉的关键文件嵌入式rootfs经常被裁剪得很狠有些文件缺了表面上看不出来但会让密码认证彻底失效。Dropbear默认从/etc/passwd读取用户信息如果系统启用了shadow支持还会去/etc/shadow读取密码哈希。有些精简rootfs只保留了passwd把shadow删了或者passwd里root行的密码字段填的是x但对应的shadow文件不存在结果就是密码怎么输都不对。排查思路很简单。第一确认passwd文件里面root行的第二列是真正的哈希值还是x。如果是x说明系统走shadow体系必须确认/etc/shadow存在并且root项确实有哈希。第二用ls -l /etc/shadow看一下权限shadow文件通常是640权限属主root组shadow或root如果权限太松或被busybox精简掉也会出问题。第三在设备本地控制台用login试一下如果本地能登录而SSH不行再回头查Dropbear的编译选项确认--disable-shadow是不是和目标rootfs的认证方式不一致。这个问题还有一种变体嵌入式rootfs通常没有/etc/pam.d但如果你编译Dropbear时开了PAM支持它会尝试走PAM认证而系统里根本没有PAM模块认证自然失败。这也是我前面推荐默认--disable-pam的直接原因越简单的认证链在裁剪rootfs上越不容易出幺蛾子。7.3 连接卡在密钥交换阶段大概率是熵源不足有类嵌入式设备特别是低成本方案上电后SSH连接卡住-v日志停在密钥交换阶段就绪状态迟迟不出来。SSH的密钥交换需要用到随机数生成。PC上有独立的硬件熵源但很多MCULinux的板子把硬件随机数发生器裁了内核的熵池在开机初期几乎是空的而Dropbear在密钥交换时发现随机数不够就进入等待表现就是客户端无响应。排查手段是进设备看熵池状态cat /proc/sys/kernel/random/entropy_avail如果这个值长期只有几十甚至接近0就是熵源不足。解决路径有两条。一条是内核开启CONFIG_RANDOM_TRUST_CPU让内核信任CPU里的硬件随机数指令比如ARM的RNDR指令这样开机就能快速填充熵池。另一条是给设备接一个外部TRNG模块成本稍高但可靠性更好。实际操作中还要看平台有的芯片虽然有TRNG但驱动没起来检查dmesg | grep -i random大概率能看到线索。这三个问题我在不同项目里都遇到过每次事后复盘都会发现出问题的根源要么是版本差异要么是rootfs裁剪过度要么是硬件平台的特性没考虑到。把这三条排查链路背下来远程管理通道的稳定性至少能上一个台阶。最后分享一个我坚持了两年的习惯每次给批量设备烧完系统开机后第一件事不是测试业务而是用SSH连一次、传一个测试文件、再重启用新hostkey连一次把这三件事跑通再放行。这套流程看着浪费时间其实省掉的是后续排障时的大把熬夜时间。Dropbear本身很稳定真正需要你用心的是围绕它展开的身份管理和密钥持久化设计。