Security issue is a challenge for almost all projects, and especially for IoT projects. Since the widespread application of IoT, there have been too many security incidents in the industry.
As the fact standard for IoT communication protocols, the MQTT protocol maintains high security and provides a multi-level security design:
- Transport layer: MQTT is based on the TCP / IP protocol, and SSL/TLS can be used for encrypted transmission on the transport layer:
- SSL/TLS is used to encrypt communication data to prevent man-in-the-middle attacks;
- The client certificate is used as a device identity to verify device legitimacy.
- Application layer: MQTT's security features are used for protection:
- MQTT protocol supports client identity verification with username and password;
- MQTT Broker implements topic ACL control.
EMQX MQTT Broker fully supports various security specifications of MQTT protocol. With built-in security functions, it can be used out of the box without programming, and can quickly eliminate the security risks in the project. The EMQX authentication series will around various levels of security specifications explain how to enable related functions through the configuration of EMQX to finally achieve corresponding security protection.
This article will around the core concepts related to MQTT connection authentication in EMQX, introduce the authentication methods supported by EMQX and the applicable scene. The MQTT related authentication chain, authentication process/principle, and configuration points will be explained through the working mechanism and configuration principles to let you quickly master the EMQX authentication configuration method.
In EMQX, the built-in data sources (files, built-in databases), JWT, external mainstream databases, and custom HTTP APIs can be used as authentication data sources.
Connecting data sources and performing authentication are implemented by plugins. Each plugin corresponds to an authentication method. Therefore, users need to enable related plugins before using the authentication function.
When the client connects, the plugin implements the identity authentication of the client by checking whether its username/clientid and password are consistent with the information of the specified data source.
Authentication methods supported by EMQX:
Built-in data sources
- Username authentication
- Cliend ID authentication
The configuration file, and the built-in database of EMQX are used to provide an authenticated data source, which is managed through the HTTP API and is simple and lightweight.
- LDAP authentication
- MySQL authentication
- PostgreSQL authentication
- Redis authentication
- MongoDB authentication
The external database can store a large amount of data, and can easily integrate with external device management systems.
- HTTP authentication
- JWT authentication
JWT authentication can issue authentication information in batches, and HTTP authentication can implement complex authentication logic.
After changing the plugin configuration, you need to restart the plugin to take effect. Some authentication plugins include ACL function.
Any authentication method will eventually return a result:
- Authentication succeeded: the client authentication succeeded after comparison
- Authentication failed: the client authentication fails after comparison, which is because the password in the data source does not match the current password
- Ignore: The authentication data is not found with the current authentication method, and the result cannot be determined explicitly, and will use the next method of authentication chain or anonymous authentication to determine the result.
Anonymous authentication is enabled in the EMQX default configuration and any client can access EMQX. When the authentication plugin is not enabled or the authentication plugin does not explicitly allow/deny(ignore) the connection request, EMQX will decide whether to allow the client to connect based on whether the anonymous authentication is enabled.
Configure the anonymous authentication:
# etc/emqx.conf ## Value: true | false allow_anonymous = true
Please disable anonymous authentication in production environments.
Password salting rules and hash methods
The hash method can be enabled in most EMQX authentication plugins. Only the password cipher text is saved in the data source to ensure data security.
When the hash method is enabled, the user can specify a salt for each client and configure a salting rule. The password stored in the database is the processed cipher text according to the salting rule and hash method.
Taking MySQL authentication as an example：
Salting rules and hash method configuration：
# etc/plugins/emqx_auth_mysql.conf ## only hash is used without salt auth.mysql.password_hash = sha256 ## salt prefix: use sha256 to encrypt salt + password auth.mysql.password_hash = salt,sha256 ## salt suffix: encrypted password using sha256 + salt auth.mysql.password_hash = sha256,salt ## pbkdf2 with macfun iterations dklen ## macfun: md4, md5, ripemd160, sha, sha224, sha256, sha384, sha512 ## auth.mysql.password_hash = pbkdf2,sha256,1000,20
How to generate authentication information
- Assign user name, Client ID, password, and salt for each client
- Use the same salting rules and hash method as MySQL authentication to process client information to get cipher text
- Write the client information to the database. The client password should be cipher text information.
EMQX authentication process
- The authentication data such as password (ciphertext) and salt are queried according to the configured authentication SQL combined with the information passed in by the client. If there is no query result, the authentication will terminate and return the ignore result.
- The cipher text is calculated according to the configured salting rule and hash method. If no hash method is enabled, this step is skipped.
- Compare the cipher text stored in the database with the cipher text calculated by the current client. If the comparison is successful, the authentication succeeds. Otherwise, the authentication fails.
Taking PostgreSQL authentication as an example, its functional logic is as follows:
The authentication can be performed normally when the salting rules and hash method of the written data are consistent with the configuration of the corresponding plugin. It will invalidate existing authentication data when changing the hashing method.
When enabling multiple authentication methods at the same time, EMQX will perform chain authentication in the order in which the plugins are opened:
Once authentication succeeds, terminate the authentication chain and allow clients to access
Once authentication fails, terminate the authentication chain and prohibit client access
If Failing to pass until the last authentication method, it is determined according to anonymous authentication configuration
- Allow client access when anonymous authentication is enabled
- Deny client access when anonymous authentication is disabled
It can improve client authentication efficiency when enabling only one authentication plugin at the same time.
MQTT TLS authentication
The default port for MQTT TLS is 8883:
listener.ssl.external = 8883
Configure certificates and CAs:
listener.ssl.external.keyfile = etc/certs/key.pem listener.ssl.external.certfile = etc/certs/cert.pem listener.ssl.external.cacertfile = etc/certs/cacert.pem
Note that the
cacert.pem under the default directory of
etc/certs are self-signed certificates generated by EMQX Broker. Therefore, when testing with a client that supports TLS, you need to configure the above CA certificate
etc/certs/cacert.pem to the client.
The cipher list supported by the server needs to be specified explicitly. The default list is consistent with Mozilla's server cipher list:
listener.ssl.external.ciphers = ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-SHA384,ECDHE-ECDSA-AES256-SHA384,ECDHE-RSA-AES256-SHA384,ECDHE-ECDSA-DES-CBC3-SHA,ECDH-ECDSA-AES256-GCM-SHA384,ECDH-RSA-AES256-GCM-SHA384,ECDH-ECDSA-AES256-SHA384,ECDH-RSA-AES256-SHA384,DHE-DSS-AES256-GCM-SHA384,DHE-DSS-AES256-SHA256,AES256-GCM-SHA384,AES256-SHA256,ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256,ECDHE-ECDSA-AES128-SHA256,ECDHE-RSA-AES128-SHA256,ECDH-ECDSA-AES128-GCM-SHA256,ECDH-RSA-AES128-GCM-SHA256,ECDH-ECDSA-AES128-SHA256,ECDH-RSA-AES128-SHA256,DHE-DSS-AES128-GCM-SHA256,DHE-DSS-AES128-SHA256,AES128-GCM-SHA256,AES128-SHA256,ECDHE-ECDSA-AES256-SHA,ECDHE-RSA-AES256-SHA,DHE-DSS-AES256-SHA,ECDH-ECDSA-AES256-SHA,ECDH-RSA-AES256-SHA,AES256-SHA,ECDHE-ECDSA-AES128-SHA,ECDHE-RSA-AES128-SHA,DHE-DSS-AES128-SHA,ECDH-ECDSA-AES128-SHA,ECDH-RSA-AES128-SHA,AES128-SHA
If you want to use PSK authentication, you need to comment out
listener.ssl.external.ciphers in TLS Authentication, and then configure
#listener.ssl.external.ciphers = ECDHE-ECDSA-AES256-GCM-SHA384,... listener.ssl.external.psk_ciphers = PSK-AES128-CBC-SHA,PSK-AES256-CBC-SHA,PSK-3DES-EDE-CBC-SHA,PSK-RC4-SHA
Then, enable the emqx_psk_file plugin:
$ emqx_ctl plugins load emqx_psk_file
The configuration file for PSK is
etc/psk.txt. A colon
: is used to separate the PSK ID and PSK: