fix: keep RDP creds out of tunnel URL/logs via single-use encrypted stash
This commit is contained in:
+3
-1
@@ -56,7 +56,9 @@ func main() {
|
||||
}()
|
||||
|
||||
// Start REST server
|
||||
r := gin.Default()
|
||||
r := gin.New()
|
||||
r.Use(gin.Recovery())
|
||||
r.Use(gin.LoggerWithConfig(gin.LoggerConfig{SkipPaths: []string{"/api/console/tunnel"}}))
|
||||
r.Use(corsMiddleware())
|
||||
api.RegisterRoutes(r)
|
||||
|
||||
|
||||
@@ -44,6 +44,13 @@ func consoleConnect(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if body.Protocol == "rdp" && (body.RDPUsername != "" || body.RDPPassword != "") {
|
||||
if err := services.StashConsoleRDPCreds(sess.SessionID, body.RDPUsername, body.RDPPassword); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
services.LogEvent("console.opened", actorFromCtx(c), srv.ServerID, "",
|
||||
"console session opened ("+body.Protocol+")")
|
||||
|
||||
@@ -83,10 +90,15 @@ func consoleTunnel(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// RDP creds are single-use, passed via the connect step into the session
|
||||
// document is avoided; instead they are re-supplied here as query params
|
||||
// over the already-authenticated WS token. For ssh they are empty.
|
||||
gp, err := services.BuildGuacParams(srv, sess.Protocol, privKey, c.Query("u"), c.Query("p"))
|
||||
var rdpUser, rdpPass string
|
||||
if sess.Protocol == "rdp" {
|
||||
rdpUser, rdpPass, err = services.ConsumeConsoleRDPCreds(sessionID)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "could not load credentials"})
|
||||
return
|
||||
}
|
||||
}
|
||||
gp, err := services.BuildGuacParams(srv, sess.Protocol, privKey, rdpUser, rdpPass)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
|
||||
@@ -16,4 +16,7 @@ type ConsoleSession struct {
|
||||
StartedAt time.Time `bson:"started_at" json:"started_at"`
|
||||
EndedAt *time.Time `bson:"ended_at,omitempty" json:"ended_at,omitempty"`
|
||||
ClientIP string `bson:"client_ip,omitempty" json:"client_ip,omitempty"`
|
||||
|
||||
RDPUserEnc string `bson:"rdp_user_enc,omitempty" json:"-"`
|
||||
RDPPassEnc string `bson:"rdp_pass_enc,omitempty" json:"-"`
|
||||
}
|
||||
|
||||
@@ -150,6 +150,56 @@ func GetConsoleSession(sessionID string) (*models.ConsoleSession, error) {
|
||||
return &s, nil
|
||||
}
|
||||
|
||||
// StashConsoleRDPCreds encrypts and stores single-use RDP credentials on the
|
||||
// session document. They are consumed (and cleared) when the tunnel opens.
|
||||
func StashConsoleRDPCreds(sessionID, username, password string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
u, err := encryptString(username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p, err := encryptString(password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = db.Col("console_sessions").UpdateOne(ctx,
|
||||
bson.M{"session_id": sessionID},
|
||||
bson.M{"$set": bson.M{"rdp_user_enc": u, "rdp_pass_enc": p}},
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
// ConsumeConsoleRDPCreds decrypts and returns the stored RDP credentials, then
|
||||
// clears them from the session document (single-use). Returns empty strings if
|
||||
// none were stored.
|
||||
func ConsumeConsoleRDPCreds(sessionID string) (username, password string, err error) {
|
||||
s, err := GetConsoleSession(sessionID)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
if s.RDPUserEnc == "" && s.RDPPassEnc == "" {
|
||||
return "", "", nil
|
||||
}
|
||||
if s.RDPUserEnc != "" {
|
||||
if username, err = decryptString(s.RDPUserEnc); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
}
|
||||
if s.RDPPassEnc != "" {
|
||||
if password, err = decryptString(s.RDPPassEnc); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
_, _ = db.Col("console_sessions").UpdateOne(ctx,
|
||||
bson.M{"session_id": sessionID},
|
||||
bson.M{"$unset": bson.M{"rdp_user_enc": "", "rdp_pass_enc": ""}},
|
||||
)
|
||||
return username, password, nil
|
||||
}
|
||||
|
||||
func EndConsoleSession(sessionID string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
Reference in New Issue
Block a user