Why Enable ONVIF Security?
By default, ONVIF communication uses unencrypted HTTP and plain-text SOAP messages. For production deployments and security compliance, ONVIF defines two layers of protection:
- Transport-Level Security (TLS/HTTPS): Encrypts the entire HTTP session between the client and the ONVIF device, preventing eavesdropping and man-in-the-middle attacks on all SOAP request/response traffic.
- Message-Level Security (WS-Security): Embeds authentication credentials (UsernameToken) and optionally encrypts individual SOAP messages, ensuring end-to-end security even when intermediate proxies are involved.
Happytime ONVIF Server supports both layers: HTTPS with SHA-256 certificates for transport encryption, and the ONVIF Security Service (per the ONVIF Security Service Specification) for TLS server configuration and keystore management. Enabling these is essential for testing VMS platforms that require secure ONVIF communication.
Understanding ONVIF Security Architecture
Transport Layer: HTTPS/TLS
At the transport layer, ONVIF devices use standard TLS (Transport Layer Security) to encrypt HTTP traffic. The device acts as a TLS server, presenting an X.509 certificate to the client during the TLS handshake. The client validates the certificate and then all subsequent SOAP requests and responses are encrypted over the secure channel.
Key TLS configuration elements on the ONVIF device:
- Server Certificate: An X.509 certificate (self-signed or CA-signed) that identifies the device to clients.
- Private Key: The cryptographic key pair matching the certificate's public key, used to establish the TLS session.
- TLS Version: TLS 1.2 or higher is recommended. TLS 1.0 and 1.1 are deprecated and should be disabled in production.
- Cipher Suites: The set of encryption algorithms the server supports (e.g., TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384).
Message Layer: WS-Security
At the message layer, ONVIF uses the WS-Security standard to add authentication tokens to SOAP message headers. Even when HTTPS is enabled, WS-Security provides an additional layer of identity verification. The ONVIF specification mandates support for:
- UsernameToken with Password Digest: The most common ONVIF WS-Security mode. The client sends a password digest (SHA-256 hash of nonce + creation timestamp + password) rather than the plaintext password.
- UsernameToken with Plaintext Password: Used only over HTTPS, since the transport layer provides encryption.
ONVIF Security Service
The ONVIF Security Service (defined in the ONVIF Security Service Specification) is a dedicated web service on the device that allows clients to programmatically manage the device's TLS configuration:
| Operation | Description |
|---|---|
| GetKeystoreState | Query whether the keystore is initialized and available. |
| GetCertificates | List all installed certificates and their properties (subject, issuer, validity). |
| GetCertificatesStatus | Check the status of each certificate (ok, error, aboutToExpire). |
| AddServerCertificate | Upload a new X.509 certificate and its private key to the device keystore. |
| DeleteCertificates | Remove one or more certificates from the keystore. |
| CreateCertificationPath | Create the full certificate chain (for CA-signed certificates). |
| SetTLSConfiguration | Enable/disable TLS, select the active server certificate, and configure allowed cipher suites. |
| GetTLSConfiguration | Retrieve the current TLS settings (enabled status, selected certificate, cipher suites). |
Step 1: Generate a Self-Signed Certificate (for Testing)
For development and testing, a self-signed certificate is sufficient. For production, replace this with a certificate signed by a trusted Certificate Authority (CA).
Option A: Using OpenSSL (Windows/Linux/macOS)
# Generate a 2048-bit RSA private key
openssl genrsa -out key.pem 2048
# Generate a self-signed certificate (valid for 365 days)
openssl req -new -x509 -key key.pem -out cert.pem -days 365 -subj "/C=CN/ST=Beijing/L=Beijing/O=Happytimesoft/CN=192.168.1.200"
Option B: Using PowerShell (Windows)
# Generate a self-signed certificate
$cert = New-SelfSignedCertificate -DnsName "192.168.1.200" -CertStoreLocation "cert:\CurrentUser\My" -KeyAlgorithm RSA -KeyLength 2048 -NotAfter (Get-Date).AddYears(1)
# Export certificate as PEM (for cert.pem)
$bytes = $cert.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Cert)
[System.IO.File]::WriteAllBytes("cert.pem", $bytes)
# Note: For the private key (key.pem), use OpenSSL or export the PFX and convert:
# openssl pkcs12 -in temp.pfx -nocerts -nodes -out key.pem
Certificate field recommendations for testing:
| Field | Value | Notes |
|---|---|---|
/C= | Country code (e.g., CN, US) | Two-letter ISO 3166 country code. |
/ST= | State/Province (e.g., Beijing) | Full state or province name. |
/L= | Locality/City (e.g., Beijing) | City name. |
/O= | Organization (e.g., Happytimesoft) | Company or organization name. |
/CN= | Common Name — use the device's IP address | This is the most important field. The client validates that the certificate's CN matches the device IP or hostname being connected to. |
Important: Set the /CN= (Common Name) to the IP address or hostname that ONVIF clients will use to reach the device. If you use a hostname, ensure DNS resolution works from the client side.
Step 2: Configure HTTPS in the ONVIF Server Config
Place the generated certificate and key files in the ONVIF Server working directory, then configure the HTTPS settings in onvif.cfg.
<?xml version="1.0" encoding="utf-8"?>
<config>
<server_ip>192.168.1.200</server_ip>
<!-- HTTP / HTTPS settings -->
<http_enable>1</http_enable>
<http_port>8000</http_port>
<https_enable>1</https_enable>
<https_port>8443</https_port>
<cert_file>cert.pem</cert_file>
<key_file>key.pem</key_file>
<http_max_users>16</http_max_users>
<ipv6_enable>1</ipv6_enable>
<wan_ip></wan_ip>
<!-- Authentication -->
<need_auth>1</need_auth>
<!-- Logging -->
<log_enable>1</log_enable>
<log_level>1</log_level>
<log_path></log_path>
<log_mode>loop</log_mode>
<log_max_size></log_max_size>
<log_max_index></log_max_index>
<information>
<Manufacturer>Happytimesoft</Manufacturer>
<Model>IPCamera</Model>
<FirmwareVersion>2.4</FirmwareVersion>
<SerialNumber>123456</SerialNumber>
<HardwareId>1.0</HardwareId>
</information>
<user>
<username>admin</username>
<password>admin</password>
<userlevel>Administrator</userlevel>
</user>
<user>
<username>user</username>
<password>123456</password>
<userlevel>User</userlevel>
</user>
</config>
Security-related configuration parameters:
| Parameter | Description | Values |
|---|---|---|
<server_ip> |
IP address to bind the HTTP/HTTPS server to. Leave empty to bind to all interfaces. | IP string, e.g., 192.168.1.200 |
<http_enable> |
Enable or disable plain HTTP. When set to 1, the server listens on <http_port>. |
1 (enabled) or 0 (disabled) |
<http_port> |
Port for unencrypted HTTP connections. | Integer, default 8000 |
<https_enable> |
Enable or disable HTTPS/TLS. When set to 1, the server listens on <https_port> for TLS-encrypted connections. |
1 (enabled) or 0 (disabled) |
<https_port> |
Port for TLS-encrypted HTTPS connections. | Integer, default 8443 |
<cert_file> |
Path to the X.509 certificate file in PEM format. Placed in the same directory as the executable. | Filename string, default cert.pem |
<key_file> |
Path to the RSA private key file in PEM format. Must not be encrypted with a passphrase. | Filename string, default key.pem |
<need_auth> |
Controls whether ONVIF WS-Security UsernameToken authentication is required on SOAP requests. When 1, the server requires a valid UsernameToken header. |
1 (required) or 0 (optional) |
<http_max_users> |
Maximum number of concurrent HTTP/HTTPS connections. Limits DoS exposure. | Integer, default 16 |
Step 3: Configure User Credentials and Authentication
The <user> block defines the accounts that ONVIF clients use for WS-Security UsernameToken authentication. When <need_auth> is 1, every SOAP request must carry a valid UsernameToken matching one of the configured users.
User configuration parameters:
| Parameter | Description |
|---|---|
<username> |
The login name for this user. Used as the Username value in WS-Security tokens. |
<password> |
The authentication password. Supports both plaintext and digest modes. |
<userlevel> |
Access level: Administrator (full access) or User (limited access, typically read-only operations). |
Multiple <user> blocks can be defined. At least one Administrator-level user is required for full device configuration access.
Step 4: Configure the ONVIF Client for Secure Connection
On the client side, you need to configure it to connect via HTTPS (port 8443) and, when <need_auth> is 1, embed WS-Security credentials in each SOAP request.
Client-Side Certificate Trust (for Self-Signed Certificates)
When using a self-signed certificate, ONVIF clients will reject the TLS handshake by default because the certificate is not from a trusted CA. You have two options:
Option 1: Trust the Self-Signed Certificate (Recommended for Testing)
- Copy the
cert.pemfile to the client machine. - Import the certificate into the client's trusted certificate store. For example, on Windows:
Import Certificate to Windows Trusted Store
certutil -addstore -f "Root" cert.pem - Configure your ONVIF client to use HTTPS when connecting to the device (e.g.,
https://192.168.1.200:8443/onvif/device_service).
Option 2: Disable Certificate Validation (Development Only)
Some ONVIF client libraries offer a flag to skip certificate validation. Use this only in development environments; never in production.
Client-Side WS-Security Configuration
When WS-Security is enabled on the server, the client must include a UsernameToken in every SOAP request header. The structure of a WS-Security UsernameToken with password digest is:
<wsse:Security>
<wsse:UsernameToken>
<wsse:Username>admin</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">aGVsbG8gd29ybGQ=</wsse:Password>
<wsse:Nonce>dGhpcyBpcyBhIG5vbmNl</wsse:Nonce>
<wsu:Created>2026-07-09T12:00:00Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
The Password Digest is calculated as:
PasswordDigest = Base64( SHA-256( Nonce + Created + Password ) )
Most ONVIF client libraries (including Happytime ONVIF Client Library) handle this automatically when you provide the username and password — no manual digest calculation is needed.
Step 5: Testing the Secure Configuration
Test 1: Verify HTTPS is Listening
After launching the ONVIF Server, verify that it is listening on the HTTPS port:
# Using OpenSSL s_client (Windows/Linux/macOS)
openssl s_client -connect 192.168.1.200:8443 -showcerts
# Using PowerShell (Windows)
Test-NetConnection -ComputerName 192.168.1.200 -Port 8443
# Using curl (verify TLS is working)
curl -k https://192.168.1.200:8443/onvif/device_service
The OpenSSL s_client output should show the server's certificate details and a successful TLS handshake.
Test 2: Verify ONVIF Service Endpoint over HTTPS
Send a simple ONVIF GetCapabilities request over HTTPS:
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<s:Header>
<!-- WS-Security UsernameToken (if enabled) -->
</s:Header>
<s:Body>
<GetCapabilities xmlns="http://www.onvif.org/ver10/device/wsdl">
<Category>All</Category>
</GetCapabilities>
</s:Body>
</s:Envelope>
A successful response will contain the device's service capabilities and XAddrs. Under HTTPS, the XAddrs URLs should use https:// schemes.
Test 3: Verify Authentication Enforcement
- Send a GetCapabilities request without a WS-Security UsernameToken header. The server should return a SOAP Fault indicating that credentials are required.
- Send the same request with a valid UsernameToken containing the correct username and password (e.g.,
admin/admin). The server should return a normal capabilities response. - Send a request with an incorrect password. The server should reject it with an authentication-related SOAP Fault.
- Send a request with a non-existent username. The server should reject it with a credential-related SOAP Fault.
Test 4: Verify Certificate Validation (Client Side)
- Attempt to connect to the device over HTTPS without trusting the self-signed certificate. The client should reject the connection with a certificate error.
- Import the certificate into the client's trust store and reconnect. The client should now establish the HTTPS session without errors.
Step 6: Complete Secure Configuration Example
Below is a full onvif.cfg with HTTPS enabled, authentication required, and a complete device identity:
<?xml version="1.0" encoding="utf-8"?>
<config>
<server_ip>192.168.1.200</server_ip>
<http_enable>1</http_enable>
<http_port>8000</http_port>
<https_enable>1</https_enable>
<https_port>8443</https_port>
<cert_file>cert.pem</cert_file>
<key_file>key.pem</key_file>
<http_max_users>16</http_max_users>
<ipv6_enable>1</ipv6_enable>
<wan_ip></wan_ip>
<need_auth>1</need_auth>
<log_enable>1</log_enable>
<log_level>1</log_level>
<log_path></log_path>
<log_mode>loop</log_mode>
<log_max_size></log_max_size>
<log_max_index></log_max_index>
<information>
<Manufacturer>Happytimesoft</Manufacturer>
<Model>IPCamera</Model>
<FirmwareVersion>2.4</FirmwareVersion>
<SerialNumber>123456</SerialNumber>
<HardwareId>1.0</HardwareId>
</information>
<user>
<username>admin</username>
<password>admin</password>
<userlevel>Administrator</userlevel>
</user>
<user>
<username>user</username>
<password>123456</password>
<userlevel>User</userlevel>
</user>
<profile>
<video_source>
<width>1280</width>
<height>720</height>
</video_source>
<video_encoder>
<width>1280</width>
<height>720</height>
<encoding>H264</encoding>
</video_encoder>
</profile>
<scope>onvif://www.onvif.org/name/Secure-IP-Camera</scope>
<event>
<renew_interval>60</renew_interval>
</event>
</config>
Troubleshooting
| Issue | Possible Cause | Resolution |
|---|---|---|
| ONVIF Server fails to start with HTTPS enabled | Certificate or key file not found, or the private key is encrypted with a passphrase. | Verify that cert.pem and key.pem exist in the same directory as the executable and are valid PEM files. If the key is encrypted, regenerate it without a passphrase using: openssl rsa -in encrypted-key.pem -out key.pem |
| Client shows "SSL/TLS handshake failed" | TLS version mismatch or the certificate's CN does not match the host being connected to. | Ensure the certificate's CN matches the IP or hostname used by the client. Use openssl s_client -connect IP:8443 to see detailed TLS negotiation errors. |
| "Certificate not trusted" error on client | Self-signed certificate not in the client's trust store. | Import the server certificate into the client's trusted root certificate store. For Windows, use certutil -addstore Root cert.pem. |
| SOAP requests rejected with "Authentication failed" | <need_auth> is 1 but the client's WS-Security credentials do not match any configured user. |
Verify that the username and password in the SOAP UsernameToken header match one of the <user> entries in onvif.cfg. Check for case-sensitive mismatches and extra whitespace. |
| SOAP Fault: "Credentials missing" | <need_auth> is 1 but the client did not include a UsernameToken in the SOAP header. |
Configure your ONVIF client to include WS-Security credentials. If you do not need authentication during development, set <need_auth> to 0. |
| HTTP still accessible after enabling HTTPS | Both <http_enable> and <https_enable> are 1. |
To accept only HTTPS, set <http_enable> to 0. The server will then only respond on <https_port> (8443). |
| HTTPS works but SOAP responses reference HTTP URLs | The <wan_ip> and <server_ip> may affect XAddr generation. |
Verify that <server_ip> is correctly set. The ONVIF Server uses this to construct the https:// scheme in its service endpoint XAddrs. Check the GetCapabilities response to confirm the returned URLs use the correct scheme and port. |
| Cannot connect to HTTPS from remote network | Firewall blocking port 8443, or <wan_ip> not set. |
Open port 8443 in the server's firewall. If the server is behind NAT, use port forwarding on the router and optionally set <wan_ip> to the public IP address for correct XAddr generation. |
Best Practices
- Use Separate Certificates for Testing and Production: Generate a dedicated self-signed certificate for development testing. For production, obtain a certificate from a trusted CA so clients can validate it without manual trust store modifications.
- Disable HTTP in Production: Set
<http_enable>to0to force all ONVIF traffic over HTTPS. This ensures no client accidentally sends credentials over an unencrypted channel. - Use Strong Passwords for Authentication: Change the default
admin/admincredentials in the<user>block. Use strong, unique passwords for all user accounts, especially Administrator-level ones. - Remove Default User Accounts: Delete or disable the default
user/123456account in production deployments. Only keep the minimum necessary Administrator accounts. - Rotate Certificates Before Expiry: Self-signed certificates typically have a validity of 365 days from creation. Set a reminder to generate and deploy a new certificate before the current one expires, or the ONVIF Server will fail to accept HTTPS connections.
- Test Both Transport and Authentication Independently: First enable only HTTPS (
<https_enable>=1,<need_auth>=0) and verify the encrypted channel. Then enable authentication (<need_auth>=1) and verify credential handling. Isolating the tests makes it easier to identify which layer is causing an issue. - Configure WAN IP for Remote Access: If the device sits behind NAT, set
<wan_ip>to the public IP address. This ensures the ONVIF GetCapabilities XAddrs return the correct externally-routable URLs. - Monitor HTTP Max Users: Adjust
<http_max_users>(default 16) based on your expected concurrent client count. Setting it too low may cause legitimate clients to be rejected; setting it too high may increase the risk of DoS attacks.