or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-features.mdbasic-connectivity.mdcopy-operations.mddatasource.mdindex.mdlarge-objects.mdpostgresql-types.mdreplication.mdresultset.mdssl-security.mdstatement-execution.mdtransactions.md

ssl-security.mddocs/

0

# SSL/TLS Security

1

2

This document covers SSL/TLS configuration for secure database connections, including SSL modes, certificate management, and custom SSL factories.

3

4

## Capabilities

5

6

### SSL Modes

7

8

PostgreSQL JDBC driver supports multiple SSL security levels.

9

10

```java { .api }

11

package org.postgresql.jdbc;

12

13

/**

14

* SSL connection modes controlling security level.

15

*/

16

public enum SslMode {

17

/**

18

* Do not use SSL encryption.

19

* Connection is unencrypted.

20

*/

21

DISABLE,

22

23

/**

24

* Try non-SSL connection first.

25

* If server requires SSL, upgrade to SSL connection.

26

* Not recommended for security.

27

*/

28

ALLOW,

29

30

/**

31

* Try SSL connection first (default).

32

* If server doesn't support SSL, fallback to non-SSL.

33

* Provides encryption if available.

34

*/

35

PREFER,

36

37

/**

38

* Require SSL connection.

39

* Fail if server doesn't support SSL.

40

* Does NOT verify server certificate.

41

*/

42

REQUIRE,

43

44

/**

45

* Require SSL with server certificate verification.

46

* Verifies certificate is signed by trusted CA.

47

* Does NOT verify hostname.

48

*/

49

VERIFY_CA,

50

51

/**

52

* Require SSL with full certificate verification.

53

* Verifies certificate AND hostname match.

54

* Most secure mode.

55

*/

56

VERIFY_FULL;

57

58

/**

59

* Returns whether this mode requires an encrypted connection.

60

*

61

* @return true if REQUIRE or higher (VERIFY_CA, VERIFY_FULL)

62

*/

63

public boolean requireEncryption();

64

65

/**

66

* Returns whether this mode verifies the server certificate.

67

*

68

* @return true for VERIFY_CA or VERIFY_FULL

69

*/

70

public boolean verifyCertificate();

71

72

/**

73

* Returns whether this mode verifies the server hostname matches the certificate.

74

*

75

* @return true only for VERIFY_FULL

76

*/

77

public boolean verifyPeerName();

78

79

/**

80

* Parses SSL mode from connection properties.

81

* Falls back to checking the 'ssl' property if 'sslmode' is not set.

82

*

83

* @param info Connection properties

84

* @return SslMode enum constant

85

* @throws PSQLException if sslmode value is invalid

86

*/

87

public static SslMode of(Properties info) throws PSQLException;

88

}

89

```

90

91

### GSSAPI Encryption Modes

92

93

PostgreSQL JDBC driver supports GSSAPI encryption (Kerberos-based encryption) as an alternative to SSL.

94

95

```java { .api }

96

package org.postgresql.jdbc;

97

98

/**

99

* GSSAPI encryption modes for Kerberos-based secure connections.

100

* Provides an alternative to SSL for environments using Kerberos authentication.

101

*/

102

public enum GSSEncMode {

103

/**

104

* Do not use GSSAPI encrypted connections.

105

*/

106

DISABLE,

107

108

/**

109

* Start with non-encrypted connection, then try encrypted one.

110

*/

111

ALLOW,

112

113

/**

114

* Start with encrypted connection, fallback to non-encrypted (default).

115

*/

116

PREFER,

117

118

/**

119

* Ensure connection is encrypted via GSSAPI.

120

*/

121

REQUIRE;

122

123

/**

124

* Returns whether this mode requires GSSAPI encryption.

125

*

126

* @return true if REQUIRE mode is set

127

*/

128

public boolean requireEncryption();

129

130

/**

131

* Parses GSSAPI encryption mode from connection properties.

132

* Falls back to ALLOW if gssEncMode is not set.

133

*

134

* @param info Connection properties

135

* @return GSSEncMode enum constant

136

* @throws PSQLException if gssEncMode value is invalid

137

*/

138

public static GSSEncMode of(Properties info) throws PSQLException;

139

}

140

```

