cossacklabs / acra

Database security suite. Database proxy with field-level encryption, search through encrypted data, SQL injections prevention, intrusion detection, honeypots. Supports client-side and proxy-side ("transparent") encryption. SQL, NoSQL.
https://www.cossacklabs.com/acra/
Apache License 2.0
1.33k stars 128 forks source link

Process sequence of pending packets #580

Closed Lagovas closed 1 year ago

Lagovas commented 1 year ago

What was the problem? DB drivers can send set of packets in one TCP packet. And usually, they are related to each other and look like Parse + Bind + Describe + Execute + Sync. Driver registers query in Parse, then binds data, then asks to describe types, executes query and commit state. Acra registers PreparedStatement on ParseComplete packet that DB responds to driver after validation and acceptance. Bind packet relates to Parse packet because it should specify statement name for which it sends values. In this flow acra do next: remembers Parse packet and save it as pendingParse. Then handle Bind packet, loads finds pendignParse and link them together.

Previously we expected that one set of packets in TCP packet contains only one packet with a query like SimpleQuery or Parse packet. And when Acra receives ParsePacket, it resets state, forgets about Bind and other kind of packets - https://github.com/cossacklabs/acra/blob/master/decryptor/postgresql/protocol.go#L121

But drivers not limited in the number of query packets. They can send several of them in one set. And they should be processed in same order. If acra got 2 Describe packets from driver to database and then receives 2 RowDescription responses from the database, it should link first RowDescription to the first Describe, second one to the second. So Acra should not store only last packet, but should all of them in same order.

In this PR was added new component that stores all pendingPackets and store them separately according to the type, works as a queue. And was refactored logic with working with pending packets. Now it removes item from the queue, not nilify a field.

Due to limitations of python's drivers that don't allow to compile such set of packets to write regression test, were added unit-test with dumped packets that reproduces the problem.

Checklist