sudo使用--stdin参数长时延迟后无法从标准输入获取密码问题
问题原因
这个行为差异本质是sudo安全校验机制和测试阶段的假象共同导致的:
- 把sleep设为1秒测试时的无交互效果根本不是传参生效:跑测试前你基本都在同一个终端里输过
sudo密码,sudo默认开启的tty_tickets机制会把认证凭据和当前终端绑定,默认缓存5到15分钟(macOS默认是5分钟)。缓存有效期内sudo根本不会读你通过--stdin传的密码,直接用缓存就过了校验,很容易误以为传参逻辑没问题。 - 把sleep设为4天的时候,时间长度早就超过了凭据缓存的最大有效期,这时候
sudo需要真的校验传入的密码,就会触发两层安全拦截:sudo本身会校验密码输入的交互属性,你用<<<here-string传的内容属于非交互重定向输入,如果对应终端长达数小时没有用户主动输入、或者中间系统经历过锁屏、休眠、唤醒流程,sudo会直接判定这个输入源不可信,忽略--stdin收到的内容,强制要求用户直接在终端手动输密码。- macOS自带的TCC安全框架会给长期没拿到前台焦点的终端进程降权,这类进程调用
sudo申请root权限时,非交互的密码输入通道会被直接拦截,只认用户手动在终端敲的密码,就算你把明文密码直接写在变量里传进去也没用。
解决方案
- 最稳定的方案是修改sudoers配置,给要执行的命令开启免密权限。直接执行
sudo visudo打开配置文件,在末尾添加对应规则:
配置完成后执行对应命令完全不需要输入密码,也不会弹出交互提示,等待时长、系统休眠都不会影响执行效果。你的系统用户名 ALL=(ALL) NOPASSWD: /usr/bin/head /etc/hosts - 如果一定要保留从钥匙串读取密码的逻辑,不要用
--stdin加here-string的写法,换expect工具模拟真实tty交互输入密码,能绕开sudo对非交互输入的检测。 - 不建议用前台挂脚本sleep数天的方式跑周期任务,macOS下可以用launchd配置定时触发规则,配合上述sudo免密配置,稳定性远高于前台挂脚本运行。
内容的提问来源于stack exchange,提问作者jack
相关产品推荐
相关产品推荐

