Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

在 libgit2 后端中支持密钥保护的 SSH Key #334

Closed
Jisu-Woniu opened this issue Oct 11, 2024 · 3 comments · Fixed by #337
Closed

在 libgit2 后端中支持密钥保护的 SSH Key #334

Jisu-Woniu opened this issue Oct 11, 2024 · 3 comments · Fixed by #337

Comments

@Jisu-Woniu
Copy link

Jisu-Woniu commented Oct 11, 2024

问题描述

使用 SSH 克隆 resource 仓库时,如果使用了受密钥保护的私钥,会出现以下错误:

Error: failed to authenticate SSH session: Unable to extract public key from private key file: Wrong passphrase or invalid/unrecognized private key file format; class=Ssh (23)

原因分析

参考代码后,发现这处 git2 调用中将 passphrase 参数(第 4 个参数)设置成了 None

git2::Cred::ssh_key(username_from_url.unwrap(), None, ssh_key, None)

在一个简单测试中,发现只要增加可选的 passphrase 参数即可正常执行:

fn clone(
    url: &str,
    branch: Option<&str>,
    dest: &Path,
    ssh_key: Option<(&Path, Option<&str>)>, // (path, passphrase)
) -> Result<()> {
    let mut builder = RepoBuilder::new();

    if let Some(branch) = branch {
        builder.branch(branch);
    }

    if let Some((key_path, passphrase)) = ssh_key { // 匹配 passphrase
        let mut callbacks = git2::RemoteCallbacks::new();
        callbacks.credentials(move |_, username_from_url, _| {
            git2::Cred::ssh_key(username_from_url.unwrap(), None, key_path, passphrase) // 传入参数
        });

        // 以下不变
    }
    // ...
}

fn test() {
    // Some definitions ...

    clone(
        REPO_URL,
        None,
        DEST_PATH.as_ref(),
        Some((Path::new(MY_KEY_PATH), Some(MY_PASSPHRASE))),
    )?;
}

其他方案(workaround)

  1. 创建一个专用的无密码密钥,但是 GitHub 并无限制密钥使用范围的功能,因此(对于部分用户)有潜在安全风险
  2. 恢复使用 git 后端,因为其可以提示用户输入密钥
  3. 通过 HTTP 克隆
@wangl-cc
Copy link
Member

感谢反馈。

我的一个疑问是密码应该放在哪里,最简单的办法是在 Remote 相关设置里面加一个:

pub struct Remote {
/// URL to resource repository
#[serde(default = "default_url")]
url: String,
/// Branch of resource repository
#[serde(default)]
branch: Option<String>,
/// SSH key to access resource repository when fetch from SSH
#[serde(default)]
ssh_key: Option<PathBuf>,
}

但是明文把密码放在配置文件里面比创建一个无密码的密钥更不安全。或许我们可以在运行时询问用户,但是不知道 git 是如何判断一个 key 需不需要密码的。

另一个选择是使用 ssh-agent, 这样可以避免使用无密码密钥,同时不需要把密码明文存在任何地方。

@Jisu-Woniu
Copy link
Author

我在 StackExchange 上找到了一篇相关的回答:

https://security.stackexchange.com/a/129729

下方的评论中提到了:

The base64-encoded data does contain information about whether the key is encrypted, though: The first decodes to openssh-key-v1.....aes256-cbc....bcrypt.........v.. and the second decodes to openssh-key-v1.....none....none................ssh-

我使用的密钥符合这里的介绍。

@wangl-cc
Copy link
Member

wangl-cc commented Oct 16, 2024

现在你可以使用 ssh-agent 或者密码授权了,具体参见文档

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants