Fundamental Security Part Seven– Data Encryption At Rest

October 2023 – Oracle 19C+

Photo by Sajad Nori on Unsplash

What is Data Encryption At Rest and why should we use it?

We have looked at Data Encryption in Transit, encrypting your network traffic. Everyone should be doing this. But what about Encrypting Data At Rest? Data that is stored permanently (on your hard drives).


The simplest way to do this, from a database/DBA perspective, is to use an encrypted storage device. Most SAN/NAS devices come with encryption built-in, and encryption of the storage presented to servers is abstracted away to the SAN. The CPU overhead is handled by the SAN and you don’t need to worry about it. However, if you are using Exadata or any Oracle Cloud Service, this is not an option. You will need to implement Oracle Transparent Data Encryption. This is mandatory with the Oracle Cloud. Some cloud providers provide a Storage-Level encryption option (which is frequently an added cost and is usually not the default!)

Why Do This?

There are 3 reasons to implement Encryption At Rest

1. In case the hardware gets stolen. This may not just be directly from your data centre, but following the decommissioning or break/replace of the hardware too.
2. Bypassing database controls to read or amend the data in your database directly from the files.
3. Because the auditors insist upon it (see points 1 and 2)


Storage-Level Encryption [SLE] v Oracle Transparent Data Encryption [TDE]

Neither Storage-Level Encryption [SLE] nor TDE means your data is safe. The processes running against your data need to see it unencrypted. If the processes can do this, so can suitably privileged Operating System administrators.

No matter what security you have put within your databases to prevent unauthorised access to your data, if your data is unencrypted (or encrypted using SLE where it is presented to the server “unencrypted”), you can run a “dd” (in Linux, other O/S have similar commands) and view the data directly. Don’t think for a moment that because it is in an Oracle internal format that it is difficult to read.

> create table read_me (c1 varchar2(1000)) tablespace users
;
Table created.

> insert into read_me values ('I CAN SEE YOU!');
1 row created.

> commit;
Commit complete.

select segment_name,block_id,blocks from dba_extents where segment_name = 'READ_ME';

SEGMENT_NAME                     BLOCK_ID     BLOCKS
------------------------------ ---------- ----------
READ_ME                               136          8

$ dd if=./users01.dbf bs=8192 skip=136 count=8 | od -xa --endian=big

*
0157740    0000    0000    0000    0000    0000    2c01    010e    4920
        nul nul nul nul nul nul nul nul nul nul   , soh soh  so   I  sp
0157760    4341    4e20    5345    4520    594f    5521    0106    7004
          C   A   N  sp   S   E   E  sp   Y   O   U   ! soh ack   p eot
0160000    06a2    0000    8f00    c003    6f04    4200    0000    0204
        ack   " nul nul  si nul   @ etx   o eot   B nul nul nul stx eot
0160020    73e2    0000    0100    0000    4426    0100    6f04    4200
          s   b nul nul soh nul nul nul   D   & soh nul   o eot   B nul
0160040    0080    0000    0200    3200    8800    c003    0000    0000
        nul nul nul nul stx nul   2 nul  bs nul   @ etx nul nul nul nul
0160060    0000    0000    0000    0000    0000    0000    0000    0000
        nul nul nul nul nul nul nul nul nul nul nul nul nul nul nul nul
*

Encrypting your data on the storage layer DOES NOT PREVENT this sort of access or potential attack.

Oracle Transparent Data Encryption [TDE]

First of all, Oracle Transparent Data Encryption is a COST OPTION. It is not part of the standard Oracle license.

TDE encrypts the actual Oracle data files. Running a “dd” against an encrypted tablespace reveals no usable information. However, you now need to handle all of the keys to be able to open your databases. Key management is the most important aspect of using TDE, ensuring they are available and are not compromised. If you lose the keys, your data is unrecoverable. Remember to backup the keys at the same time (but not with!) as the database as you will need the relevant key should you need to recover the database.

Important note: Most companies who implement TDE do it at the tablespace level. This means the data on disk is encrypted and the CPU overhead is generally low. However, data in memory is NOT encrypted. In Linux, as memory is effectively treated as a file by the O/S, it is possible to read whatever is in your buffer cache using the “dd” method. If you are very skilled (hackers are!), this is also possible from the dom0 layer of the hypervisor, which is accessible by the staff of the cloud provider. Only data encrypted at a column level remains encrypted within the buffer cache. The overhead for accessing column-level encrypted data is high.

It is debatable whether data in the server memory is “at rest”. If you have extremely valuable data, such as credit card information, this should be encrypted by the application (for example by adhering to PCI DSS standards).

For a basic implementation of TDE, I would recommend looking at Tim’s article here (rather than me repeat his excellent website) or one from an Oracle PM here.

When I have time, I’ll do a follow-on article about using a HSM or OKV to manage your keys.


Now I would like to talk about Fundamental Security Part Eight – Unified Audit

Fundamental Security Part Six– Network Encryption

August 2023 – Oracle 19C

We have considered observability. Knowing where you may have a security problem. We now need to look at removing some of the main problems associated with Oracle databases. Lets start with Network Security.

By default, all data travelling over the network with Oracle is unencrypted. This means that anyone with something like Wireshark can inspect packets and read your data as it travels between the client/application and the database. This is not secure. You are going to want to encrypt this data.

There are 2 options when it comes to encryption; implement Transport Layer Security (TLS) using certificates or use Oracle Native Network Encryption and Integrity (note: these used to be part of the Advanced Security Option but is now free with all supported Oracle versions from Oracle 10 onwards)


Transport Layer Security (TLS)

This involves generating and signing a certificate, and putting it into an Oracle Wallet on the database server, and also including the same certificate on each Oracle client or application server needing to connect to the database. You then need to do the same on each client and add the certificate to the database server wallet. This can provide full standard TLS encryption, but at a cost of certificate management. Certificates must expire, and many companies require certificates to be signed by a Certificate Authority, which should impose a maximum lifespan of 1 year on the certificate. When the certificates expire, they need to be replaced. It is possible to link directly to a CA to assist with this, depending upon your setup, but that is beyond the scope of this blog post. Maybe later…

It’s a good idea to use certificate management software to perform this function, otherwise you probably have a never-ending task “like painting the Forth Bridge“.

WARNING! One of the commonest causes of system
outage in the IT industry is an expired certificate

For an example of implementing TLS, please check-out this blog post by Tim Hall

Note that TLS will require you to make both server-side and client-side changes (to every client which connects to the database).

To check if your session is running with encrypted TCPS (rather than TCP), you can issue the following command:

SELECT sys_context('USERENV', 'NETWORK_PROTOCOL') as network_protocol FROM dual;

NETWORK_PROTOCOL
----------------
tcps

As the following Twitter conversation shows, there are alternate ways to configure TLS. You could just generate your own signed certificate on each box, exchange it and hope nobody compromises it. You could just use a single signed and trusted root cert from your CA. It can be simpler, but there are inevitably trade-offs involved.


Oracle Native Network Encryption and Integrity (ONNEI or ANO)

The first thing you should look to do if you are not encrypting network traffic is to implement Oracle Native Network Encryption and Integrity (formerly Advanced Networking Option – ANO). Largely because it’s so simple, so easy to implement and will also show where you have older clients which need to be upgraded.

So what does the name mean? Encryption and Integrity. When you encrypt data you need good Encryption. You also need to ensure nobody has changed the data in transit. Integrity (or checksums). The industry standard algorithms at the moment are AES256 for encryption and SHA384 for crypto-checksumming.

Configuring ONNEI

One of the advantages of using the native encryption is that you can enable this server-side only. You may not need to make any changes at all to the clients, if the client or (JDBC) drivers are sufficiently up to date. Setup in REQUESTED mode to start with, so any non-compliant clients will still connect unencrypted.

Edit the sqlnet.ora file on the tns listener home on the database server(s) and add:

SQLNET.ENCRYPTION_SERVER = REQUESTED
SQLNET.ENCRYPTION_TYPES_SERVER = (AES256)
SQLNET.CRYPTO_CHECKSUM_SERVER = REQUESTED
SQLNET.CRYPTO_CHECKSUM_TYPES_SERVER = (SHA384)

NOTE: the sqlnet.ora file is re-read dynamically every time there is a new database connection. Changing the file will immediately cause new connections to encrypt

Monitor connections to ensure they are encrypting:

SELECT sys_context('USERENV', 'NETWORK_PROTOCOL') as network_protocol FROM dual;

NETWORK_PROTOCOL
----------------
tcp

Ah! We are not using TLS so we aren’t encrypting as TCPS. The encryption is Oracle Native. The packets are not fully encrypted. Only the contents (your data!) are subject to encryption. We therefore need another method.

Looking at GV$SESSION_CONNECT_INFO, we can see 2 lines which would not normally be present, showing AES256 and SHA384 encryption. The SQL below restricts the output to your session. Remove the WHERE clause and you can see the encryption for every session. (You can sort-of use this view to see if the connection is using TCPS as the line “TCP/IP NT Protocol Adapter for Linux:…..” will not exist.)

Note that we are using REQUESTED and not REQUIRED at this stage, so some connections may have only 3 lines of output, some may have 5. Also, if you have note specified the level of encryption required, this is also reflected in the output (e.g. in 19C, the default is AES256 but the weak algorithm for checksumming, SHA1)

ONNEI

SELECT sys_context('USERENV', 'NETWORK_PROTOCOL') as network_protocol FROM dual;

NETWORK_PROTOCOL
----------------
tcp

SELECT network_service_banner FROM gv$session_connect_info 
      WHERE sid IN (SELECT DISTINCT sid FROM v$mystat) ORDER BY 1;

NETWORK_SERVICE_BANNER
----------------------------------------------------------------------------
AES256 Encryption service adapter for Linux: Version 19.0.0.0.0 - Production
Crypto-checksumming service for Linux: Version 19.0.0.0.0 - Production
Encryption service for Linux: Version 19.0.0.0.0 - Production
SHA384 Crypto-checksumming service adapter for Linux: Version 19.0.0.0.0 - P
TCP/IP NT Protocol Adapter for Linux: Version 19.0.0.0.0 - Production

TLS

SELECT sys_context('USERENV', 'NETWORK_PROTOCOL') as network_protocol FROM dual;

NETWORK_PROTOCOL
----------------
tcps

SELECT network_service_banner FROM gv$session_connect_info
WHERE sid IN (SELECT DISTINCT sid FROM v$mystat) ORDER BY 1;

NETWORK_SERVICE_BANNER
----------------------
Crypto-checksumming service for Linux: Version 19.0.0.0.0 - Production
Encryption service for Linux: Version 19.0.0.0.0 - Production

(if you are using both ONNEI and TLS, you may also get the SHA384 line)
One you are happy that all connections are encrypting successfully, change from REQUESTED to REQUIRED. This will reject any connection attempts which cannot encrypt.
SQLNET.ENCRYPTION_SERVER = REQUIRED
SQLNET.ENCRYPTION_TYPES_SERVER = (AES256)
SQLNET.CRYPTO_CHECKSUM_SERVER = REQUIRED
SQLNET.CRYPTO_CHECKSUM_TYPES_SERVER = (SHA384)

All done. 1 or 2 changes to sqlnet.ora and you’re enforcing encryption over the network.

You can also confirm the protocol (tcp v tcps) used if you are auditing successful logons (you should be!)

SELECT dbusername,authentication_type FROM unified_audit_trail;

dbu  authentication_type
---  -------------------
TIM  (TYPE=(DATABASE));(CLIENT ADDRESS=((ADDRESS=(PROTOCOL=tcp)(HOST=192.168.56.194)(PORT=63849))));
NEIL (TYPE=(DATABASE));(CLIENT ADDRESS=((ADDRESS=(PROTOCOL=tcps)(HOST=192.168.56.193)(PORT=44317))));

Performance Impact

All encryption comes with a CPU requirement. You will burn more CPU on the client and server encrypting and decrypting traffic. You also add a few milliseconds latency at connect time for the handshake (although for most databases systems using stable connection pools, this should not be noticeable)

Extra CPU is usually in the 1%-5% range for Oracle DB network encryption, although you do need to test as it will vary across applications. There is minimal difference between using TLS and ONNEI, although the TLSv1.3 handshake has been performance optimised over TLSv1.2, I have not re-tested for any performance difference at this point and if you are using connection pooling there will be no noticeable difference.

Conclusion – what should I use?

Both. One of the important things to remember about ONNEI is that it doesn’t use TLS, so it’s not using an “industry standard” protocol. Your security team may insist upon having TLSv1.2 or 1.3. However, it is encrypting/checksumming to the same standard so there is very little to choose between the 2 methods.

If you use pre-exchanged TLS certificates associated only with each server, you do have the advantage that you cannot fall foul of a man-in-the-middle attack. This is possible, although difficult, with ONNEI. Simple eavesdropping will not be possible.

However, you don’t need to choose to get started. You can set the sqlnet.ora parameter:

IGNORE_ANO_ENCRYPTION_FOR_TCPS=TRUE

This allows ONNEI to be used if the connection if not TLS encrypted, but ignores the ONNEI config for already encrypted connections.

So, setup ONNEI, monitor it for old client connections, then consider if you need to explicitly encrypt using TLS for some or all of your connections with the overhead that entails.

Next lets talk about Data Encryption At Rest