141

142

**Configuration Examples:**

143

144

```java

145

import java.sql.Connection;

146

import java.sql.DriverManager;

147

import java.util.Properties;

148

149

// Example 1: SSL via URL

150

public class SSLURLExample {

151

public static Connection connectSSL() throws SQLException {

152

String url = "jdbc:postgresql://localhost:5432/mydb?ssl=true&sslmode=require";

153

return DriverManager.getConnection(url, "user", "password");

154

}

155

}

156

157

// Example 2: SSL via Properties

158

public class SSLPropertiesExample {

159

public static Connection connectSSL() throws SQLException {

160

String url = "jdbc:postgresql://localhost:5432/mydb";

161

Properties props = new Properties();

162

props.setProperty("user", "postgres");

163

props.setProperty("password", "secret");

164

props.setProperty("ssl", "true");

165

props.setProperty("sslmode", "verify-full");

166

return DriverManager.getConnection(url, props);

167

}

168

}

169

170

// Example 3: SSL via DataSource

171

public class SSLDataSourceExample {

172

public static Connection connectSSL() throws SQLException {

173

PGSimpleDataSource ds = new PGSimpleDataSource();

174

ds.setServerName("db.example.com");

175

ds.setDatabaseName("mydb");

176

ds.setUser("postgres");

177

ds.setPassword("secret");

178

ds.setSsl(true);

179

ds.setSslMode("verify-full");

180

return ds.getConnection();

181

}

182

}

183

```

184

185

### SSL Factories

186

187

Custom SSL socket factories for certificate management.

188

189

```java { .api }

190

package org.postgresql.ssl;

191

192

import javax.net.ssl.SSLSocketFactory;

193

194

/**

195

* Default SSL factory compatible with libpq certificate file locations.

196

* Looks for certificates in ~/.postgresql/ directory:

197

* - root.crt: trusted CA certificates

198

* - postgresql.crt: client certificate

199

* - postgresql.pk8: client private key (PKCS#8 format)

200

*/

201

public class LibPQFactory implements SSLSocketFactory {

202

// Automatically loads certificates from standard locations

203

}

204

205

/**

206

* SSL factory that does NOT validate server certificates.

207

* WARNING: Vulnerable to man-in-the-middle attacks.

208

* Only use for testing or when security is not required.

209

*/

210

public class NonValidatingFactory extends WrappedFactory {

211

/**

212

* Constructor accepting an optional argument.

213

* The argument is ignored but presence avoids reflection lookup overhead.

214

*

215

* @param arg Optional argument (ignored)

216

* @throws GeneralSecurityException if SSL context cannot be created

217

*/

218

public NonValidatingFactory(String arg) throws GeneralSecurityException;

219

}

220

221

/**

222

* SSL factory that validates against a single trusted certificate.

223

* More secure than NonValidatingFactory as it pins the server certificate.

224

* The certificate can be loaded from classpath, filesystem, environment variable, or inline.

225

*

226

* Configuration via sslfactoryarg connection property:

227

* - classpath:ssl/server.crt - Load from classpath

228

* - file:/path/to/server.crt - Load from filesystem

229

* - env:MYDB_CERT - Load from environment variable

230

* - sys:mydb.cert - Load from system property

231

* - No prefix - Inline PEM-encoded certificate

232

*/

233

public class SingleCertValidatingFactory extends WrappedFactory {

234

/**

235

* Constructor accepting certificate specification via sslfactoryarg.

236

*

237

* @param arg Certificate source specification (see class documentation)

238

* @throws GeneralSecurityException if certificate cannot be loaded or validated

239

*/

240

public SingleCertValidatingFactory(String arg) throws GeneralSecurityException;

241

}

242

243

/**

244

* SSL factory using Java's default SSL configuration.

245

* Uses system truststore (cacerts) and keystore.

246

* Always validates server certificate using Java's default truststore.

247

*/

248

public class DefaultJavaSSLFactory extends WrappedFactory {

249

/**

250

* Constructor using Java's default SSL socket factory.

251

*

252

* @param info Connection properties (unused)

253

*/

254

public DefaultJavaSSLFactory(Properties info);

255

}

256

257

/**

258

* Abstract base class for SSL factories using JKS keystore.

259

* Subclasses must implement getKeyStorePassword() and getKeyStoreStream().

260

* The keystore is used for both client certificates and trusted CAs.

261

*/

262

public abstract class DbKeyStoreSocketFactory extends WrappedFactory {

263

/**

264

* Constructor that loads and initializes the keystore.

265

*

266

* @throws DbKeyStoreSocketException if keystore cannot be loaded

267

*/

268

public DbKeyStoreSocketFactory() throws DbKeyStoreSocketException;

269

270

/**

271

* Returns the password for the keystore.

272

* Must be implemented by subclasses.

273

*

274

* @return Keystore password as char array

275

*/

276

public abstract char[] getKeyStorePassword();

277

278

/**

279

* Returns an InputStream for reading the keystore.

280

* Must be implemented by subclasses.

281

*

282

* @return InputStream for JKS keystore

283

*/

284

public abstract InputStream getKeyStoreStream();

285

286

/**

287

* Exception thrown when keystore operations fail.

288

*/

289

public static class DbKeyStoreSocketException extends Exception {

290

public DbKeyStoreSocketException(String message);

291

}

292

}

293

294

/**

295

* Custom hostname verifier for SSL connections.

296

*/

297

public class PGjdbcHostnameVerifier implements javax.net.ssl.HostnameVerifier {

298

@Override

299

public boolean verify(String hostname, javax.net.ssl.SSLSession session);

300

}

301

```

302

303

**Configuration Examples:**

304

305

```java

306

// Example 1: Using LibPQFactory (default)

307

public class LibPQFactoryExample {

308

public static Connection connectWithLibPQ() throws SQLException {

309

// Place certificates in ~/.postgresql/:

310

// - root.crt (trusted CA certificates)

311

// - postgresql.crt (client certificate)

312

// - postgresql.pk8 (client private key)

313

314

Properties props = new Properties();

315

props.setProperty("user", "postgres");

316

props.setProperty("password", "secret");

317

props.setProperty("ssl", "true");

318

props.setProperty("sslmode", "verify-full");

319

props.setProperty("sslfactory", "org.postgresql.ssl.LibPQFactory");

320

321

String url = "jdbc:postgresql://localhost/mydb";

322

return DriverManager.getConnection(url, props);

323

}

324

}

325

326

// Example 2: Using DefaultJavaSSLFactory

327

public class JavaSSLFactoryExample {

328

public static Connection connectWithJavaSSL() throws SQLException {

329

// Set JVM properties for truststore/keystore

330

System.setProperty("javax.net.ssl.trustStore", "/path/to/truststore.jks");

331

System.setProperty("javax.net.ssl.trustStorePassword", "password");

332

System.setProperty("javax.net.ssl.keyStore", "/path/to/keystore.jks");

333

System.setProperty("javax.net.ssl.keyStorePassword", "password");

334

335

Properties props = new Properties();

336

props.setProperty("user", "postgres");

337

props.setProperty("password", "secret");

338

props.setProperty("ssl", "true");

339

props.setProperty("sslmode", "verify-full");

340

props.setProperty("sslfactory", "org.postgresql.ssl.DefaultJavaSSLFactory");

341

342

String url = "jdbc:postgresql://localhost/mydb";

343

return DriverManager.getConnection(url, props);

344

}

345

}

346

347

// Example 3: NonValidatingFactory (testing only)

348

public class NonValidatingExample {

349

public static Connection connectWithoutValidation() throws SQLException {

350

// WARNING: Do not use in production!

351

Properties props = new Properties();

352

props.setProperty("user", "postgres");

353

props.setProperty("password", "secret");

354

props.setProperty("ssl", "true");

355

props.setProperty("sslfactory", "org.postgresql.ssl.NonValidatingFactory");

356

357

String url = "jdbc:postgresql://localhost/mydb";

358

return DriverManager.getConnection(url, props);

359

}

360

}

361

```

