Your Oracle Traffic Is Readable on the Wire. Here's the Proof, and the Fix.
The database is patched. The data files are encrypted with TDE. The audit trail is clean. And every query your application runs — along with every row it gets back — crosses the network as readable text. Not because anyone turned encryption off, but because nobody ever turned it on: out of the box, an Oracle client and an Oracle server agree to talk in plaintext.
That is not a theoretical weakness. Anyone who can see the packets — a compromised jump host, a mirrored switch
port, a misconfigured cloud network, a curious admin with tcpdump — can read the SQL, the bind values, and the
result sets. This post shows exactly what is on the wire, why the default is plaintext, the four lines of
sqlnet.ora that fix it, how to verify a session is actually encrypted, and a lab that captures the same
session before and after.
What is actually on the wire
Here is what a packet capture of an ordinary session looks like on a default install. The APP user connects
over TCP and runs one query against a table holding a confidential value; tcpdump -A on port 1521 shows:
wire> select 'ROWS='||count(*) from vault where secret like 'CANARY-%'
wire> CANARY-7731-CONFIDENTIAL
That is the SQL text and the result value, lifted straight out of the packets. No exploit, no credentials, no access to the database — just a view of the network path.
Two things are worth being precise about. First, the password is not the problem: Oracle’s logon is a challenge-response, so the password itself does not cross in the clear even here. Everything after the logon does. Second, this is not an “old version” issue. The capture above is from the current Oracle Database Free release, with nothing misconfigured — it is simply the default.
Why the default is plaintext
Oracle’s native network encryption is negotiated per connection, and each side has a setting in sqlnet.ora:
SQLNET.ENCRYPTION_SERVER on the database host and SQLNET.ENCRYPTION_CLIENT on the client. Each can be one of
four values:
REJECTED— never encrypt; refuse a peer that insists.ACCEPTED— encrypt only if the other side asks. This is the default on both sides.REQUESTED— ask for encryption, but fall back to plaintext if the other side won’t.REQUIRED— encrypt or refuse the connection.
The trap is in that default. When both ends are ACCEPTED, each is willing to encrypt but neither asks — so
the negotiation succeeds with no encryption at all. Nothing is broken, nothing logs a warning, and the session
runs in plaintext forever.
The integrity side works the same way with SQLNET.CRYPTO_CHECKSUM_SERVER / _CLIENT: a per-packet
cryptographic checksum that detects tampering and replay in transit. It is a separate switch, and it defaults to
off for the same reason.
The fix: four lines on the server
Make encryption and integrity required on the database server, and pin strong algorithms. In the server’s
sqlnet.ora (normally $ORACLE_HOME/network/admin, or wherever TNS_ADMIN points):
SQLNET.ENCRYPTION_SERVER = REQUIRED
SQLNET.ENCRYPTION_TYPES_SERVER = (AES256)
SQLNET.CRYPTO_CHECKSUM_SERVER = REQUIRED
SQLNET.CRYPTO_CHECKSUM_TYPES_SERVER = (SHA256)
Why the server, and why REQUIRED:
- One change covers every client. Clients default to
ACCEPTED, so once the server requires encryption, every client that hasn’t explicitly rejected it simply negotiates it. No application change, no client redeploy. REQUIRED, notREQUESTED.REQUESTEDfalls back to plaintext if a peer declines — which means a misconfigured client silently stays readable.REQUIREDmakes that client fail loudly withORA-12660instead, which is what you want to find in testing, not in an incident.- Pin the algorithm list. List only the algorithms you accept (AES256, and AES192/AES128 if you must), so nothing negotiates down to a legacy cipher. Same for the checksum: SHA-2 family only.
- Integrity is not optional. Encryption without the checksum hides the data but doesn’t stop tampering or replay. Require both.
No restart is needed: the server reads sqlnet.ora when it starts a new server process for a new connection.
That also means existing sessions keep whatever they negotiated — recycle connection pools after the change,
or they will stay in plaintext until they reconnect.
Verify it, don’t assume it
A config file is a claim. The proof is what each session actually negotiated, which Oracle exposes in
V$SESSION_CONNECT_INFO:
SELECT network_service_banner
FROM v$session_connect_info
WHERE sid = SYS_CONTEXT('USERENV', 'SID');
On an encrypted session you will see lines naming the algorithm in use — AES256 Encryption service adapter…
and SHA256 Crypto-checksumming service adapter…. On a plaintext session you will only see the generic
“Encryption service for Linux” / “Crypto-checksumming service” lines with no algorithm adapter. Run the same
check across all sessions (drop the WHERE, join to V$SESSION for usernames and programs) to find any
connection still in the clear.
Don’t take my word for it — run it. The SQL*Net encryption lab stands up Oracle Database Free and a throwaway
tcpdumpsidecar that shares the database’s network namespace. TheAPPuser reads a confidential row over TCP: on the default config the session negotiates no encryption and the capture contains both the SQL text and the secret value. It then adds the foursqlnet.oralines, runs the same session under the same capture, and asserts the session negotiatedAES256/SHA256and that neither the SQL nor the secret appears anywhere in the packets. If the plaintext doesn’t reproduce, or the fix doesn’t hide it, the run fails. Proven on every CI push.
In the lab, the before-and-after is unambiguous:
default : session encryption: NONE integrity: NONE SQL seen 2x, secret seen 1x
fixed : session encryption: AES256 integrity: SHA256 SQL seen 0x, secret seen 0x
Native encryption or TLS?
Oracle offers two ways to encrypt the connection, and both are included in every edition at no extra cost:
- Native network encryption (what this post configures) — a few lines of
sqlnet.ora, no certificates, and it works with existing connect strings on port 1521. The fastest way to get every session off plaintext. - TLS (TCPS) — certificate-based, usually on a separate port. Its key advantage is server authentication: the client verifies it is talking to the real database, which protects against a rogue or spoofed listener in the middle. Native encryption has no such check. TLS is also what many compliance frameworks name explicitly, and it encrypts the connect packet that native encryption leaves readable.
A practical path: turn on native encryption with REQUIRED now — it closes the plaintext gap today with almost no
risk — and plan TLS where you need server authentication or an auditor asks for it by name.
What teams get wrong
- Assuming TDE covers it. TDE encrypts data at rest — data files and backups. The moment a row is read and sent to a client, TDE is out of the picture. In-transit protection is a separate control.
- Assuming the network is private. “It’s all inside the VPC / the data center” is exactly the assumption an attacker with one foothold relies on. Internal traffic is where lateral movement happens.
- Setting
REQUESTEDand calling it done. It looks like encryption is on, but any peer that declines gets a plaintext session with no error. UseREQUIREDand let incompatible clients fail where you can see them. - Encrypting without integrity. Without
CRYPTO_CHECKSUM, traffic is hidden but can still be modified or replayed in transit. Require both. - Never verifying. A
sqlnet.orain the wrong directory, an overridingTNS_ADMIN, or a pool that never reconnected all leave sessions in plaintext while the config looks correct. CheckV$SESSION_CONNECT_INFO. - Expecting everything to be hidden. The initial connect packet — service name, client program, OS user — is sent before negotiation and stays readable with native encryption. The database username, SQL and data do not. If the connect descriptor itself is sensitive, that’s an argument for TLS.
Frequently asked questions
Is Oracle database network traffic encrypted by default?
No. By default both the Oracle client and the database server have their native network encryption setting at ACCEPTED, which means each side is willing to encrypt but neither one requests it, so the connection is negotiated without encryption. SQL statements, bind values and result sets then cross the network as readable bytes that anyone who can capture the packets can read. The logon password is protected by Oracle's challenge-response authentication, but everything after logon is in plaintext until you configure encryption, either with native network encryption in sqlnet.ora or with TLS (TCPS).
How do I enable Oracle native network encryption?
Add four lines to the database server's sqlnet.ora (normally in $ORACLE_HOME/network/admin or the directory TNS_ADMIN points to): SQLNET.ENCRYPTION_SERVER = REQUIRED, SQLNET.ENCRYPTION_TYPES_SERVER = (AES256), SQLNET.CRYPTO_CHECKSUM_SERVER = REQUIRED, and SQLNET.CRYPTO_CHECKSUM_TYPES_SERVER = (SHA256). Because clients default to ACCEPTED, every new connection then negotiates AES256 encryption and SHA-256 integrity without any client change. No database restart is needed, but existing sessions keep what they already negotiated, so recycle application connection pools afterwards and verify the result in V$SESSION_CONNECT_INFO.
What is the difference between ACCEPTED, REQUESTED and REQUIRED?
They control how each side negotiates encryption. REJECTED never encrypts and refuses a peer that requires it. ACCEPTED, the default, encrypts only if the other side asks. REQUESTED asks for encryption but falls back to plaintext if the other side declines. REQUIRED insists on encryption and refuses the connection otherwise. Encryption is used when at least one side requests or requires it and the other does not reject it; if one side is REQUIRED and the other REJECTED, the connection fails with ORA-12660. Using REQUIRED on the server is the safe choice because it turns a silent plaintext fallback into a visible error.
How can I check whether an Oracle session is encrypted?
Query V$SESSION_CONNECT_INFO for the session, for example SELECT network_service_banner FROM v$session_connect_info WHERE sid = SYS_CONTEXT('USERENV','SID'). An encrypted session shows a line naming the algorithm adapter in use, such as 'AES256 Encryption service adapter', and an integrity-protected session shows a line such as 'SHA256 Crypto-checksumming service adapter'. A plaintext session only shows the generic encryption and crypto-checksumming service lines with no algorithm adapter. To audit the whole instance, query it for all sessions joined to V$SESSION to see which users and programs are still connecting without encryption.
Does native network encryption need a separate license?
No. Oracle native network encryption and data integrity, as well as TLS (TCPS) for database connections, were once part of the separately licensed Advanced Security option, but Oracle made network encryption available in all editions of the database years ago. Transparent Data Encryption and Data Redaction remain part of Advanced Security, but encrypting traffic between clients and the database does not require it.
Should I use native network encryption or TLS?
Both encrypt the traffic. Native network encryption is configured with a few sqlnet.ora parameters, needs no certificates, and works with existing connect strings, which makes it the fastest way to get every session off plaintext. TLS (TCPS) uses certificates and adds server authentication, so the client verifies it is connected to the genuine database and is protected against a spoofed listener or man-in-the-middle; it also encrypts the initial connect packet and is the control many compliance frameworks name explicitly. A common approach is to enable native encryption with REQUIRED immediately, and adopt TLS where server authentication or a specific compliance requirement calls for it.
Does Transparent Data Encryption protect data in transit?
No. Transparent Data Encryption (TDE) encrypts data at rest, in data files, redo, and backups, so that stolen files or media are unreadable. When a session queries the data, the database decrypts it and sends the result to the client, and at that point TDE no longer applies. Protecting data as it travels between the client and the database requires network encryption, either native network encryption or TLS. A complete setup uses both: TDE for data at rest and network encryption for data in transit.
Network encryption is the in-transit half of a picture the rest of the security series builds from other angles:
the hardening checklist decides who can connect and how,
TDE protects the data files and backups at rest,
redaction narrows which values reach a screen, and
unified auditing records who asked. None of them help once a result set is
crossing the network in readable bytes. Set the server to REQUIRED, pin AES256 and SHA-256, verify every session
in V$SESSION_CONNECT_INFO, and then prove it the way that ends the argument: with the SQL*Net encryption
lab, where the same query is readable in a
packet capture before the fix and unreadable after.
Have a question or some feedback?
I write here in a personal capacity and enjoy comparing notes with other Oracle folks. Say hello.
Get in touch