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.35k stars 127 forks source link

Question about poison records #667

Closed m8522s closed 10 months ago

m8522s commented 1 year ago

Not a bug, just a question. The documentation at https://docs.cossacklabs.com/acra/security-controls/intrusion-detection/#usage-example says: This key is generated either with acra-keys, or upon running poison record generation utility acra-pisonrecordmaker (but you will have to move the keys into AcraServer’s key storage manually).

acra-poisonrecordmaker generates a base64 string, which I insert into the database somewhere. But how and in which format does the keystore expects the base64 string? I am using the keystore v1. Thanks for clarification.

Lagovas commented 1 year ago

Nice catch.

(but you will have to move the keys into AcraServer’s key storage manually).

This row is not relevant and incorrect. We will remove it. acra-poisonrecordmaker generates poison record that you should place into your storage. If you didn't generate keys for poison records, this tool will generate it automatically. By default it will place it to .acrakeys folder using specified ACRA_MASTER_KEY. So, if you run acra-poisonrecord that configured to use acra-server's keystore, then you don't need to do anything more.

But you should keep in mind, that tool generates binary poison record encoded into the base64 to print it to stdout. But storages uses binary format. PostgreSQL uses bytea, MySQL BINARY/BLOB. So, you need decode base64 output and save into the db poison record in the binary format

m8522s commented 1 year ago

So I need to run acra-poisonrecordmaker, base64-decode the output and store it in the database? In case of MySQL, are the following commands the right way to place a poison record?

acra-poisonrecordmaker
JSUl2wAAAAAAAADxIiIiIiIiIiJVRUMyAAAALTls2DQDONAG1vIFH/KyTqZzUFXlHzPRN9rVxoREcOIsDh0i8ScgJwQmVAAAAAABAUAMAAAAEAAAACAAAADqxJKo+kJ9oNUn6bI9WKaPJSaIx1hm9TG7AtkzgBYyGJ1jaTNSlA385Rf7wGnNLPE+mpZhAldNc6cLn00+AAAAAAAAAAABAUAMAAAAEAAAABIAAABnESuzeVeVfsNUlsyRmA2ezKkOVpKRhvCzxv6NTAAxkafxOWdM119lnJw0ghT4
INSERT INTO users (user_id,password) VALUES (994, FROM_BASE64('JSUl2wAAAAAAAADxIiIiIiIiIiJVRUMyAAAALTls2DQDONAG1vIFH/KyTqZzUFXlHzPRN9rVxoREcOIsDh0i8ScgJwQmVAAAAAABAUAMAAAAEAAAACAAAADqxJKo+kJ9oNUn6bI9WKaPJSaIx1hm9TG7AtkzgBYyGJ1jaTNSlA385Rf7wGnNLPE+mpZhAldNc6cLn00+AAAAAAAAAAABAUAMAAAAEAAAABIAAABnESuzeVeVfsNUlsyRmA2ezKkOVpKRhvCzxv6NTAAxkafxOWdM119lnJw0ghT4'));
Lagovas commented 1 year ago

You didn't decode base64 output. If you want store in with INSERT query, then decode base64 to binary, then encode to hex:

echo -n 'JSUl2wAAAAAAAADxIiIiIiIiIiJVRUMyAAAALTls2DQDONAG1vIFH/KyTqZzUFXlHzPRN9rVxoREcOIsDh0i8ScgJwQmVAAAAAABAUAMAAAAEAAAACAAAADqxJKo+kJ9oNUn6bI9WKaPJSaIx1hm9TG7AtkzgBYyGJ1jaTNSlA385Rf7wGnNLPE+mpZhAldNc6cLn00+AAAAAAAAAAABAUAMAAAAEAAAABIAAABnESuzeVeVfsNUlsyRmA2ezKkOVpKRhvCzxv6NTAAxkafxOWdM119lnJw0ghT4' | base64 -d | xxd -ps -c 2000 | tr -d '\n'

You will get:

