fix(security): add SQL injection defense for CREATE DATABASE

Add quoteIdentifier() function to safely quote PostgreSQL identifiers
following PostgreSQL's quoting rules (wrap in double quotes, escape
internal quotes by doubling).

This provides defense-in-depth for the CREATE DATABASE statement,
complementing the existing validateDBName() input validation.

Changes:
- Add quoteIdentifier() function with proper escaping
- Use quoted identifier in CREATE DATABASE statement
- Add comprehensive unit tests for quoteIdentifier()
This commit is contained in:
User
2026-04-16 20:28:36 +08:00
parent c9992af876
commit db307b0d0f
2 changed files with 67 additions and 4 deletions

View File

@@ -87,3 +87,55 @@ func TestWriteConfigFileKeepsDefaultUserConcurrency(t *testing.T) {
t.Fatalf("config missing default user concurrency, got:\n%s", string(data))
}
}
func TestQuoteIdentifier(t *testing.T) {
t.Parallel()
tests := []struct {
name string
input string
expected string
}{
{
name: "simple name",
input: "mydb",
expected: `"mydb"`,
},
{
name: "name with underscore",
input: "my_db_123",
expected: `"my_db_123"`,
},
{
name: "name with double quote (injection attempt)",
input: `my"; DROP TABLE users; --`,
expected: `"my""; DROP TABLE users; --"`,
},
{
name: "name with multiple double quotes",
input: `my"db"test`,
expected: `"my""db""test"`,
},
{
name: "empty name",
input: "",
expected: `""`,
},
{
name: "name starting with number",
input: "123db",
expected: `"123db"`,
},
}
for _, tc := range tests {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
got := quoteIdentifier(tc.input)
if got != tc.expected {
t.Fatalf("quoteIdentifier(%q) = %q, want %q", tc.input, got, tc.expected)
}
})
}
}