Securely store IoT data, expose that stored data through protected APIs, and call protected APIs from mobile and web applications
An important security goal in cloud-based IoT applications is to ensure that sensitive and private data from devices cannot be accessed by unauthorized users. The application also needs to guard against sending unauthorized commands to the device. This article, part 3 of a three-part series, will look at the different ways to secure web and mobile applications processing IoT device data. Sections 1 and 2 list the details of securing the device and how to secure the communication between the device and the network. Approaches to securing web and mobile applications that process IoT device data show the approaches described in this article. Mobile and web clients have specific security mechanisms in place to ensure that only authenticated users can access the application. The core of the application logic is in the IBM Cloud-based back-end services. This application logic pulls data from IBM Watson IoT Platform (by using the protected Watson IoT Platform APIs), analyzes the data, and then sends commands to control the device. Ways to secure web and mobile applications that process IoT device data.
This article assumes that you know how to develop and work with IBM Cloud applications. If you're new to IBM Cloud, consider taking the tutorials in the IBM Cloud Fundamentals learning path. This article won't go into detail about how to develop a web or mobile app; Explain only how to add security features to a web or mobile application. The IoT Security Demo Server application we created for this article will subscribe to Watson IoT event data and persist the received data in the Cloudant database. When persisting data, such as payloads from IoT devices, the IoT Security Demo Server application encrypts some sensitive attributes of the stored data. The payload is in JSON format and stored in a Cloudant database in AES encrypted format. It will be decrypted when it retrieves the authorized user. Encryption and decryption are transparent to users.
Get an IoT Security Demo Server application**When you add an Internet of Things Platform service to IBM Cloud, access credentials are generated for your application (such as the one shown below) that grant you access to the IBM Watson IoT Platform.
Subscribing to events and status updates for the Watson IoT Platform is simple, as shown in the following paragraph:
var iotfclient = require("ibmiotf").iotfapplication;var iotconfig = ;var iotfclient = new iotfclient(iotconfig);iotfclient.connect();iotfclient.on("error", function (err) )iotfclient.on("connect", function ()iotfclient.on("deviceevent", function (devicetype, deviceid, eventtype, format, payload) )iotfclient.on("devicestatus", function (devicetype, deviceid, payload, topic) )
With this, whenever an IoT event is received, the event and associated payload are inserted into the Cloudant database.
Data stored in an IBM Cloudant NoSQL DB instance is always encrypted, which is referred to as encryption at rest. Learn more about Cloudant data protection and security in the IBM Cloud documentation. However, you can implement a custom encryption method to ensure that sensitive data is protected.
The encryption and decryption of stored and retrieved data can be based on the industry-standard AES-256 algorithm, as shown in the following paragraph:
var crypto = require('crypto');var algorithm = 'aes-256-ctr';var cryptokey = 'your-key';function encrypt(text)function decrypt(text)
Encrypting data comes with a performance cost, especially when processing large amounts of data, so it's important to consider and implement the right approach.
Learn more about Cloudant data protection and security in the IBM Cloudant documentation. You can directly access IoT data stored in your Cloudant database in one of two ways:
If the Cloudant API key is shared, the third-party application is used. Create your own custom APIs protected by IBM Cloud Security services. Third-party access using Cloudant API keys When you add a Cloudant DB service to IBM Cloud, you generate access credentials like the following for your application to enable your programs to programmatically access the CloudAnt database.
, "syslog_drain_url": null, "volume_mounts": ["label": "cloudantnosqldb", "provider": null, "plan": "lite", "name": "iotsecuritydemo‑cloudantnosqldb", "tags": "data_management", "ibm_created", "lite", "ibm_dedicated_public" }
You can use this username and password to generate a Cloudant API key as follows:
post _api/v2/api_keys
Once the key is generated, you can use the API key like a normal user account, such as granting read, write, or administrative access.
post https://.cloudant.com/_api/v2/api_keys
The response will look similar to the following
"password": "ypncaix1sjrx5upal3eqvtfi","ok": true,"key": "blentfortedsionstrindigl"
An API key is required to grant access to a specific database. Use the PUT request shown below to access your database.
https://.cloudant.com/_api/v2/db//_security),
Note that it is also possible to generate an API key from the Cloudant dashboard, as shown in the following image.
API key password pairs can be treated like any other user account. You can pass an API key to a call to share a database with it and assign permissions to it. You can use the API key password pair for any situation where a user account is not suitable, such as when you have credentials in your source**, and when you need to programmatically create multiple accounts with different permissions.
The API response contains the following properties:
okReturns when the request is successful. errorReturned when the request was unsuccessful, with an error. keyReturns the API key. passwordReturn the API password. Third-party access using custom APIs makes third-party integrations fragile and expensive to maintain by providing direct access to Cloudant databases. One recommended architecture is to use custom APIs to provide an encapsulation layer on top of the database. Custom APIs will hide database-specific details and return device information from specific interface contracts.
The first custom API in our IoT Security Demo Server application allows you to use thishttp
Request access to the list of devices:
http:///iotf/devices
For example, to access data from a list of devices stored in the Cloudant database in our IoT Security Demo Server application, you can use the following request:
The second custom API in our IoT Security Demo Server application allows you to use thishttp
Request access to data for a specific device:
http:///iotf/devices/
For example, to see the last 50 events in our IoT Security Demo Server application and their targeting device JThe payload of Patra, which can be used with the following requests:
/j.patra
Finally, you can request a specific number of events by specifying an extra parameter on the request:
http:///iotf/devices/?count=
For example, to see the last 5 events in our IoT Security Demo Server application and their targeting device JThe payload of Patra, which can be used with the following requests:
/j.patra?count=5
user
withusergroup
Objects are custom authentication and authorization objects that provide secure, role-based access to data stored in Cloudant databases. This article uses a custom authentication provider to use theseuser
withusergroup
Object.
When using custom APIs, you may want more control over user authorization to access device data and send commands to the device. To gain this control, you can do so in Cloudantuser
withusergroup
Create a set of custom documents.
This set of custom documents in Cloudant is used to perform role-based authorization for the custom authentication provider implemented in this IoT Security Demo Server application.
Here are the customizationsuser
Example of documentation:
Here are the customizationsusergroup
Example of documentation:
The custom authorization provider developed in this article uses the above User and UserGroup documents from the Cloudant database.
Learn more about getting started with IBM App IDs in the IBM Cloud documentation. Once your data is protected and exposed through custom APIs, the next step is to secure those APIs with authentication and authorization. Web and mobile apps need to provide the necessary authentication credentials to call these APIs, and can only access data from devices to which they have access. To protect custom APIs, this article uses the IBM App ID service on IBM Cloud.
The custom API in this article is to use Nodejs development. To secure the API endpoint, the NodeThe API Handler method in JS has been enhanced. The password authentication middleware is a nodeA JS Passport instance, which has been initialized with an IBM App ID policy object so that authentication requests are intercepted and processed by the IBM App ID Server SDK.
Web applications that provide access to IoT device data need to be secured with the username and password combination of the application user. In our web application, a back-end user registry, such as the IBM Cloud directory, is used to store all user information.
The App ID service supports three identities for user credentials**
Before an app developer can embed the App ID feature into an app, an administrator must create a service instance and add an identity**. Perform the following steps to add the App ID feature (by using the IBM Cloud Catalog) to your web application.
Set up the App ID service in IBM Cloud and create a new IBM Cloud directory.
Add users to your cloud directory. See the image below
The following snippet is from the IoT Security demo application that demonstrates how to use IBM App IDs to secure custom API endpoints (IoTF devices).
Pass authentication middleware is usedapistrategy
to validate the incoming request. It will look for the authorization field in the HTTP header of the request. For App IDs, the authorization header consists of three different tokens, separated by spaces: the keyword bearer, the access token, and the optional identity token.
const passport = require('passport');const apistrategy = require("bluemix‑appid").apistrategy;app.use(passport.initialize())passport.use(new apistrategy())// declare the api you want to protectapp.get(iotroutebase + '/devices',passport.authenticate(apistrategy.strategy_name,),function(req, res) else })
As a REST API with the appropriate authentication header, this protected API can be accessed from the client application. Subsequent sections discuss how to implement web and mobile clients that will call these APIs.
Read more about IBM Cloud security in the IBM Cloud documentation To protect IoT client applications, you can use a unified authentication method for web and mobile applications. The IBM Cloud platform provides security at the platform, data and application levels.
Figure 3 illustrates the unified authentication and authorization approach based on the App ID service. With this unified authentication method, both mobile and web apps use the same App ID-based authentication provider and a custom Cloudant-based authorization provider to protect device data and limit who can send commands to the device.
Same authentication, same protected application.
In this section, we'll take a look at how to access our protected custom IoT APIs from your web application based on the authentication and authorization associated with the logged-in user profile.
The steps are as follows: The client program uses the App ID client SDK by being specific to the App ID instanceoauthserverurl
Provide the App ID Tenant ID and Client ID and the key to initialize the session with the IBM App ID instance. Client program uselogin_url
Start a sign-in session with your App ID. The App ID displays a login page to the user, validates credentials at submission, and returns an access token and identity token. The client program calls a protected endpoint on the server (in the case of a secure presentation server application/iotf/devices
)。When it does this, it sets the authorization header with an access token and optionally an identity token in the request. The App ID server-side SDK (set up as pass middleware on the protected endpoint) will verify that the provided access token and (optionally) identity token are valid. If valid, the App ID server-side SDK will allow the endpoint handler to be called. Otherwise, it returns a response with HTTP 401 Authorized. Here's a snippet from the IoT Security Demo Web Application that demonstrates how to secure web application logins using IBM App IDs.
const webappstrategy = require("bluemix‑appid").webappstrategy;// configure express application to use passportjsapp.use(passport.initialize())app.use(passport.session())const login_url = "/ibm/bluemix/appid/login";const callback_url = "/ibm/bluemix/appid/callback";const landing_page_url = "/iot_sample_app.html";// configure passportjs to use webappstrategypassport.use(new webappstrategy())// explicit login endpoint. will always redirect browser to login widget.// if forcelogin is set to false redirect to login widget will not occur// for already authenticated users.app.get(login_url, passport.authenticate(webappstrategy.strategy_name, )// callback to finish the authorization process. will retrieve access and// identity tokens from app id service.app.get(callback_url, passport.authenticate(webappstrategy.strategy_name));
After the user has successfully logged in, we will display the user a page to get the device data that the user has permission to view. To do this, we start with a custom nodeThe JS server calls two protected custom APIs
/iotf/devices
Used to obtain a list of authorized devices/iotf/devices/:deviceid?count=n
Used to get the last n device data (also known in IBM IoT terminology.)deviceevent
)。Learn more about the IBM App ID authentication header structure. To access the protected API, we need to set the authorization token correctly in the request header. The following snippet from the web application side (client) demonstrates the same thing.
// protected area. if current user is not authenticated ‑ redirect to the// login widget.// in case user is authenticated ‑ a page with current user information// will be returned.app.get("/protected", passport.authenticate(webappstrategy.strategy_name),function(req, res) }request.get(options, function (error, response, body) else }
IBM App ID services can also be used to provide services to ensure the security of mobile applications. The process is exactly the same as securing a web application.
Mobile devices use the App ID client SDK to initialize a session with a specific instance of the App ID by providing the App ID Tenant ID and Region ID. The mobile device initiates a sign-in session with the App ID, specifying whether this is an anonymous or credential-based login. If this is an anonymous login, the App ID immediately returns the appropriate access token and identity token. If this is a credential-based sign-in, the App ID displays the sign-in page to the user, validates the credentials at submission, and returns an access token and an identity token. The mobile device uses the request class provided by the App ID client SDK to call the protected endpoint on the mobile app backend (in our Secure Demo Server application/iotf/devices
)。The App ID client SDK adds the cached authorization header to the request, calls the protected API on the endpoint, and verifies that the provided access token and (optionally) identity token are valid. If valid, the App ID server-side SDK will allow the endpoint handler to be called. Otherwise, it returns a response with HTTP 401 Authorized. The authentication flow examines whether Facebook, Google, or IBM Cloud directories have been configured for the App ID service. It returns the results to the App ID server-side SDK. When the authentication flow against the App ID server-side SDK is successful, it calls the protected endpoint (in our secure demo server application/iotf/devices
endpoint handler. The following snippet shows how to initialize the App ID client SDK.
You can find your tenant ID in the Service Credentials section of the IBM Cloud App ID dashboard.
// initialize ibm cloud appid service sdk with tenant id and region of the// appid service to connect to// you can find your tenant id and region in the service credentials section//at left hand side of your appid service dashboard appid = appid.getinstance();appid.initialize( getapplicationcontext(),deviceiotdemoapplication.ibmcloudappid_tenant_id, deviceiotdemoapplication.ibmcloudappid_region_id); bmsclient = bmsclient.getinstance();bmsclient.initialize( getapplicationcontext(),deviceiotdemoapplication.bmsclient_region_id );
After initializing the SDK, determine whether the login is anonymous or with specific credentials. To initiate a login, use the following snippet:
public void startloginactivity(view view)
When the authentication process succeeds or fails, the widget will be **appidauthorizationlistener
Once successful, you can make a request to the protected API:
http:///iotf/devices
To make a request to the above endpoint from the mobile app, you can use the App ID for Android client SDK provided in the SDKrequest
Class:
new request( server_hostname + "/iotf/devices/", request.get).send( deviceiotdemoapplication.get(),new responselistener() override public void onfailure(response response, throwable t, jsonobject extendedinfo)
Custom nodeWhen a throttled server API is called on a JS serverrequest
The class passes the authorization access token and identity token received from the App ID service as the request header. The server is used before the business logic is executedapistrategy
Validate the token against the App ID service.
The mobile Android client sample app we developed for this article first asks the user to sign in. Users can log in anonymously if needed.
For users who wish to sign in, the mobile app is obtained from the appid instanceloginwidget
and give control to the sign-in widget. The login widget will control the web-based login page that collects usernames and passwords, ensuring that the mobile app doesn't directly access these credentials.
Get the mobile Android client ** The Android app implements a custom authorization listenerappidauthorizationlistener
。This class will handle ** notifications from the login widget about authorization success, failure, and similar events. On success, this listener implements a custom methodgetauthorizeddevices
to customize the nodeThe call on the JS server is restricted/iotf/devices
api。
After successful authentication, the device API will return a list of devices that this user has permission to view. Each device is displayed in a separate tab in the application UI. Each tab displays the last event for the corresponding device, by customizing the nodeAnother restricted API is called on the JS server to get it. The timestamp of the event and the sensor payload data are displayed.
public class customauthenticationlistener implements authenticationlistener @override public void onauthenticationchallengereceived ( authenticationcontext authcontext, jsonobject challenge, context context) catch (jsonexception e) }
For this article, you can use our device simulator program to simulate the payload data. The IBM Cloud platform that gets the device emulator also offers services to help you scan or monitor your apps. For example, the IBM Application Security on Cloud service ensures that there are no security vulnerabilities in the application. Developers can use these services to scan web and mobile applications for vulnerabilities, identify security issues, and implement recommended fixes prior to deployment. In addition, the App ID service provides a dashboard to monitor and analyze the usage of mobile applications and security events in the device, such as successful or failed authentication. Security must be an important area of concern for applications that analyze sensitive data from IoT devices, as well as applications that control the functionality of those IoT devices. In this article, we focus on securing the IoT application layer running on the IBM Cloud platform. You learned how to use IBM Cloud security services to implement common user authentication and authorization across web and mobile applications, and how to store sensitive data securely in a Cloudant database.