go-sql-driver / mysql

Go MySQL Driver is a MySQL driver for Go's (golang) database/sql package
https://pkg.go.dev/github.com/go-sql-driver/mysql
Mozilla Public License 2.0
14.45k stars 2.3k forks source link

ssl-ca param contains slash, which will cause errInvalidDSNUnescaped #1605

Closed shengjiangfeng closed 2 months ago

shengjiangfeng commented 2 months ago

Issue description

I want to use dsn in golang to connect mysql8.0.
My dsn is like admin:pwd@tcp(host:3306)/mysql?allowCleartextPasswords=true&ssl-ca=/tmp/bundle.pem. But get errInvalidDSNUnescaped error.

Example code


    dsn := fmt.Sprintf("%s:%s@tcp(%s)/mysql?allowCleartextPasswords=true&ssl-ca=%s",
        "rotateuser", authenticationToken, dbEndpoint, fmt.Sprintf("/tmp/%s-bundle.pem", "us-west-2"),
    )
    fmt.Println(dsn)

    db, err := sql.Open("mysql", dsn)

Error log

panic: invalid DSN: did you forget to escape a param value?

goroutine 1 [running]:
main.GetClient()
        /usr/local/src/pro/main.go:74 +0x39c
main.main()
        /usr/local/src/pro/main.go:84 +0x13
exit status 2

Configuration

*Driver version (or git SHA):1.8.1

*Go version:1.21

*Server version:MySQL 8.0

*Server OS: ubuntu:22.04

bug code go-sql-driver/mysql@v1.8.1/dsn.go

            // [protocol[(address)]]
            // Find the first '(' in dsn[j+1:i]
            for k = j + 1; k < i; k++ {
                if dsn[k] == '(' {
                    // dsn[i-1] must be == ')' if an address is specified
                    if dsn[i-1] != ')' {
                        if strings.ContainsRune(dsn[k+1:i], ')') {
                            return nil, errInvalidDSNUnescaped
                        }
                        return nil, errInvalidDSNAddr
                    }
                    cfg.Addr = dsn[k+1 : i-1]
                    break
                }
            }
            cfg.Net = dsn[j+1 : k]
        }
methane commented 2 months ago

https://github.com/go-sql-driver/mysql?tab=readme-ov-file#loc

Please keep in mind, that param values must be url.QueryEscape'ed. Alternatively you can manually replace the / with %2F. For example US/Pacific would be loc=US%2FPacific.

shengjiangfeng commented 2 months ago

I try to add url.QueryEscape(ssl-ca-path) , but i will get another x509 error. The dsn cannot parse ssl-ca path correctly.

new dsn is admin:pwd@tcp(host:3306)/mysql?tls=true&allowCleartextPasswords=true&ssl-ca=%2Ftmp%2Fbundle.pem

panic: tls: failed to verify certificate: x509: certificate signed by unknown authority
goroutine 1 [running]:
main.GetClient()
        /usr/local/src/pro/main.go:79 +0x399
main.main()
        /usr/local/src/pro/main.go:85 +0x13
exit status 2
shengjiangfeng commented 2 months ago

My env is in aws, i visit aurora-mysql use iam-role. The aws requires me to provide ssl-ca-path.

I know, this lib does not contain a param named ssl-ca, but how can i connect to mysql use ssl & ssl-ca ?

methane commented 2 months ago

https://pkg.go.dev/github.com/go-sql-driver/mysql?utm_source=godoc#Config

You can set tls.Config object to Config.TLS.

shengjiangfeng commented 2 months ago

Fixed, thanks very much!