-
-
Notifications
You must be signed in to change notification settings - Fork 7.3k
Database ssl support #6371
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Database ssl support #6371
Changes from all commits
9179898
99460e4
46c6c10
35e7e2c
9a79400
a5826ff
1f9c75f
55bac49
07fc4a5
b3f8f46
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -165,7 +165,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Read the database config | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @throws {Error} If the config is invalid | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @typedef {string|undefined} envString | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @returns {{type: "sqlite"} | {type:envString, hostname:envString, port:envString, database:envString, username:envString, password:envString}} Database config | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @returns {{type: "sqlite"} | {type:envString, hostname:envString, port:envString, database:envString, username:envString, password:envString, ssl:boolean, ssl_ca:envString}} Database config | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| static readDBConfig() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let dbConfig; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -185,13 +185,37 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @typedef {string|undefined} envString | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param {{type: "sqlite"} | {type:envString, hostname:envString, port:envString, database:envString, username:envString, password:envString}} dbConfig the database configuration that should be written | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param {{type: "sqlite"} | {type:envString, hostname:envString, port:envString, database:envString, username:envString, password:envString, ssl:boolean, ssl_ca:envString}} dbConfig the database configuration that should be written | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @returns {void} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| static writeDBConfig(dbConfig) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fs.writeFileSync(path.join(Database.dataDir, "db-config.json"), JSON.stringify(dbConfig, null, 4)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Conditionally generates the MySQL SSL configuration object. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param {{type: "sqlite"} | {type:envString, hostname:envString, port:envString, database:envString, username:envString, password:envString, ssl:boolean, ssl_ca:envString}} dbConfig the database configuration | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @returns {{ssl: object} | undefined} An object containing the ssl configuration, or undefined if SSL is not enabled. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| static getSslConfig(dbConfig) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!dbConfig.ssl) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return undefined; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const sslOptions = {}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (dbConfig.ssl_ca) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sslOptions.ca = fs.readFileSync(dbConfig.ssl_ca, "utf8"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Check failureCode scanning / CodeQL Uncontrolled data used in path expression High
This path depends on a
user-provided value Error loading related location Loading |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log.warn("db", `Failed to read CA file from ${dbConfig.ssl_ca}: ${error.message}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sslOptions.rejectUnauthorized = false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+210
to
+211
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log.warn("db", `Failed to read CA file from ${dbConfig.ssl_ca}: ${error.message}`); | |
| sslOptions.rejectUnauthorized = false; | |
| log.error("db", `Failed to read CA file from ${dbConfig.ssl_ca}: ${error.message}`); | |
| throw new Error(`Failed to read database SSL CA file from ${dbConfig.ssl_ca}: ${error.message}`); |
Copilot
AI
Dec 23, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Security concern: When SSL is enabled but no CA certificate path is provided, the code defaults to rejectUnauthorized: false, which disables certificate verification. This approach is insecure by default.
Consider implementing one of these safer alternatives:
- Default to
rejectUnauthorized: true(use system CA bundle) and only set it to false if explicitly configured via a separate environment variable likeUPTIME_KUMA_DB_SSL_REJECT_UNAUTHORIZED=false - Require the CA certificate path when SSL is enabled, failing the connection if neither CA nor an explicit opt-out is provided
The current behavior means users enabling SSL thinking they're securing their connection are actually vulnerable to MITM attacks unless they also provide a CA certificate.
| if (dbConfig.ssl_ca) { | |
| try { | |
| sslOptions.ca = fs.readFileSync(dbConfig.ssl_ca, "utf8"); | |
| } catch (error) { | |
| log.warn("db", `Failed to read CA file from ${dbConfig.ssl_ca}: ${error.message}`); | |
| sslOptions.rejectUnauthorized = false; | |
| } | |
| } else { | |
| sslOptions.rejectUnauthorized = false; | |
| } | |
| // Default to secure behavior: verify certificates unless explicitly disabled. | |
| let rejectUnauthorized = true; | |
| const rejectEnv = process.env.UPTIME_KUMA_DB_SSL_REJECT_UNAUTHORIZED; | |
| if (typeof rejectEnv === "string" && rejectEnv.toLowerCase() === "false") { | |
| rejectUnauthorized = false; | |
| } | |
| if (dbConfig.ssl_ca) { | |
| try { | |
| sslOptions.ca = fs.readFileSync(dbConfig.ssl_ca, "utf8"); | |
| } catch (error) { | |
| log.warn("db", `Failed to read CA file from ${dbConfig.ssl_ca}: ${error.message}`); | |
| } | |
| } | |
| sslOptions.rejectUnauthorized = rejectUnauthorized; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Documentation: The JSDoc @typedef is defined inline but should be placed outside the function parameter documentation for better readability and reusability. Additionally, the complex type definition for dbConfig is duplicated across multiple methods. Consider defining a proper typedef once at the class level or file level and reusing it.
For example:
This same typedef appears to be duplicated in lines 169, 189, and 198.