mirror of
https://github.com/rustfs/rustfs.git
synced 2026-07-26 16:28:15 +00:00
fix(protocols): use constant-time secret comparison in FTPS and WebDAV auth (#4403)
The FTPS and WebDAV authentication handlers compared the client-supplied secret key against the stored secret with `String::eq`, which short-circuits on the first differing byte. A network attacker who knows (or enumerates) a valid access key can recover the secret key byte-by-byte via response-timing analysis; neither path is rate limited. Switch both to a constant-time comparison using `subtle::ConstantTimeEq`, the same primitive the SFTP handler and `rustfs/src/auth.rs::constant_time_eq` already use. `subtle` is added to the `ftps` and `webdav` feature dependency sets (it was previously gated on `sftp` only). Addresses GHSA-3p3x-734c-h5vx.
This commit is contained in:
@@ -27,7 +27,7 @@ categories = ["network-programming", "filesystem"]
|
||||
|
||||
[features]
|
||||
default = []
|
||||
ftps = ["dep:libunftp", "dep:unftp-core", "dep:rustls", "dep:rustfs-tls-runtime"]
|
||||
ftps = ["dep:libunftp", "dep:unftp-core", "dep:rustls", "dep:rustfs-tls-runtime", "dep:subtle"]
|
||||
swift = [
|
||||
"dep:rustfs-keystone",
|
||||
"dep:rustfs-ecstore",
|
||||
@@ -53,7 +53,7 @@ swift = [
|
||||
"dep:base64",
|
||||
"dep:async-compression",
|
||||
]
|
||||
webdav = ["dep:dav-server", "dep:hyper", "dep:hyper-util", "dep:http-body-util", "dep:tokio-rustls", "dep:base64", "dep:rustls", "dep:percent-encoding", "dep:rustfs-tls-runtime"]
|
||||
webdav = ["dep:dav-server", "dep:hyper", "dep:hyper-util", "dep:http-body-util", "dep:tokio-rustls", "dep:base64", "dep:rustls", "dep:percent-encoding", "dep:rustfs-tls-runtime", "dep:subtle"]
|
||||
sftp = ["dep:russh", "dep:russh-sftp", "dep:uuid", "dep:subtle", "dep:tokio-util", "dep:socket2"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -26,6 +26,7 @@ use std::net::IpAddr;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use subtle::ConstantTimeEq;
|
||||
use tokio::sync::broadcast;
|
||||
use tokio::sync::watch;
|
||||
use tracing::{debug, error, info, warn};
|
||||
@@ -464,7 +465,15 @@ impl Authenticator for FtpsAuthenticator {
|
||||
AuthenticationError::BadUser
|
||||
})?;
|
||||
|
||||
if !identity.credentials.secret_key.eq(&s3_creds.secret_key) {
|
||||
// Constant-time secret comparison to prevent timing side-channel
|
||||
// attacks. Same primitive used by the SFTP handler and rustfs/src/auth.rs.
|
||||
let secret_matches: bool = identity
|
||||
.credentials
|
||||
.secret_key
|
||||
.as_bytes()
|
||||
.ct_eq(s3_creds.secret_key.as_bytes())
|
||||
.into();
|
||||
if !secret_matches {
|
||||
warn!(
|
||||
event = EVENT_FTPS_AUTH_STATE,
|
||||
component = LOG_COMPONENT_PROTOCOLS,
|
||||
|
||||
@@ -32,6 +32,7 @@ use std::convert::Infallible;
|
||||
use std::net::IpAddr;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use subtle::ConstantTimeEq;
|
||||
use tokio::net::TcpListener;
|
||||
use tokio::sync::{broadcast, watch};
|
||||
use tokio_rustls::TlsAcceptor;
|
||||
@@ -441,7 +442,15 @@ where
|
||||
WebDavInitError::Server("User not found".to_string())
|
||||
})?;
|
||||
|
||||
if !identity.credentials.secret_key.eq(&s3_creds.secret_key) {
|
||||
// Constant-time secret comparison to prevent timing side-channel
|
||||
// attacks. Same primitive used by the SFTP handler and rustfs/src/auth.rs.
|
||||
let secret_matches: bool = identity
|
||||
.credentials
|
||||
.secret_key
|
||||
.as_bytes()
|
||||
.ct_eq(s3_creds.secret_key.as_bytes())
|
||||
.into();
|
||||
if !secret_matches {
|
||||
warn!(
|
||||
event = EVENT_WEBDAV_AUTH_STATE,
|
||||
component = LOG_COMPONENT_PROTOCOLS,
|
||||
|
||||
Reference in New Issue
Block a user