Skip to content

Commit 0c6cf40

Browse files
committed
Improve TLS documentation for older servers
Older/EOL database server versions tend to be built with ancient OpenSSL or yaSSL, which lack support for modern cipher suites and/or lack TLS 1.2+. At the same time, recent Golang versions have updated the default client tls.Config in ways that are incompatible with these old server versions. This commit improves TLS documentation to mention this incompatibility, provide sample code for solving it, and explain how "preferred" plaintext fallback mode is not triggered in cases of TLS incompatibilities. Closes #1635 by providing example code for solving the handshake failure. Additional information which may be helpful for reviewers/maintainers: TLS version * Go 1.18+ changes the default client TLS MinVersion to be TLS 1.2 * MySQL 5.5 and 5.6 supports TLS 1.0 * MySQL 5.7.0-5.7.27 supports TLS 1.1 * MySQL 5.7.28+ supports TLS 1.2 * MariaDB 10.1+ supports TLS 1.2 * I did not examine MySQL 5.1 or MariaDB 10.0 or anything more ancient Cipher suites * Go 1.22+ changes the default client TLS config to remove cipher suites which use RSA key exchange * MySQL 8.0+ and MariaDB 10.2+ fully support ECDHE cipher suites and are compatible with Go's current default cipher suite list. * MySQL 5.x typically needs RSA key exchange cipher suites, due to https://bugs.mysql.com/bug.php?id=82935. Likewise for MariaDB 10.1. * There are some exceptions, for example Percona Server 5.7 is built with a newer OpenSSL, https://docs.percona.com/percona-server/5.7/security/ssl-improvement.html * It is also possible to custom compile MySQL 5.7 with a newer OpenSSL version to solve the cipher suite issue, but this is not common.
1 parent 7403860 commit 0c6cf40

File tree

2 files changed

+31
-2
lines changed

2 files changed

+31
-2
lines changed

README.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,11 @@ Valid Values: true, false
181181
Default: false
182182
```
183183

184-
`allowFallbackToPlaintext=true` acts like a `--ssl-mode=PREFERRED` MySQL client as described in [Command Options for Connecting to the Server](https://dev.mysql.com/doc/refman/5.7/en/connection-options.html#option_general_ssl-mode)
184+
`allowFallbackToPlaintext=true` permits fallback to an unencrypted connection if the server is not configured to use TLS. This behavior is enabled automatically when using `tls=preferred`, but it is also available as a separate parameter to allow plaintext fallback when using a custom TLS configuration.
185+
186+
Plaintext fallback only occurs if the server is not configured to use TLS at all. MySQL 5.7+ and MariaDB 11.4+ ship with TLS support pre-enabled by default using a self-signed server cert, so plaintext fallback typically won't occur with these server versions.
187+
188+
Setting `allowFallbackToPlaintext=true` does **not** allow plaintext fallback in situations where the server has TLS enabled but is incompatible with the client configuration's cipher suites or TLS version. In recent Golang versions, establishing an encrypted connection to older server versions (e.g. MySQL 5.x or MariaDB 10.1) often requires a custom TLS configuration which allows RSA key exchange cipher suites. Very old server versions also require reducing the client's minimum TLS version. See documentation for [`mysql.RegisterTLSConfig`](https://godoc.org/github.com/go-sql-driver/mysql#RegisterTLSConfig) for example code.
185189

186190
##### `allowNativePasswords`
187191

@@ -431,8 +435,9 @@ Valid Values: true, false, skip-verify, preferred, <name>
431435
Default: false
432436
```
433437

434-
`tls=true` enables TLS / SSL encrypted connection to the server. Use `skip-verify` if you want to use a self-signed or invalid certificate (server side) or use `preferred` to use TLS only when advertised by the server. This is similar to `skip-verify`, but additionally allows a fallback to a connection which is not encrypted. Neither `skip-verify` nor `preferred` add any reliable security. You can use a custom TLS config after registering it with [`mysql.RegisterTLSConfig`](https://godoc.org/github.com/go-sql-driver/mysql#RegisterTLSConfig).
438+
`tls=true` enables TLS / SSL encrypted connection to the server. Use `skip-verify` if you want to use a self-signed or invalid certificate (server side) or use `preferred` to use TLS only when advertised by the server. Using `tls=preferred` is equivalent to setting `tls=skip-verify&allowFallbackToPlaintext=true`, which permits fallback to an unencrypted connection if the server is not configured to use TLS at all. Neither `skip-verify` nor `preferred` add any reliable security. You can use a custom TLS config after registering it with [`mysql.RegisterTLSConfig`](https://godoc.org/github.com/go-sql-driver/mysql#RegisterTLSConfig).
435439

440+
In recent Golang versions, establishing an encrypted connection to older server versions (MySQL 5.x or MariaDB 10.1) often requires a custom TLS configuration, in order to allow RSA key exchange cipher suites and a lower minimum TLS version. See documentation for [`mysql.RegisterTLSConfig`](https://godoc.org/github.com/go-sql-driver/mysql#RegisterTLSConfig) for example code.
436441

437442
##### `writeTimeout`
438443

utils.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,33 @@ var (
4949
// log.Fatal(err)
5050
// }
5151
// clientCert = append(clientCert, certs)
52+
// cipherSuites := []uint16{
53+
// // These 10 are the normal Go 1.22+ defaults
54+
// tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
55+
// tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
56+
// tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
57+
// tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
58+
// tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
59+
// tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
60+
// tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
61+
// tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
62+
// tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
63+
// tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
64+
//
65+
// // These 4 use RSA key exchange, no longer included by default in Go 1.22+
66+
// // but often needed to connect to MySQL 5.7, MariaDB 10.1, or anything older
67+
// tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
68+
// tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
69+
// tls.TLS_RSA_WITH_AES_128_CBC_SHA,
70+
// tls.TLS_RSA_WITH_AES_256_CBC_SHA,
71+
// }
5272
// mysql.RegisterTLSConfig("custom", &tls.Config{
5373
// RootCAs: rootCertPool,
5474
// Certificates: clientCert,
75+
//
76+
// // Only include the following two lines when supporting older servers
77+
// CipherSuites: cipherSuites, // in Go 1.22+, allow TLS connection to MySQL 5.x or MariaDB 10.1 or older
78+
// MinVersion: tls.VersionTLS10, // in Go 1.18+, allow TLS connection to MySQL 5.6 or older
5579
// })
5680
// db, err := sql.Open("mysql", "user@tcp(localhost:3306)/test?tls=custom")
5781
func RegisterTLSConfig(key string, config *tls.Config) error {

0 commit comments

Comments
 (0)