362

363

### Password Management

364

365

PostgreSQL JDBC driver provides a secure method to change user passwords.

366

367

```java { .api }

368

package org.postgresql;

369

370

/**

371

* Secure password change functionality (part of PGConnection interface).

372

*/

373

public interface PGConnection extends Connection {

374

/**

375

* Change a user's password to the specified new password.

376

*

377

* The password is encrypted locally before transmission, so the plain text

378

* password is never sent on the wire. This provides secure password changes

379

* even over non-SSL connections.

380

*

381

* If encryptionType is null, this method queries the database server for

382

* the server's default password_encryption setting.

383

*

384

* The newPassword array is automatically zeroed out after use for security.

385

*

386

* @param user The username of the database user

387

* @param newPassword The new password (will be zeroed after use)

388

* @param encryptionType Encryption type: "md5", "scram-sha-256", or null for server default

389

* @throws SQLException If the password could not be altered

390

* @since 42.2.0

391

*/

392

default void alterUserPassword(String user, char[] newPassword, String encryptionType)

393

throws SQLException;

394

}

395

```

396

397

**Usage Example:**

398

399

```java

400

import org.postgresql.PGConnection;

401

import java.sql.*;

402

403

public class PasswordManagementExample {

404

public static void changePassword(Connection conn, String username) throws SQLException {

405

// Unwrap to get PGConnection interface

406

PGConnection pgConn = conn.unwrap(PGConnection.class);

407

408

// New password as char array (more secure than String)

409

char[] newPassword = "newSecurePassword123!".toCharArray();

410

411

try {

412

// Use SCRAM-SHA-256 for maximum security (PostgreSQL 10+)

413

pgConn.alterUserPassword(username, newPassword, "scram-sha-256");

414

System.out.println("Password changed successfully for user: " + username);

415

} finally {

416

// Password array is automatically zeroed by the method

417

// No need to manually zero it

418

}

419

}

420

421

public static void changePasswordWithServerDefault(Connection conn, String username)

422

throws SQLException {

423

PGConnection pgConn = conn.unwrap(PGConnection.class);

424

425

char[] newPassword = "anotherSecurePassword!".toCharArray();

426

427

// Use null to let server decide encryption type (recommended)

428

pgConn.alterUserPassword(username, newPassword, null);

429

System.out.println("Password changed using server default encryption");

430

}

431

}

432

```

433

434

**Important Notes:**

435

436

- **Use `null` for encryptionType**: Recommended to use the server's default

437

- **Avoid "md5"**: Only use for legacy servers that don't support SCRAM-SHA-256

438

- **Use "scram-sha-256"**: Most secure option for PostgreSQL 10+

439

- **char[] vs String**: Password is passed as char[] for security (can be zeroed)

440

- **Automatic cleanup**: The method automatically zeros the password array after use

441

- **Local encryption**: Password is encrypted locally, never sent in plain text

442

- **Permissions required**: User must have ALTER USER privilege or be superuser

443

444

### Certificate Configuration

445

446

**Connection Properties:**

447

448

