Concluded·21 Jun 2026 · 2 min read
OPC UA: NoSecurity vs Sign & Encrypt on the wire
OPC UA · asyncua · Basic256Sha256 · Docker · tcpdump · tshark
The capstone measures the difference a securable protocol makes. One server, one variable, two endpoints — one with security off, one with Sign & Encrypt on — and a capture of the same read through both.
Kepware is the usual aggregator in this role and is Windows-only, so this runs on an open
OPC UA server (asyncua). The role and the result are what matter.
Lab setup
security/opcua-server.py builds an asyncua server on TCP 4840 that offers two
security policies at once:
server.set_security_policy([
ua.SecurityPolicyType.NoSecurity,
ua.SecurityPolicyType.Basic256Sha256_SignAndEncrypt,
])It seeds one variable, Pump.Speed = 42.0, and generates a self-signed certificate for
the encrypted endpoint. The client (security/opcua-read.py) generates its own
certificate, then reads the variable twice — once through each door.
Reproduce
python opcua-server.py # NoSecurity + Basic256Sha256 Sign&Encrypt, Pump.Speed=42.0
tcpdump -i br-<id> -w opcua.pcap 'tcp port 4840'
python opcua-read.py # reads through both endpointsClient output:
NoSecurity read Pump.Speed = 42.0 (cleartext on the wire)
Sign&Encrypt read Pump.Speed = 42.0 (encrypted on the wire)
The proof
Both reads returned 42.0. The IEEE-754 double for 42.0 is 00 00 00 00 00 00 45 40.
Counting its occurrences across the whole capture:

The capture contains two full sessions (two HELLO/ACK, two OpenSecureChannel pairs, the MSG bodies). Only the NoSecurity session exposes the value; the Sign & Encrypt session's application payload is encrypted.
The series on one ladder
Modbus, EtherNet/IP, and S7comm cannot defend themselves, so they are defended at the network. MQTT and OPC UA can, so they are defended at the protocol. The aggregator on the IT/OT boundary is where both halves meet — plaintext down to what cannot do better, Sign & Encrypt up to what can:
Note on Kepware
Kepware (KEPServerEX) is Windows-only and was not run in this Linux lab; an open OPC UA server stood in for the aggregator role. The security-mode contrast — None readable, Sign & Encrypt opaque — is a property of OPC UA itself, not of any one product.
Harness
opcua-server.py, opcua-read.py, and opcua.pcap are in the
modbus-copilot repo security/. Isolated
lab, own equipment only.
Why this matters, in plain terms: OPC UA can refuse, and almost nobody asks it to.
Newsletter
New essays, by email.
SCADA, cloud, AI, and the plant floor — a short email when something new is published. No noise, unsubscribe anytime.