Hardened OPC UA wrapper with Presidio security extensions. Independent of Microsoft Presidio (a data-anonymization toolkit).
Project description
presidio-hardened-opcua
Hardened OPC UA wrapper with Presidio security extensions.
Drop-in replacement for python-opcua that adds strong security defaults, certificate validation, anomaly detection, and input sanitization — all without changing your existing OPC UA code.
Installation
pip install presidio-hardened-opcua
Quick Start
Replace your existing import:
# Before (plain opcua)
from opcua import Client, Server
# After (Presidio-hardened)
from presidio_opcua import Client, Server
That's it. Your existing code gains security hardening automatically.
Side-by-Side Comparison
Plain opcua — no security enforced
from opcua import Client
client = Client("opc.tcp://10.0.0.5:4840")
client.connect() # ← connects with NO encryption
node = client.get_node("ns=2;i=1") # ← no input sanitization
value = node.get_value()
client.disconnect()
Problems: No certificate validation, no encryption requirement, no anomaly detection, no input sanitization. An attacker on the network can eavesdrop, tamper, or inject malicious node IDs.
presidio-hardened-opcua — secure by default
from presidio_opcua import Client, SecurityPolicy
policy = SecurityPolicy(
allow_self_signed=False, # reject self-signed certs
session_timeout_ms=30_000, # tight session timeout
)
client = Client("opc.tcp://10.0.0.5:4840", security_policy=policy)
# Security is enforced — this will FAIL without calling set_security() first:
# client.connect() → raises PresidioSecurityError
# Configure mutual authentication:
client.set_security(
"Basic256Sha256",
certificate_path="client_cert.der",
private_key_path="client_key.pem",
server_certificate_path="server_cert.der",
# mode defaults to SignAndEncrypt — cannot be set to None
)
client.connect() # ✓ encrypted, authenticated, hardened timeouts
# Node IDs are automatically sanitized:
node = client.get_node("ns=2;i=1") # ✓ validated
value = node.get_value()
# Anomaly detection runs in the background:
print(client.anomaly_detector.stats)
client.disconnect()
Server — insecure policies automatically rejected
from presidio_opcua import Server
from opcua import ua
server = Server()
# NoSecurity is silently filtered out:
server.set_security_policy([
ua.SecurityPolicyType.NoSecurity, # ← rejected
ua.SecurityPolicyType.Basic256Sha256_SignAndEncrypt, # ← kept
])
server.start()
Security Features
| Feature | Description |
|---|---|
| Certificate Validation | Rejects self-signed certs by default; validates expiry and format |
| Strict Security Mode | Enforces SignAndEncrypt; rejects None security mode |
| Input Sanitization | Validates node IDs, browse paths, and variant values against injection patterns |
| Anomaly Detection | Monitors access rate and unique-node counts; logs warnings on suspicious activity |
| Dependency CVE Check | Checks installed versions of opcua and cryptography against known vulnerabilities |
| Session Hardening | Configurable session and channel timeouts (defaults: 30s / 60s) |
| Security Event Logging | All security decisions logged via Python logging under presidio_opcua.* |
Configuration
from presidio_opcua import SecurityPolicy
policy = SecurityPolicy(
allow_self_signed=False, # reject self-signed certificates
allow_no_security=False, # reject None security mode
session_timeout_ms=30_000, # session timeout in milliseconds
secure_channel_timeout_ms=60_000,# secure channel timeout
)
Logging
Enable security event logging:
import logging
logging.basicConfig(level=logging.INFO)
# All Presidio security events are logged under:
# presidio_opcua.client
# presidio_opcua.server
# presidio_opcua.security
# presidio_opcua.anomaly
# presidio_opcua.dep_check
Development
git clone https://github.com/presidio-v/presidio-hardened-opcua.git
cd presidio-hardened-opcua
pip install -e ".[dev]"
pytest --cov=presidio_opcua
ruff check .
License
MIT — see LICENSE.
SDLC
This repository is developed under the Presidio hardened-family SDLC: https://github.com/presidio-v/presidio-hardened-docs/blob/main/sdlc/sdlc-report.md.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file presidio_hardened_opcua-0.1.0.tar.gz.
File metadata
- Download URL: presidio_hardened_opcua-0.1.0.tar.gz
- Upload date:
- Size: 51.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7bc8f04b75e1ca8c0422a1f0317460601666f0c3f3ee0ac183d20b26f855203e
|
|
| MD5 |
e79e81ade7a43fb5661efc2401a257f0
|
|
| BLAKE2b-256 |
4cf49803d82e159d754b0b589c4f4eac6f5492b4afb136e3b1fa2da199979bb4
|
Provenance
The following attestation bundles were made for presidio_hardened_opcua-0.1.0.tar.gz:
Publisher:
publish.yml on presidio-v/presidio-hardened-opcua
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
presidio_hardened_opcua-0.1.0.tar.gz -
Subject digest:
7bc8f04b75e1ca8c0422a1f0317460601666f0c3f3ee0ac183d20b26f855203e - Sigstore transparency entry: 1791799643
- Sigstore integration time:
-
Permalink:
presidio-v/presidio-hardened-opcua@ad2b565b249099067533db7414f2a6694fdbabbf -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/presidio-v
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ad2b565b249099067533db7414f2a6694fdbabbf -
Trigger Event:
push
-
Statement type:
File details
Details for the file presidio_hardened_opcua-0.1.0-py3-none-any.whl.
File metadata
- Download URL: presidio_hardened_opcua-0.1.0-py3-none-any.whl
- Upload date:
- Size: 12.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
89f02349e835c5064e54fe6d0d7f9c548dde8cd5491c97cd1d04bdc393104b3b
|
|
| MD5 |
98e3998d8a3975b3061a5959b0fc0b95
|
|
| BLAKE2b-256 |
cce892c51d2ba24c8642a607fc33b796c6d01ed1a0d5f4db042d5d14321ef20f
|
Provenance
The following attestation bundles were made for presidio_hardened_opcua-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on presidio-v/presidio-hardened-opcua
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
presidio_hardened_opcua-0.1.0-py3-none-any.whl -
Subject digest:
89f02349e835c5064e54fe6d0d7f9c548dde8cd5491c97cd1d04bdc393104b3b - Sigstore transparency entry: 1791801607
- Sigstore integration time:
-
Permalink:
presidio-v/presidio-hardened-opcua@ad2b565b249099067533db7414f2a6694fdbabbf -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/presidio-v
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ad2b565b249099067533db7414f2a6694fdbabbf -
Trigger Event:
push
-
Statement type: