嵌入式Linux轻量级SSH首选:Dropbear部署与配置实战
2026/9/5 8:37:20 网站建设 项目流程

开头直接用从业者口吻引入,把Dropbear放在嵌入式Linux这个具体场景里,点明它能解决的问题:小内存设备上的SSH远程管理。然后说明这篇文章要讲什么:协议层面的取舍、部署配置、密钥管理、常见问题,适合哪些人看:做嵌入式开发、搞运维、自建路由器系统的人。不要教科书式说教,要像同行聊天。

1. 为什么嵌入式Linux里SSH首选Dropbear,而不是OpenSSH

嵌入式设备这个词说起来轻巧,实际工作环境极其苛刻。Flash空间按MB算,内存条按MB的几分之一算,CPU主频还不如十年前PC的一个零头。很多项目用的内核镜像也就十几MB,跟PC上的Linux发行版动辄几个GB完全是两个物种。在这种环境下,SSH远程管理就成了一个很微妙的需求:功能要全,体积要小,占用要低。

很多人第一反应是装OpenSSH,因为服务器上一直用它,熟悉。真装上去就后悔了,一个sshd二进制几十MB依赖库,还要配置文件、host key、PAM认证模块,几轮下来机器的整个用户空间都被它吃掉大半。更头疼的是OpenSSH默认配置面向通用服务器,一堆加密算法和认证方式默认开启,对嵌入式这种资源紧张的设备来说纯属浪费。

Dropbear就是干这个的。它从设计之初就把“小”刻在骨子里:静态编译完整个包含了SSH服务端和客户端的完整方案,一般只有几百KB的二进制体积,特别适合放进去busybox这种精简用户空间里。它的内存占用峰值通常在几MB到十几MB之间,在内存只有32MB甚至16MB的老设备上,跑起来完全没压力。它支持SSH协议2.0,也能完成SCP和SFTP这类基本文件传输需求,对于日常的远程登录、命令执行、日志查看、文件上传下载,完全够用。

还有一点容易被忽略:Dropbear的代码库非常紧凑,审计成本低。在嵌入式设备这种缺乏即时补丁条件的场景下,代码越少、功能越收敛,攻击面就越小。这并不是说Dropbear一定比OpenSSH安全,而是说在设备资源受限、没法频繁更新的前提下,把暴露面控制在最小范围本身就是最实际的一种安全策略。

所以在多数嵌入式Linux项目里,最终的技术选型基本是:服务端用dropbear,客户端也直接用dropbear提供的dbclient,整套SSH能力打包起来还不够OpenSSH一个零头,这才是嵌入式环境下该有的姿态。

1.1 Dropbear和OpenSSH在嵌入式场景下的核心差异对比

经常有人问,Dropbear到底比OpenSSH差在哪,为什么服务器上不用它。直接看一组实际数据就清楚了,我拿同一台ARM Cortex-A7设备分别编译两个服务端,rootfs环境完全一致:

对比项DropbearOpenSSH
服务端静态编译体积约700KB-800KB约2MB-3MB,加上依赖库更夸张
运行内存占用(空闲连接)1.5MB-3MB8MB-15MB
连接建立后内存增量每连接约200KB-400KB每连接约1MB-2MB
依赖库基本无外部依赖,可静态编译通常需要zlib、openssl、pam等
配置文件启动参数即可控制,配置文件极简大量配置项,默认配置几百行
密钥生成工具dropbearkey,单个二进制ssh-keygen,需要对应工具链
典型适用场景嵌入式、物联网网关、路由器服务器、桌面系统、堡垒机

不是说OpenSSH不好,在服务器那种资源充足、审计要求高、需要对接AD域或复杂认证策略的环境里,OpenSSH的丰富特性是不可替代的。但嵌入式设备首先得活下来,资源占用直接决定产品能不能量产,功能再全装不上都是白搭。

很多人还有一个误区,觉得Dropbear功能太少不够用。真实项目里,远程管理需要的东西无非就是:登录命令行、传文件、密钥认证、端口转发。这几样Dropbear全都支持,只是配置方式跟OpenSSH不太一样,习惯之后反而觉得更清爽。SFTP功能在较新版本里也支持了,需要编译时加--enable-sftp-server选项,由系统的sftp-server进程配合实现。

1.2 轻量化思路如何影响嵌入式项目的整体架构

选Dropbear不只是一个软件替换的问题,它会影响整个嵌入式Linux系统的设计思路。做嵌入式产品的人应该都有体会,用户空间根文件系统一定要能瘦就瘦,能静态编译就静态编译,能去掉的依赖库坚决去掉。因为每多一个动态库,就得把对应的so文件拷进去,还得小心处理符号依赖和版本冲突,万一库版本不对,某个功能启动时直接报undefined symbol,排错排到怀疑人生。

Dropbear的轻量化,正好契合了这种“一个进程干一件事,互不牵扯”的思路。很多项目中,直接把dropbear的静态编译版本放进rootfs的/usr/sbin目录,然后通过busybox的init脚本或者systemd的service单元来管理启动,全程不需要额外的运行库。这种模式带来的好处至少有三个方面:

第一是裁剪方便。想要去掉某个加密算法,编译时加上对应选项即可,二进制立刻变小。第二是部署可靠。静态编译的Dropbear几乎不依赖rootfs里其他组件,就算把libc都替换成musl或者uclibc,它也能正常工作。第三是便于调试。真出问题的时候,直接用一个statically linked的dropbear,配合dropbearkey生成临时密钥跑起来,不需要管库文件对不对、路径有没有配错,排查速度能快一整截。

我这几年接触过的嵌入式Linux项目里,至少一半选择了“busybox + dropbear”这个基础组合,再根据业务需要挂上ntpclient、udhcpc、telnetd(仅调试)、lighttpd、mqtt客户端之类的东西。这种组合经得住量产验证,维护成本低,出了问题社区里一搜一堆答案,非常适合长期维护的项目。

2. Dropbear的SSH协议实现与技术细节

光知道它小还不够,作为工程师得理解它怎么实现“小”的,以及这种实现方式带来哪些技术上的取舍。很多人在OpenSSH上积累的排错经验,换到Dropbear上会失效,原因就在于两者的协议实现和代码路径差异很大。

Dropbear遵循的是RFC 4251到RFC 4254这套SSH协议体系,也就是我们常说的SSH-2.0。它本身就摒弃了古老且不安全的SSH 1.x协议,整个代码库也是为SSH-2.0量身定做的,不存在OpenSSH那种为了兼容老版本而保留的历史包袱。这意味着它的代码路径更短,状态机更简洁,出问题的概率天然会更低。

完整的SSH协议交互流程大致是:客户端发起TCP连接,TCP三次握手完成后,双方交换版本字符串,就类似两个人在开口说话之前先报上家门。服务端发送的版本字符串一般是“SSH-2.0-dropbear_2022.83”,客户端看到后确定协议版本,接着进入密钥交换阶段,协商加密算法、MAC算法、压缩算法等,这一步叫algorithm negotiation。然后是密钥交换,这一步决定了双方能否安全地建立会话密钥,Diffie-Hellman系列算法是核心。认证阶段通常是password或者publickey两种方式,认证通过后进入连接协议阶段,开始承载shell通道、exec命令、sftp子系统等真正的业务数据。

Dropbear在这条链路里做了大量有针对性的简化。它默认只启用少数几个性能较好、实现精简的加密算法,比如chacha20-poly1305、aes128-ctr、aes256-ctr,以及支持最基本的diffie-hellman-group14和curve25519-sha256密钥交换算法。这跟OpenSSH默认开启一大堆算法形成了鲜明对比。好处是代码瘦、握手快,坏处是如果客户端太老或者配置了很古怪的cipher白名单,可能出现算法协商失败,这个在后面的问题排查里我会细说。

2.1 SSH协议中的密钥交换与算法协商过程

SSH协议安全性的核心,在于密钥交换和后续的消息认证。Dropbear在算法协商阶段的逻辑跟OpenSSH基本一致,只是支持的算法集合更小且更聚焦。以最常见的diffie-hellman-group14-sha256为例,过程大致是这样:

客户端和服务端各自生成一个DH私钥,然后根据选定的素数群计算自己的公钥并发送给对方。收到对方的公钥后,双方各自计算出一个共享的密钥K。这个K本身并不会直接用于加密通信,而是作为种子材料,通过哈希运算推导出会话密钥。会话密钥用于后续的对称加密和消息完整性校验。整个过程中,私钥始终不出本方机器,中间人即使截获了交换数据,也无法还原出会话密钥。

Dropbear对curve25519-sha256的支持值得一提。这个概念源于OpenSSH后来引入的curve25519算法,被广泛认为是目前性能与安全性平衡最好的密钥交换方案。Dropbear在较新版本里直接内建了curve25519的实现,不需要依赖外部加密库,这也是它“小而全”的一个体现。

实际操作中,算法协商的结果可以通过打开更详细日志来查看。在启动dropbear时加上-v参数,或者在配置日志级别为DEBUG时,就能看到类似“kex: algorithm: curve25519-sha256”的输出。这个信息在排查“为什么某些客户端连不上”的时候非常有用,能第一时间确定是哪一层的算法没匹配上。

2.2 公开密钥认证与主机密钥的生成管理

SSH免密登录在嵌入式设备上尤其重要。设备部署到现场之后,没有键盘显示器,根本没法输密码。这时候只能靠公钥认证。Dropbear的配置方式跟OpenSSH大同小异,但有些细节要格外留意。

首先要确定配置位置。默认情况下,Dropbear读取/etc/dropbear目录下的host key文件,比如dropbear_rsa_host_key、dropbear_ed25519_host_key。客户端用户的授权密钥文件路径跟OpenSSH一样,放在用户家目录下的~/.ssh/authorized_keys文件里。这点很贴心,从OpenSSH搬过来的公钥可以直接用。

V版本差异要注意。较老版本的Dropbear在读取authorized_keys时要求文件权限不能对group和other开放,否则直接拒绝。所以配置完之后最好执行chmod 700 ~/.ssh,再把authorized_keys设成600。很多老鸟在嵌入式上反复配置免密不生效,最后发现是权限问题,就是这一下。

主机密钥是所有SSH服务的根,一旦丢失或损坏,所有客户端缓存的主机指纹都会失配,表现为“REMOTE HOST IDENTIFICATION HAS CHANGED”的警告。对嵌入式设备来说,这个问题尤其隐蔽,因为设备通常没有外置存储,密钥可能在出厂时生成一次就再也没管过。万一Flash损坏、OTA升级过程中rootfs被重写,主机密钥没了,老客户端的known_hosts就全废了。

我一般建议在量产阶段就把host key预置进rootfs,并固化在独立的配置分区里,比如/data/dropbear目录,这样即使系统分区被刷写,密钥也能保留。生成主机密钥的命令很简单:

mkdir -p /etc/dropbear dropbearkey -t ed25519 -f /etc/dropbear/dropbear_ed25519_host_key # 可选,兼容旧客户端再加一组 dropbearkey -t rsa -s 2048 -f /etc/dropbear/dropbear_rsa_host_key

需要留意的是,RSA密钥的最小位数在较新版本里可能被抬高到2048位,生成的时候位数别设太低。另外,主机密钥的权限要改成600:

chmod 600 /etc/dropbear/*_host_key

3. 在busybox环境里集成Dropbear的完整部署流程

理论聊完,直接上实战。下面这套流程是我在多个项目里反复验证过的,从零开始把Dropbear集成到基于busybox的最小Linux系统中,加上密钥认证、端口切换、调试日志,整个过程大概半小时就能搞定。

先交代环境假设:目标系统是ARM Cortex-A7架构,内核版本4.9或5.10,rootfs由busybox构建,管理方式是通过串口先进入设备shell。如果你的rootfs是用Buildroot或Yocto生成的,操作方式大同小异,只是文件路径和启动脚本写法略有差异。

3.1 交叉编译Dropbear时的关键配置参数

交叉编译是嵌入式开发的日常操作。Dropbear本身用autotools构建,支持标准的configure交叉编译模式,比较友好。以arm-linux-gnueabihf工具链为例,典型配置命令长这样:

./configure --prefix=/usr --host=arm-linux-gnueabihf \ --disable-zlib \ --disable-pam \ --disable-lastlog \ --disable-utmp \ --disable-wtmp \ --enable-static

这些参数各有讲究,我逐一说下:

  • --disable-zlib:关闭zlib压缩支持。嵌入式Flash本来就小,压缩省下的那点带宽不如省下的体积划算,而且zlib依赖还会引入外部库,静态编译时尤其麻烦。
  • --disable-pam:关闭PAM认证。嵌入式系统通常没有PAM框架,不开它反而省事。
  • --disable-lastlog、--disable-utmp、--disable-wtmp:这些登录审计功能依赖系统日志和utmp设施。如果你不需要记录用户登录历史,直接关掉减小体积。
  • --enable-static:静态链接。出来一个几乎独立的二进制,拷到rootfs里就能用。

编译命令也很常规:

make PROGRAMS="dropbear dropbearkey dbclient scp" make install

再提醒一下,如果工具链用的是musl libc,编译时通常不用额外参数;如果用的是uclibc,可能出现“fork: Cannot allocate memory”之类的怪问题,一般调一下系统内存配置或者改用musl就能解决。这里踩坑概率挺高,后文专门列出来。

3.2 为rootfs制作启动脚本与密钥预置策略

拿到编译好的三个二进制(dropbear、dropbearkey、dbclient),下一步就是插进rootfs。推荐路径如下:

/usr/sbin/dropbear # 服务端 /usr/bin/dropbearkey # 密钥生成工具 /usr/bin/dbclient # SSH客户端,可选 /usr/bin/scp # 开了SCP选项后会有

启动脚本方面,我习惯把它们集成到busybox的init流程里。如果用的是busybox init,就在/etc/init.d/rcS里加载服务。如果用的是systemd,则写一个service unit。这里给一个最小可用的busybox init脚本示例:

#!/bin/sh # /etc/init.d/S50dropbear DZ=/usr/sbin/dropbear KEY_DIR=/data/dropbear if [ ! -d "$KEY_DIR" ]; then mkdir -p "$KEY_DIR" fi # 如果没有主机密钥就先生成 if [ ! -f "$KEY_DIR/dropbear_ed25519_host_key" ]; then /usr/bin/dropbearkey -t ed25519 -f "$KEY_DIR/dropbear_ed25519_host_key" 2>/dev/null fi # 启动服务 /usr/sbin/dropbear -r "$KEY_DIR/dropbear_ed25519_host_key" -p 2222

有几个细节值得展开:

一是密钥目录最好放在独立分区。上面例子放在/data/dropbear,就是要跟系统分区隔离。这样OTA升级、系统重置都不会影响已配好的主机密钥和用户密钥。

二是默认端口我习惯改成2222而不是22。原因不是安全,22端口的扫描太疯狂了,日志里全是暴力破解尝试,看着烦。改成一个高位端口能屏蔽掉绝大多数无脑扫描流量,降低无效负载,Log也干净一些。

三是如果设备有多个网卡,比如一个内网一个外网,一定要用-p参数明确绑定监听地址。比如只监听内网地址:

/usr/sbin/dropbear -p 192.168.1.10:22

这比监听0.0.0.0更可控,外网接口根本不暴露SSH服务。

系统启动之后,可以先在本机测试一下服务是否正常:

dbclient -y -i /path/to/id_ed25519 root@127.0.0.1

如果提示连接被拒绝,多半是服务没起来,查一下进程在不在、端口有没有监听。如果提示算法协商失败,就看日志。

3.3 配置密钥认证和dfbv客户端登录的其他细节

服务端跑起来之后,接下来配置用户级公钥认证。在嵌入式设备上,root用户是事实上的管理账户,所以一般直接给root配置公钥。步骤很简单:

mkdir -p /root/.ssh echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAxxxxxx user@laptop" > /root/.ssh/authorized_keys chmod 700 /root/.ssh chmod 600 /root/.ssh/authorized_keys

然后把设备上的pubkey保存下来,或者在调试阶段先用dbclient配合密码登录,后面再切换成密钥认证。

如果你习惯用OpenSSH的ssh-keygen生成客户端密钥,生成的公钥Dropbear可以直接用。很多人不知道这个兼容关系,自己拿dropbearkey生成了一堆客户端密钥,最后发现密钥格式不对,去查文档才发现多此一举。直接用你电脑上的~/.ssh/id_ed25519.pub内容拷进去即可。

在这里额外说一句,公钥认证有个安全细节:公钥本身等于“主钥匙”的锁芯,谁有私钥谁就能开这台设备。所以密钥一定不要放到代码仓库里,设备上只用公钥,私钥只保存在你的电脑或专用的密钥管理工具里。如果设备丢失,马上把对应的公钥从所有设备的authorized_keys里删掉。批量管理这个环节,后面专门说。

4. 从OpenSSH迁移到Dropbear时的配置转换技巧

很多项目早期用OpenSSH,后来为了缩包、降内存,逐步切到Dropbear。这个迁移过程比想象中麻烦,主要是两边的配置语法、密钥路径、认证行为不完全一致。踩过几次坑之后,我把常用迁移点总结成下面几条。

4.1 配置项与启动参数对照速查表

OpenSSH习惯把所有东西写在一个sshd_config文件里,而Dropbear习惯用命令行参数控制,虽然也有配置文件支持(通过-R或者默认行为读取/etc/dropbear/config),但社区普遍直接传参。下面这张对照表是迁移时最常用的:

功能OpenSSH写法Dropbear对应写法
监听端口Port 2222-p 2222
监听地址ListenAddress 0.0.0.0-p 0.0.0.0:2222
主机密钥路径HostKey /etc/ssh/ssh_host_ed25519_key-r /etc/dropbear/dropbear_ed25519_host_key
允许root登录PermitRootLogin yes默认允许,以-start参数控制
指定认证方式PasswordAuthentication yes-s参数强制公钥,-g参数开启密码
空闲超时ClientAliveInterval 60-I 60(单位是秒)
最大连接数MaxSessions 10-C 10(较新版本支持)
日志级别LogLevel VERBOSE-v(会输出到标准错误或syslog)

注意有些参数不是一一对应的。比如PermitRootLogin in OpenSSH可以限定root登录方式为prohibit-password,Dropbear没有这么细的粒度,只能通过启动参数控制允许密码还是只允许公钥。如果你的安全合规要求root只能密钥登录,那就用-s参数关掉密码登录,在全局层面实现,而不是单账号层面。

4.2 authorized_keys兼容性的坑和解决方式

OpenSSH和Dropbear对authorized_keys的解析规则大体一致,但有一个地方容易踩雷:options字段。OpenSSH的authorized_keys里每行开头可以带一堆选项,比如from="192.168.1.0/24",command="/usr/bin/foo",no-pty ssh-rsa AAAA...。Dropbear在解析时,部分选项支持,部分选项直接忽略,如果选项里带了Dropbear不认识的语法,整行可能被判定为无效,导致这台设备上该公钥无法登录。

遇到这种问题,推荐一个稳妥做法:在目标设备上专门准备一个纯公钥的authorized_keys文件,只放“ssh-rsa AAAA...”“ssh-ed25519 AAAA...”这种最简格式。至于source IP限制、命令强制等功能,可以在服务端防火墙层面做,或者用Dropbear支持的选项做,效果一样,还不会把密钥文件本身搞得复杂。

另一个坑是关于密钥类型的优先级。如果你同一台设备上既放RSA公钥又放ED25519公钥,服务端默认会尝试用自己能匹配的算法。如果你在客户端强制指定了某个密钥,比如ssh -i指定RSA私钥,但服务端只配置了ED25519的host key,这里倒不影响用户认证。真正影响用户认证的是你本地的ssh_config里有IdentityFile指定顺序,有时候会选错私钥导致认证失败。排查时不光要盯设备端,也要看客户端-w选项打印的信息。

5. 远程管理实战:从单机调试到批量运维

SSH的价值在于远程管理,而远程管理的复杂度随着设备数量指数上升。一台设备用SSH登录很简单,一百台设备用SSH管理,就要认真思考批量策略了。这里分享几个我在嵌入式设备现场运维中沉淀下来的实战方案。

5.1 用dbclient完成单机登录与快捷文件传输

先讲单机。很多人的开发机上没有OpenSSH,或者因为某些原因不想装。Dropbear自带的dbclient完全可以承担单台设备的登录任务,只是参数和输出格式跟OpenSSH略有区别。典型登录命令:

dbclient -i ~/.ssh/id_ed25519 root@192.168.1.100 -p 2222

能加-y参数跳过首次主机指纹确认,在测试环境方便,但生产环境慎用。加了-y等于默认信任所有主机,存在中间人攻击风险。文件传输方面,如果编译时带了SCP支持,直接用scp命令即可:

scp -P 2222 ./app.bin root@192.168.1.100:/tmp/

注意这里SCP的端口参数是大写的-P,OpenSSH是-P吗?其实是小写-p,这点容易记混。Dropbear下的scp用法和行为基本复刻OpenSSH,所以日常习惯无缝迁移。

对于不支持SFTP文件列表功能的场景,你也可以用tar加管道的方式打包传输目录。比如把整个/etc目录拷回来:

ssh root@192.168.1.100 -p 2222 "tar czf - /etc" > etc_backup.tar.gz

这种玩法在嵌入式上非常实用,尤其调试归档时,不需要在设备上安装额外工具。

5.2 批量登录脚本的思路与安全建议

设备多起来,手动一条一条SSH登录就不现实了。批量运维的核心无外乎:所有设备用同一套root公钥、脚本循环遍历IP、命令统一执行、结果汇总返回。我写过一个最小但可扩展的批量脚本框架:

#!/bin/bash # batch_exec.sh - 批量执行远程命令 HOSTS_FILE=hosts.txt KEY=~/.ssh/id_ed25519 PORT=2222 CMD="$@" if [ -z "$CMD" ]; then echo "Usage: $0 <command>" exit 1 fi while read -r host; do [ -z "$host" ] && continue echo "===== $host =====" timeout 10 dbclient -y -i "$KEY" -p "$PORT" root@"$host" "$CMD" 2>&1 done < "$HOSTS_FILE"

这套脚本的核心是timeout命令,防止某一台设备网络不通时整个脚本卡死。批量推送文件也类似,无非是把dbclient换成scp。

安全上必须强调三点:

第一,所有设备的root公钥必须由可控人员持有,不能放公网可访问的Git仓库,也不能直接放在产品固件里公开下载。第二,批量操作前先在1-2台设备上试运行,确认命令没有破坏性,再全量跑。很多事故都发生在“我以为这命令是幂等的,结果跑完数据全没了”。第三,生产环境最好不用-y参数,把公钥指纹分发给运维人员,或者用known_hosts的方式维护可信指纹。

如果设备量达到几千台,建议上专门的批量运维平台或者配合Ansible这种工具。Dropbear做不好集中式密钥管理,但它能把被管端的Agent体积做到最小,这就是它的价值。

5.3 密钥的轮换与灰度发布

长期运行的设备,密钥总有过期和泄露的时候。SSH公钥没有真正的过期时间概念,但你可以通过更换authorized_keys内容实现轮换。实际操作中,我比较推荐“灰度替换法”:

先在客户端生成一对新密钥:

ssh-keygen -t ed25519 -f ~/.ssh/new_deploy_key -C "deploy-key-v2"

然后把新公钥追加到部分设备上,注意是追加而不是覆盖:

echo "ssh-ed25519 AAAAC3... new_deploy_key_v2" >> /root/.ssh/authorized_keys

用新私钥验证登录成功后,再从所有设备的authorized_keys里删掉旧公钥。如果某些设备在批量修改过程中失联,还可以保留旧公钥作为回溯通道。这跟软件灰度发布是同一个逻辑,核心思想是不能一刀切。

轮换过程中经常遇到的问题:设备掉电导致文件写到一半,authorized_keys损坏。所以我写了个原子替换的脚本片段:

cat > /root/.ssh/authorized_keys.new << 'EOF' ssh-ed25519 AAAA... key_v2 EOF chmod 600 /root/.ssh/authorized_keys.new mv /root/.ssh/authorized_keys.new /root/.ssh/authorized_keys

先写临时文件再mv,确保不会出现半截文件。这个习惯我后来也用在了所有嵌入式配置文件的更新上,强烈推荐。

6. 常见故障排查与调试技巧实录

Dropbear整体稳定,但真正用起来还是会遇到各种问题。这一节挑几个我觉得最有代表性的,按顺序说下典型现象、排查思路和最终解决办法,希望对你有帮助。

6.1 连接超时与端口不可达问题的研判流程

嵌入式设备连不上SSH,先别急着怀疑Dropbear本身。我一般按下面这个顺序排查:

第一步,确认网络通不通。从开发机ping设备IP,如果ping不通,先查网线、Wi-Fi、IP配置、路由表,这些问题跟Dropbear没关系。

第二步,确认端口是否监听。在设备本机(通过串口进去)执行netstat -an或ss -lntp:

# 如果系统里有ss工具就用ss,没有就netstat netstat -lntp | grep 2222

如果看不到监听,检查dropbear进程有没有起来:

ps | grep dropbear

没起来就看日志、看启动脚本有没有报错、依赖的文件路径对不对。最常见的低级错误是密钥目录不存在,或者目录权限不对,dropbear直接退出了。

第三步,确认有没有防火墙拦截。很多嵌入式内核默认开启了iptables规则,但这些规则可能是出厂测试后没清干净。检查如下规则:

iptables -L -n -v

如果发现INPUT链有DROP规则,可以考虑放行指定端口或者清空规则(测试环境)。曾经遇到一台设备,串口一切正常,网络也通,就是SSH连不上,最后发现是内核netfilter模块没加载,iptables规则“看似生效”实际是空转,查了半天才发现是模块问题。

如果以上都正常,再考虑是不是加密算法不兼容。这个一般通过客户端报错看得出来,比如“no matching key exchange method found”“no matching cipher found”。解决思路是两边统一到一个安全但通用的算法集合上。老版本客户端连接新版本Dropbear,或者新版本客户端连接老版本设备,都容易出现这种问题。

6.2 免密登录失败时的分层定位思路

免密登录失败是另一个高频问题,现象就是输入密码才能登录。其实绝大多数都是公钥没被正确配置,而不是Dropbear本身的bug。我建议按层去查:

第一层,客户端是否真正用对了私钥。ssh调试时用-v参数或者dbclient -v:

dbclient -v -i ~/.ssh/id_ed25519 root@192.168.1.100 -p 2222

注意看日志里是否出现“Trying private key”之类的内容。如果客户端压根没尝试你指定的私钥,大概率是密钥路径写错了,或者ssh-agent里缓存了别的密钥。

第二层,服务端是否读取了正确用户的authorized_keys。用root登录看的就是/root/.ssh/authorized_keys。有些系统改用了/home/root,有些用/etc/dropbear/authorized_keys自定义路径,路径错一个字母都白搭。

第三层,文件权限。这一步在文章前面强调过,600和700是标配。很多嵌入式系统挂载的Flash文件系统不支持标准的Unix权限概念(比如vfat),导致权限检查逻辑看起来不可控。此时推荐一个办法:把authorized_keys放到独立分区并用ext4或jffs2这类支持权限的文件系统,否则要么总是被拒,要么权限检查形同虚设。

6.3 后门木马类风险与二进制的去伪存真

最后单独说一个跟安全相关的话题。Dropbear因为广泛用于路由器、物联网设备,已经是一些恶意软件和固件后门的目标。比如之前爆过的Dropbear供应链问题(CVE-2021-36376相关的恶意版本),以及厂商定制固件里被人悄悄植入的“魔改Dropbear”——一个表面上正常的dropbear,实际在验证密码时总是接受某个特定后门口令。

怎么防范?我建议三步走:

第一,始终从官方发布渠道获取代码,交叉验证source tarball的SHA256哈希,不要在不知名博客上随便下载二进制。第二,如果有条件,把编译后的二进制用strings查一下可疑字符串,比如“happy”“backdoor”“master”等不正常的口令校验分支。第三,做成固件后开机校验一下Dropbear的二进制哈希,跟出厂记录比对,防止运行时被篡改。

在真实项目中,还要留心固件迭代时误把调试用的后门账户或者临时密码带到生产环境。这个属于流程问题,跟具体软件无关,但对嵌入式产品的安全影响极大。建议每次发布前跑一遍自动化检查脚本,把authorized_keys、passwd、shadow这些关键文件和白名单比对。

6.4 典型问题排查速查表

把上面这些经验浓缩成一张排查表,方便现场对照:

症状优先排查项常见根因解决方式
连接超时ping、端口监听、防火墙服务未启动、网络不通对照6.1三步法依次排查
连接被拒绝进程状态、监听地址、端口占用启动参数错误、端口被占换端口或检查-p参数
密码错误但确认无误是否覆盖了密码认证只允许公钥认证(-s)重启时去掉-s或改用密钥
免密失败客户端-v日志、文件权限密钥路径、权限、文件系统支持按6.2三层法排查
算法不匹配客户端日志输出cipher或kex算法集合不一致调整客户端Or服务端算法集
主机指纹警告known_hosts内容主机密钥变更、设备重置确认设备身份后删除known_hosts旧条目
SCP/SFTP不可用编译选项未启用sftp-server或scp支持重新编译并拷贝对应组件

这张表不是万能的,但覆盖了我这些年遇到的80%以上问题。遇到新问题,第一要务是看日志,Dropbear的-v输出和信息日志已经能解决大部分困惑。

7. 内核和系统层的注意事项

说了这么多,其实SSH服务的稳定运行还取决于嵌入式的底层环境。有几个环节经常被人忽略,出问题了又特别难查,专门拿出来说。

7.1 内存不足与进程崩溃的诱发点

嵌入式设备内存小,Dropbear本身占用不大,但加上业务进程、内核页缓存后,系统随时可能进入内存压力状态。当内存严重不足时,内核会调用OOM Killer选择牺牲进程,Dropbear这种后台服务经常首当其冲。

排查方法:串口查看日志,看是否有Out of memory或者Killed process字样。如果真是这个原因,有几个解决方向:

一是限制连接数,用-C参数控制最大并发连接数。每个SSH连接会fork出一个子进程,每个子进程都要分配pty、buffer,内存开销不小。二是严格控制密码认证失败重试次数,防止暴力破解拖垮CPU和内存。三是给dropbear进程设置一个好的OOMScoreAdj值,让它比业务进程更晚被杀。这里有个取舍:你想让它活着来远程排障,但又不能让它抢了关键业务进程的资源,一般建议设置OOMScoreAdjust=0,让系统默认策略处理。

7.2 熵源不足导致密钥生成卡死的规避方案

嵌入式设备还有一个隐蔽问题:缺乏足够熵源。SSH的密钥交换和主机密钥生成都需要随机数。如果系统的熵池空了,相关操作会阻塞等待。表现就是设备刚上电,dropbear启动正常,但一有客户端连接,握手过程卡住几分钟才完成。

解决方式有几招:

第一,如果内核支持CONFIG_RANDOM_TRUST_CPU或者有硬件随机数生成器(比如ARM的CC500/CC510),确保相关驱动加载。第二,如果没有硬件熵源,可以在启动早期用busybox的seedrng或者写脚本把复位前的随机状态写回/dev/urandom。第三,dropbear在生成主机密钥时也会消耗熵,所以最好在出厂阶段就把主机密钥生成好,固化到Flash里,避免每台设备在首次启动时现场生成。

很多量产方案中,烧录rootfs时已经预置好主机密钥,这是最省心和最安全的方式,前提是每个设备要不同密钥。如果整个rootfs的镜像完全相同,所有设备的主机密钥也一样,那就危险了——攻击者拿到一个设备就能伪造所有设备。务必保证每台设备生成独立的密钥,然后再加密烧录。

7.3 文件系统类型对密钥和权限的影响

嵌入式rootfs常用squashfs这类只读文件系统,/etc目录只读,写不进去。这种情况下,不要尝试把主机密钥或authorized_keys放到/etc/dropbear,而是规划一个可写数据分区,比如/data、/var。启动脚本里要处理好“目录不存在则创建”的逻辑,避免首次启动时密钥目录没建好导致服务失败。

如果是vfat这类不支持完整Unix权限的Flash分区,权限检查会出问题。此时可以把密钥直接放在这类分区的隐藏目录里,但要理解权限形同虚设的现实。更好的做法还是用ext4、jffs2、ubifs等支持权限和属主的文件系统,系统完整性和安全性能得到保障。

8. 结合VSCode与Remote-SSH的远程开发体验

最后聊点开发体验层面的东西。嵌入式开发最头疼的一点是,交叉编译没问题,但运行时调试只能到设备上敲命令。如果能在VSCode里直接打开设备上的代码目录、执行远程终端命令、查看日志,效率提升是立竿见影的。

Remote-SSH插件默认会尝试调用系统里的ssh命令。如果你的Linux开发机本身有OpenSSH客户端,以及开发机到设备之间需要连接,但不想暴露22端口,这边有个配置技巧:可以在~/.ssh/config里定义别名主机,指定ConnectionPort为2222、指定连接命令为dbclient,或者更推荐的做法是保持OpenSSH客户端,只改端口和用户:

Host mydevice HostName 192.168.1.100 Port 2222 User root IdentityFile ~/.ssh/id_ed25519

不过OpenSSH客户端本身只是一个二进制,真正连接时它内部实现了SSH协议,不能直接用Dropbear的dbclient替代,所以上述配置在OpenSSH客户端下没有问题。如果开发机上只有dbclient,那VSCode Remote-SSH目前没法直接用dbclient作为底层连接器,建议开发机上同时装好OpenSSH客户端,这套组合最稳。

另外,VSCode Remote-SSH第一次连接设备时,会自动下载一个server组件到远端。嵌入式设备如果空间太小,可能安装失败。解决办法是用Remote-SSH的Local Server模式,或者干脆在设备上手工部署精简版的vscode-server,这个属于另一个话题了。单纯想看远程日志、改配置、跑命令的话,dbclient完全可以覆盖,不一定非要VSCode。

9. 关于安全加固的一些实战心得

SSH服务一旦暴露在网络上,就是持续被扫描的目标。尽管嵌入式设备很多在内网,但也不排除某些设备直接上公网,或者Wi-Fi网络被攻破后横向渗透。安全加固这个话题,我在项目里总结了几条原则,不一定全面,但每一条都踩过坑。

第一,默认不要开root密码登录。改成公钥认证并在dropbear启动时带-s。如果必须开密码,建议配合fail2ban之类的防护策略,但嵌入式环境装fail2ban比较重,不如直接禁用密码。第二,监听地址尽量收敛,只监听管理网段的接口。第三,在防火墙上限制源IP,如果管理端IP固定,直接白名单。第四,日志集中收集。Dropbear默认的日志走syslog,可以把所有登录日志转发到中心的日志服务器上。一台设备被攻击了不可怕,可怕的是你都不知道它被攻击了。

还有一条:注意OpenSSH客户端连接嵌入式设备时的known_hosts问题。嵌入式设备重刷系统后主机密钥变化,但客户端known_hosts还记录着旧指纹,就会拒绝连接。此时不要盲目清了known_hosts完事,要先确认设备确实是自己人,再删旧指纹。我一个同事就是没确认,连错了别的环境,深夜线上事故教育深刻。

最后再分享一个小习惯:Dropbear的版本要跟上游保持同步,哪怕嵌入式板块更新周期长。老版本有公开漏洞的概率远高于新版本。一般半年或一年集中升级一次,编译打包流程固定后成本并不高。

这篇文章很长了,写到这里,核心内容已经完整:从协议原理、源码编译、部署配置,到远程管理、密钥安全、批量运维、故障排查,基本覆盖了嵌入式Linux世界里用到Dropbear的绝大多数场景。老实说,工具本身不复杂,但要想在一个资源有限的设备上把SSH运维链路做到稳定可靠,需要考量的维度确实很多。希望这些经验和踩坑记录能帮你少走几步弯路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询