```java { .api }

449

/**

450

* SSL-related connection properties

451

*/

452

public class SSLProperties {

453

/**

454

* ssl - Enable SSL connection

455

* Values: true, false

456

* Default: false

457

*/

458

String ssl;

459

460

/**

461

* sslmode - SSL security mode

462

* Values: disable, allow, prefer, require, verify-ca, verify-full

463

* Default: prefer

464

*/

465

String sslmode;

466

467

/**

468

* sslfactory - SSL socket factory class

469

* Default: org.postgresql.ssl.LibPQFactory

470

*/

471

String sslfactory;

472

473

/**

474

* sslcert - Client certificate file path

475

* Default: ~/.postgresql/postgresql.crt

476

*/

477

String sslcert;

478

479

/**

480

* sslkey - Client private key file path

481

* Default: ~/.postgresql/postgresql.pk8

482

*/

483

String sslkey;

484

485

/**

486

* sslrootcert - Root certificate file path (trusted CAs)

487

* Default: ~/.postgresql/root.crt

488

*/

489

String sslrootcert;

490

491

/**

492

* sslpassword - Password for encrypted private key

493

*/

494

String sslpassword;

495

496

/**

497

* sslpasswordcallback - Callback class for password

498

*/

499

String sslpasswordcallback;

500

501

/**

502

* sslhostnameverifier - Custom hostname verifier class

503

*/

504

String sslhostnameverifier;

505

506

/**

507

* sslfactoryarg - Argument passed to SSL factory

508

*/

509

String sslfactoryarg;

510

}

511

```

512

513

**Usage Examples:**

514

515

```java

516

// Example 1: Custom certificate locations

517

public class CustomCertificates {

518

public static Connection connectWithCustomCerts() throws SQLException {

519

Properties props = new Properties();

520

props.setProperty("user", "postgres");

521

props.setProperty("password", "secret");

522

props.setProperty("ssl", "true");

523

props.setProperty("sslmode", "verify-full");

524

props.setProperty("sslcert", "/path/to/client.crt");

525

props.setProperty("sslkey", "/path/to/client.pk8");

526

props.setProperty("sslrootcert", "/path/to/ca.crt");

527

528

String url = "jdbc:postgresql://db.example.com/mydb";

529

return DriverManager.getConnection(url, props);

530

}

531

}

532

533

// Example 2: Encrypted private key

534

public class EncryptedKey {

535

public static Connection connectWithEncryptedKey() throws SQLException {

536

Properties props = new Properties();

537

props.setProperty("user", "postgres");

538

props.setProperty("password", "secret");

539

props.setProperty("ssl", "true");

540

props.setProperty("sslmode", "verify-full");

541

props.setProperty("sslkey", "/path/to/encrypted.pk8");

542

props.setProperty("sslpassword", "key-password");

543

544

String url = "jdbc:postgresql://localhost/mydb";

545

return DriverManager.getConnection(url, props);

546

}

547

}

548

```

549

550

### Certificate Formats

551

552

**Supported Formats:**

553

554

1. **Client Certificate**: X.509 PEM format (.crt, .pem)

555

```

556

-----BEGIN CERTIFICATE-----

557

...certificate data...

558

-----END CERTIFICATE-----

559

```

560

561

2. **Private Key**: PKCS#8 unencrypted or encrypted format (.pk8, .key)

562

```

563

-----BEGIN PRIVATE KEY-----

564

...key data...

565

-----END PRIVATE KEY-----

566

```

567

568

3. **Root Certificate**: X.509 PEM format with one or more CA certificates

569

```

570

-----BEGIN CERTIFICATE-----

571

...CA cert 1...

572

-----END CERTIFICATE-----

573

-----BEGIN CERTIFICATE-----

574

...CA cert 2...

575

-----END CERTIFICATE-----

576

```

577

578

**Converting Certificates:**

579

580

```bash

581

# Convert PKCS#1 to PKCS#8 (required format)

582

openssl pkcs8 -topk8 -inform PEM -outform PEM -in postgresql.key -out postgresql.pk8 -nocrypt

583

584

# Convert PKCS#12 to PEM

585

openssl pkcs12 -in cert.p12 -out postgresql.crt -clcerts -nokeys

586

openssl pkcs12 -in cert.p12 -out postgresql.key -nocerts -nodes

587

588

# Extract CA certificate

589

openssl s_client -connect db.example.com:5432 -starttls postgres < /dev/null | openssl x509 > root.crt

590

```

591

592

### Custom SSL Factory

593

594

Implementing a custom SSL factory:

595

596

```java

597

import javax.net.ssl.*;

598

import java.security.KeyStore;

599

import java.io.FileInputStream;

600

601

public class CustomSSLFactory extends SSLSocketFactory {

602

private SSLSocketFactory factory;

603

604

public CustomSSLFactory() throws Exception {

605

// Load truststore

606

KeyStore trustStore = KeyStore.getInstance("JKS");

607

try (FileInputStream fis = new FileInputStream("/path/to/truststore.jks")) {

608

trustStore.load(fis, "password".toCharArray());

609

}

610

611

// Create TrustManager

612

TrustManagerFactory tmf = TrustManagerFactory.getInstance(

613

TrustManagerFactory.getDefaultAlgorithm());

614

tmf.init(trustStore);

615

616

// Create SSLContext

617

SSLContext ctx = SSLContext.getInstance("TLS");

618

ctx.init(null, tmf.getTrustManagers(), null);

619

620

factory = ctx.getSocketFactory();

621

}

622

623

// Implement SSLSocketFactory methods delegating to factory

624

@Override

625

public Socket createSocket(String host, int port) throws IOException {

626

return factory.createSocket(host, port);

627

}

628

629

// ... other methods

630

}

631

632

// Usage

633

Properties props = new Properties();

634

props.setProperty("ssl", "true");

635

props.setProperty("sslfactory", "com.example.CustomSSLFactory");

636

```

637

638

### Security Best Practices

639

640

1. **Always use SSL in production**

641

```java

642

props.setProperty("ssl", "true");

643

props.setProperty("sslmode", "verify-full");

644

```

645

646

2. **Verify server certificates**

647

```

648

Use verify-full mode to prevent MITM attacks

649

```

650

651

3. **Protect private keys**

652

```

653

- Use file permissions (chmod 600)

654

- Encrypt keys with passwords

655

- Store in secure locations

656

```

657

658

4. **Use strong cipher suites**

659

```java

660

// Disable weak ciphers via JVM properties

661

System.setProperty("jdk.tls.disabledAlgorithms",

662

"SSLv3, RC4, DES, MD5withRSA, DH keySize < 2048");

663

```

664

665

5. **Rotate certificates regularly**

666

```

667

Implement certificate expiry monitoring

668

```

669

670

6. **Use certificate pinning for critical systems**

671

```java

672

// Implement custom SSLFactory with certificate pinning

673

```

674

675

7. **Monitor SSL configuration**

676

```java

677

// Log SSL connection details

678

Logger logger = Logger.getLogger("org.postgresql");

679

logger.setLevel(Level.FINE);

680

```

681

682

### Common SSL Configurations

683

684

**Development (localhost):**

685

```properties

686

ssl=false

687

```

688

689

**Testing (self-signed certs):**

690

```properties

691

ssl=true

692

sslmode=require

693

sslfactory=org.postgresql.ssl.NonValidatingFactory

694

```

695

696

**Production (CA-signed certs):**

697

```properties

698

ssl=true

699

sslmode=verify-full

700

sslrootcert=/path/to/ca-bundle.crt

701

```

702

703

**Production (client certificates):**

704

```properties

705

ssl=true

706

sslmode=verify-full

707

sslcert=/path/to/client.crt

708

sslkey=/path/to/client.pk8

709

sslrootcert=/path/to/ca-bundle.crt

710

```

711

712

**Cloud Providers (AWS RDS, Azure, GCP):**

713

```properties

714

ssl=true

715

sslmode=verify-full

716

# Download provider's CA certificate

717

sslrootcert=/path/to/provider-ca.crt

718

```

719