Python调用subprocess使用sshpass时密码含特殊字符认证失败怎么办
问题场景
编写Python脚本实现从密码管理器API获取密码、自动创建SSH会话的功能,核心调用代码如下:
subprocess.call(['sshpass', '-p', password, 'ssh', '-l', username, url])
当密码包含特殊字符时(例如测试密码*jadKWI_3ekd}ad2+),脚本执行后SSH返回认证失败报错:
Permission denied, please try again.
直接在Shell中执行如下等价命令可以正常连接,无异常:
sshpass -p "*jadKWI_3ekd}ad2+" ssh url -l username
此前尝试使用Python原始字符串处理密码变量,没有解决问题。
问题根因
- 原始字符串方案无效是因为这里不存在Python字符串转义问题:
subprocess.call使用列表传参时默认shell=False,参数会直接传递给目标进程,不会经过Shell解析,*、}、+这类特殊字符不会被转义篡改。 - 最高概率的诱因是从密码管理器API获取的
password变量携带了不可见的首尾冗余字符:比如接口返回自带的尾部换行\n、回车符\r,这类字符会被sshpass计入密码内容,导致认证失败;手动在Shell执行命令时,引号包裹的密码不含这类冗余字符,因此可以正常连接。 - 次要诱因是sshpass通过
-p参数传递密码时,部分环境下存在参数解析边界问题,极端特殊字符组合可能出现截断。
解决方法
- 首先清理密码变量的冗余字符:从API拿到密码后,先移除尾部的换行、回车符,如果密码首尾没有合法空格,可直接全量strip:
# 密码首尾无合法空格时使用 password = password.strip() # 密码首尾可能存在合法空格时,仅移除换行回车 password = password.rstrip('\r\n')
- 替换sshpass的密码传递方式,放弃命令行
-p传参,改用环境变量传递密码,彻底规避参数解析问题,参考代码:
import os import subprocess # 复制当前环境变量,注入SSHPASS密码 run_env = os.environ.copy() run_env['SSHPASS'] = password subprocess.call( [ 'sshpass', '-e', 'ssh', '-o', 'StrictHostKeyChecking=no', # 可选,跳过首次连接主机密钥确认 '-l', username, url ], env=run_env )
sshpass -e参数会直接读取SSHPASS环境变量的值作为密码,全程不经过命令行参数解析,支持任意特殊字符的密码。
- 如果上述调整后仍认证失败,可给ssh添加
-tt参数强制分配伪终端,规避部分服务端因未检测到tty拒绝密码认证的问题:
subprocess.call( [ 'sshpass', '-e', 'ssh', '-tt', '-o', 'StrictHostKeyChecking=no', '-l', username, url ], env=run_env )
内容的提问来源于stack exchange,提问作者jozinko9
相关产品推荐
相关产品推荐

