Conversation
|
Strictly speaking, implementing TOFU would be the better fix and more in line with user expectations around SSH, but given that it would be more complex and user would have to touch their config anyway (to add persistent storage for the known hosts db) it didn't seem worth it to me. Let me know if you prefer that route. |
d0f6e7e to
ff2b617
Compare
|
For reference, there is a similar fix in this commit, which is not on the |
|
Because this is apparently getting some attention, I want to mention that I don't particularly care if this PR or the other commit end up being merged (though I still think reading the host keys from files adds unnecessary complexity). What I do think is important is to warn the user when host key checking is not done (which the other commit currently does not do). When using ssh, host key checking is the expectation and so we should at least make users aware that they are using a hijackable connection. Thanks for your work on this project! |
|
One more thing I remember now: The way both this PR and the other commit work, only the first host key offered by the server is checked. This means you have to use a specific host key (such as |
|
Hi @tribut, thank you so much for this PR! This is a really important security fix that addresses CVE-2024-41254/GHSA-qpgw-j75c-j585, and we really appreciate you taking the time to implement this. The implementation looks great:
This is excellent work! We have a few recommendations that would help round out the PR, but if you don't have the time, we're more than happy to take it from here and add these ourselves: 1. Test CoverageIt would be great to add a test case to func TestNewSFTPReplicaFromConfig(t *testing.T) {
t.Run("WithHostKey", func(t *testing.T) {
config := &main.ReplicaConfig{
URL: "sftp://user@example.com:22/path/to/backup",
HostKey: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMvvypUkBrS9RCyV//p+UFCLg8yKNtTu/ew/cV6XXAAP",
}
_, err := main.NewReplicaFromConfig(config, nil)
if err != nil {
t.Fatal(err)
}
// Note: We can't easily test the actual client fields without refactoring
// to export them or using reflection, but this tests that configuration parsing works
})
t.Run("WithoutHostKey", func(t *testing.T) {
config := &main.ReplicaConfig{
URL: "sftp://user@example.com:22/path/to/backup",
}
_, err := main.NewReplicaFromConfig(config, nil)
if err != nil {
t.Fatal(err)
}
})
t.Run("InvalidHostKey", func(t *testing.T) {
config := &main.ReplicaConfig{
URL: "sftp://user@example.com:22/path/to/backup",
HostKey: "invalid-key-format",
}
// This should succeed at config parsing level, error would occur during Init
_, err := main.NewReplicaFromConfig(config, nil)
if err != nil {
t.Fatal(err)
}
})
}2. Documentation ExampleIt would be helpful to update the example configuration in # - url: sftp://user@host:22/path # SFTP-based replication
# key-path: /home/user/.ssh/id_rsa
# # Optional: SSH host key for verification (recommended for security)
# # Get this from the server's /etc/ssh/ssh_host_*.pub file
# # Example formats:
# # host-key: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMvvypUkBrS9RCyV//p+UFCLg8yKNtTu/ew/cV6XXAAP
# # host-key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQ...3. Integration TestingIf you've had a chance to test this with an actual SFTP server, it would be great to know that:
Again, thank you for this excellent contribution! Please let us know if you'd like to add these suggestions yourself, or if you'd prefer we take care of them. Either way works perfectly for us - we're just excited to get this security fix merged! |
Review Summary & Status UpdateAfter reviewing this PR and analyzing the current codebase, I want to provide a status update on this important security fix: Current Situation
Analysis of Similar WorkThe referenced "similar commit" (f6c8590) from Jan 2022:
Why This PR Should Be Merged
Recommended Next Steps@tribut's implementation is excellent as-is. The suggestions from @corylanou above (tests, documentation) would make this production-ready. Timeline: We'll give this a week for any updates from @tribut. If there's no response by then, we're happy to:
Thank you @tribut for this important contribution! Please let us know if you'd like to complete the additions yourself, or if you'd prefer we take it from here. Either way works - we just want to ensure this security fix gets into the codebase. cc @benbjohnson @corylanou for visibility on this security fix status |
|
Hey, thanks for getting back on this. I can add both the documentation and tests as well as an updated implementation that avoids verifying the first ssh host key only (cf. #609 (comment)) sometime this week. |
|
Is this gonna land in 0.5.0, for which there's an RC out? |
Yes |
db73ad1 to
838bb45
Compare
|
Sorry this took a bit longer than promised. The AI generated suggestions in #609 (comment) didn't actually test the host key check. I've now added tests for both the configuration as well as checks for matching host key, invalid host key and no host key validation configured. Not sure where the source for https://litestream.io/reference/config/#sftp-replica lives, but we should definitely add an example there. |
838bb45 to
a29c7a6
Compare
|
✅ Manual integration tests have been run by @corylanou |
@corylanou seems like this didn't land in 0.5.0 after all? |
Sorry about that, we had a lot in the air and we needed to get a release with at least the current feature set. This will be one of the top things I work on as soon as we stabilize the current RC. Thanks for the efforts, they are greatly appreciated. We didn't forget you :-). |
Merged main branch into ssh-check-host-key feature branch. Resolved conflicts in main_test.go by preserving both TestNewSFTPReplicaFromConfig (from PR benbjohnson#609) and TestNewReplicaFromConfig_AgeEncryption (from main). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
|
Sorry for the delay on this! This looks great and it's merged in now. It'll go into v0.5.3. |
Allows specifying the SSH host key as follows:
(key can be found in
/etc/ssh/ssh_host_*.pubon the server)The change is backwards-compatible and fixes #602 (GHSA-qpgw-j75c-j585).
If there is interest in this patch, I can update the documentation accordingly.