252525db00000000000000f12222222222222222554543320000002d396cd8340338d006d6f2051ff2b24ea6735055e51f33d137dad5c6844470e22c0e1d22f1272027042654000000000101400c0000001000000020000000eac492a8fa427da0d527e9b23d58a68f252688c75866f531bb02d933801632189d63693352940dfce517fbc069cd2cf13e9a966102574d73a70b9f4d3e00000000000000000101400c000000100000001200000067112bb37957957ec35496cc91980d9ecca90e56929186f0b3c6fe8d4c003191a7f139674cd75f659c9c348214f8

Then according to MySQL doc you can send it as hexadecimal literal:

INSERT INTO users (user_id,password) VALUES (994, FROM_BASE64(X'252525db00000000000000f12222222222222222554543320000002d396cd8340338d006d6f2051ff2b24ea6735055e51f33d137dad5c6844470e22c0e1d22f1272027042654000000000101400c0000001000000020000000eac492a8fa427da0d527e9b23d58a68f252688c75866f531bb02d933801632189d63693352940dfce517fbc069cd2cf13e9a966102574d73a70b9f4d3e00000000000000000101400c000000100000001200000067112bb37957957ec35496cc91980d9ecca90e56929186f0b3c6fe8d4c003191a7f139674cd75f659c9c348214f8'));
m8522s commented 1 year ago

Unfortunately the INSERT query returns an error:

ERROR 1958 (HY000): Bad base64 data as position 0

Can you provide a minimal working example? The documentation is all about creating the record and not about storing it in a database table. Thanks!

Lagovas commented 1 year ago

I missed that you example contained FROM_BASE64(...). Use you variant

INSERT INTO users (user_id,password) VALUES (994, FROM_BASE64('JSUl2wAAAAAAAADxIiIiIiIiIiJVRUMyAAAALTls2DQDONAG1vIFH/KyTqZzUFXlHzPRN9rVxoREcOIsDh0i8ScgJwQmVAAAAAABAUAMAAAAEAAAACAAAADqxJKo+kJ9oNUn6bI9WKaPJSaIx1hm9TG7AtkzgBYyGJ1jaTNSlA385Rf7wGnNLPE+mpZhAldNc6cLn00+AAAAAAAAAAABAUAMAAAAEAAAABIAAABnESuzeVeVfsNUlsyRmA2ezKkOVpKRhvCzxv6NTAAxkafxOWdM119lnJw0ghT4'));

or mine without FROM_BASE64

INSERT INTO users (user_id,password) VALUES (994, X'252525db00000000000000f12222222222222222554543320000002d396cd8340338d006d6f2051ff2b24ea6735055e51f33d137dad5c6844470e22c0e1d22f1272027042654000000000101400c0000001000000020000000eac492a8fa427da0d527e9b23d58a68f252688c75866f531bb02d933801632189d63693352940dfce517fbc069cd2cf13e9a966102574d73a70b9f4d3e00000000000000000101400c000000100000001200000067112bb37957957ec35496cc91980d9ecca90e56929186f0b3c6fe8d4c003191a7f139674cd75f659c9c348214f8');

Both should work. You need just save binary value in proper way for your database.

If you want an example, please provide a reproducible environment ready to run and extension. Some docker-compose with working mysql, generated keys, configured acra-server to work with this database, generated poison record and dumped into some file and entrypoint that has access to the database and this poison record in the file. It will help not to spend much time reproducing your environment to write 1 valid SQL query

m8522s commented 1 year ago

OK, got it. I now have inserted a poison record into the users table. Next, I start the acra-server with poison_detect_enable:

acra-server --mysql_enable=true --db_host=10.5.1.95 --db_port=3306 --incoming_connection_string=tcp://0.0.0.0:3306 -v   --poison_detect_enable=true --poison_shutdown_enable=true

Now, when a client requests SELECT * FROM users; it receives the full table including the poison record. The log file of acra-server does not warn or shut down.

Do I have to include acra-censor to make poison record detection work? Thanks for your help.

Lagovas commented 1 year ago

Do I have to include acra-censor to make poison record detection work?

No, you don't need.

We tested it locally with MySQL and poison records, with your flags and all still works. Plus, we have integration tests that do the same. If you still having problems, please provide docker-compose file that reproduces your environment with all params and steps that you do. You can find our docker-compose examples in our engineering demos for acra-server that depends on key generation and databases. Example how we do it for python script.