Files
trufflehog/pkg/detectors/jdbc/sqlserver.go
Muneeb Ullah Khan 116e717154
Lint / golangci-lint (push) Waiting to run
Lint / semgrep (push) Waiting to run
Release / Release (push) Waiting to run
Scan for secrets / test (push) Waiting to run
Test / test (push) Waiting to run
Test / test-community (push) Waiting to run
[INS-243] Fix jdbc detector detecting incomplete connection string and fixed invalid… (#4636)
* Fix jdbc detector detecting incomplete conn string and fixed invalid parsing of sql server string

* [INS-165] Jdbc detector integration tests fix (#4637)

* [INS-165] Fix Jdbc tests and updated the deprecated code
2026-01-16 15:18:40 +05:00

124 lines
3.2 KiB
Go

package jdbc
import (
"context"
"errors"
"fmt"
"strings"
logContext "github.com/trufflesecurity/trufflehog/v3/pkg/context"
mssql "github.com/microsoft/go-mssqldb"
)
type SqlServerJDBC struct {
ConnectionInfo
}
var _ JDBC = (*SqlServerJDBC)(nil)
func (s *SqlServerJDBC) ping(ctx context.Context) pingResult {
return ping(ctx, "mssql", isSqlServerErrorDeterminate,
buildSQLServerConnectionString(s.Host, s.User, s.Password, "master", map[string]string{"connection+timeout": "5"}))
}
func (s *SqlServerJDBC) GetDBType() DatabaseType {
return SQLServer
}
func (s *SqlServerJDBC) GetConnectionInfo() *ConnectionInfo {
return &s.ConnectionInfo
}
func (s *SqlServerJDBC) BuildConnectionString() string {
return buildSQLServerConnectionString(s.Host, s.User, s.Password, s.Database, s.Params)
}
func isSqlServerErrorDeterminate(err error) bool {
// Error numbers from https://learn.microsoft.com/en-us/sql/relational-databases/errors-events/database-engine-events-and-errors?view=sql-server-ver16
var sqlErr mssql.Error
if errors.As(err, &sqlErr) {
switch sqlErr.Number {
case 18456:
// Login failed
// This is a determinate failure iff we tried to use a real user
return sqlErr.Message != "login error: Login failed for user ''."
}
}
return false
}
func parseSqlServer(ctx logContext.Context, subname string) (JDBC, error) {
if !strings.HasPrefix(subname, "//") {
return nil, errors.New("expected connection to start with //")
}
conn := strings.TrimPrefix(subname, "//")
port := "1433"
user := "sa"
database := "master"
var password, host string
params := make(map[string]string)
for i, param := range strings.Split(conn, ";") {
key, value, found := strings.Cut(param, "=")
if !found && i == 0 {
// String connectionUrl = "jdbc:sqlserver://<server>:<port>;encrypt=true;databaseName=AdventureWorks;user=<user>;password=<password>";
if split := strings.Split(param, ":"); len(split) > 1 {
host = split[0]
port = split[1]
} else {
host = param
}
continue
}
// incase there is a bridge between jdbc and some driver like "odbc", and conn string looks like this odbc:server
if split := strings.Split(key, ":"); len(split) > 1 {
key = split[1]
}
switch strings.ToLower(key) {
case "password", "spring.datasource.password", "pwd":
password = value
case "server":
host = value
case "port":
port = value
case "user", "uid", "user id", "userid":
user = value
case "database", "databasename":
database = value
default:
params[key] = value
}
}
if password == "" || host == "" {
ctx.Logger().WithName("jdbc").
V(2).
Info("Skipping invalid SQL Server URL - no password or host found")
return nil, fmt.Errorf("missing host or password in connection string")
}
return &SqlServerJDBC{
ConnectionInfo: ConnectionInfo{
Host: host + ":" + port,
User: user,
Password: password,
Database: database,
Params: params,
},
}, nil
}
func buildSQLServerConnectionString(host, user, password, database string, params map[string]string) string {
conn := fmt.Sprintf("sqlserver://%s:%s@%s?database=%s", user, password, host, database)
if len(params) > 0 {
for k, v := range params {
conn += fmt.Sprintf("&%s=%s", k, v)
}
}
return conn
}