RBAC model in openHAB (and potential security vulnerability found)

Hi everyone,

In the context of my thesis where the topic was role-based access control for openHAB users, I implemented the beginning of the RBAC model in openHAB in this fork at the temp branch.

Groups (of roles) and roles are managed in openHAB, where each user contains roles and groups. Users, groups, roles are stored persistently in registries. Each group contains roles. Each role contains Item names that are unique. An Item name identifies an Item. An Item represents a resource of the platform. Therefore, the set of Item names within a role
specifies the authorized resources (Items) that the role will assign to users who own the role.

Roles and role groups can be assigned to a user with the openhab:users command and the openhab:ac command. Functions have been added to the openhab:users command and the openhab:ac command did not exist and thus has been added. The main interface has also been modified a bit to see the available users with their roles and groups, the available groups, and the available roles.

OpenHAB uses JWT to manage the access control of the platform. For each request from a user (client side) made to openHAB (server side), the JWT is checked, and the user’s name is extracted from the JWT payload. With the user’s username, the groups and roles that belong to the user can be obtained. With the obtained groups and roles, the Item names are collected to know which Items (resources) should be returned to the user. The user (on the client side) will only see in his interface the resources that correspond to his authorized elements. As a result of this filter and the management of roles and groups in openHAB, the role-based access control model has been incorporated into openHAB.

The code is not yet clean for a pull request and all HTTP requests for items are not yet handled (but for the most part yes). A video has been made to summarize what has been done at this link. A scenario has been configured which is a house with a family where the user with the administrator role is the father and the three children have the role of user. The scenario shows the usefulness of the RBAC model in openHAB. In fact, each child can only have access to his or her own devices because the father has configured openHAB’s access control with roles and groups such that each child can only access his or her own smart home devices.

By implementing the RBAC model in openHAB, some potential vulnerabilities were found, and should be fixed, and announced and explained as follows:

  1. The functions of the openah:users command in the openHAB console allow a user to delete an openHAB user or create an openHAB user. These actions can be performed by any user with access to the smart home openHAB console. So, let’s assume that a user with the least privilege in the platform or even a malicious person knows the password of the openHAB console (by default it is habopen and can be changed) and manages to reach it. He will be able to delete users with the administrator role and create a new user with the administrator role whose password he knows. As a result, the single user or malicious person removes all access of the users with the highest privilege and gets all access to the platform. This security vulnerability should be fixed by asking for the password and username of an openHAB user with the administrator role (this is implemented in this fork). Additionally (this is not implemented in the fork), a check that the parse string (which contains the username and password) contains only alphabetic numbers and letters should be done to add protection against the buffer overflow attack.

  2. The password sent by a user to the platform is not hashed. Therefore, a person can scan the smart home’s local network and retrieve the password of the user who may be a user with the role of administrator. To prove this security vulnerability, the local network where an instance of openHAB is running was scanned with Wireshark and as shown in the Figure below, the password of the user nico can be obtained. To solve this security problem, the password must be hashed on the client-side and the server-side must store the hashed password and verify the password with the hashes. \

  1. JWTs are used by openHAB to authenticate each request of openHAB users. Therefore the JWT must be checked for each request made by a user of openHAB. However, in openHAB, a user’s JWT is checked only when the client-side page is refreshed. Therefore, anyone can forge an HTTP request and send it to the server to get information about the smart home for example. The server will accept the HTTP request because it does not check the JWT in the HTTP request header. In the fork where the RBAC model has been implemented (see the code here), the security vulnerability has been fixed for HTTP methods that are used and managed to handle RBAC for openHAB users but have not been fixed for all HTTP methods used and managed by openHAB.

  2. The user (client-side) has to verify the JWT put in the HTTP response with the RSA public key that matches the RSA private key used by openHAB (server-side) to generate the JWTs. With this verification, the user (client-side) can be sure that the HTTP response is coming from openHAB (server-side). However, the client does not receive the RSA public key to verify the JWT in the HTTP response header. Therefore, anyone can forge and send a fake HTTP response to a user (client-side) and the user will accept the fake HTTP response because the JWT in the HTTP response header is not verified. To solve this security problem, the user (client-side) must receive the RSA public key used by openHAB (server-side) to generate the JWT. Then, the user (client-side) must verify the JWT in every HTTP response received by openHAB (server-side).

However, a malicious person is able to exploit any of the above security vulnerabilities only if he/she has access to the local network where openHAB is running. Considering that the local network is a network with the minimum security that is required. In order to access the local network, the user needs to know the Wi-Fi password of the local network. Furthermore, the local network is protected by a firewall. In addition, HTTPS can be used in openHAB. So if HTTPS is used, (for the second security vulnerability listed above) the password cannot be recovered but it is still better to send and handle passwords that are hashed, and (for the fourth security vulnerability listed above) the client side will not accept incoming fake HTTP responses because of the HTTPS connection. However, even with HTTPS, the third vulnerability (among those listed above) can be realized because the server accepts HTTP requests. In this link in the openHAB documentation, it says that it is vitally important that the openHAB instance is not exposed to the internet because there is no authentication in place for the users and surely because of the potential security vulnerability found.

To conclude, fixing these security vulnerabilities should be a contribution that should be made to openHAB. I plan to put the written thesis in a reply to this post once the defense is done.

Enjoy the video. (here)

Thanks to the help of the openHAB community where it would not have been possible to achieve what I did.

Thank you,

Nicolas Gennart.

4 Likes

This is somewhat related to the Zero trust security model - Wikipedia I recently read.

1 Like

Yes, this is the case if openHAB (server-side) authenticates every message made by every device (so from many different protocols) and every user, but in this case, it should be a zero-trust security model for users, not for all IoT devices in the smart home. If I understand correctly what you mean.

Few remarks from history perspective as you are not first student who works in the topic. :slight_smile: I think I remember two. Looking forward to see your work integrated with openhab main line.

Initially basic auth stuff was connected to jaas so in theory you could have one realm for everything - ie. karaf realm for shell/ssh users and UI users. Yet this is not how usually it is being done. Assumption that someone with access to shell has same privileges as user having an access to user interface is wrong. By example I can refer to Red Hat and their Wildfly application server (used between others also by Keycloak, an authorization server) differentiate “system” and “application” users. That’s the case you see here.
Access to openhab (karaf) shell is fenced by separate username and password (fair, a default one), but also host system ssh username and public key/password. Adding security measurements there only for openhab commands makes no point because if someone is there - he can completely disable authentication by modifying configuration (see config:edit and config:property-set with config:update commands) or install a malicious module which ie. log passwords in plaintext. For such cases there is a karaf security framework which can limit access to commands based on user role.
Problem with this lies somewhere completely else. Currently openHAB uses two ways to retrieve data - REST services, ones you started to modify and, in some places, also servlets. For example a ChartServlet or an IconServlet are two who are still there. While later one is least risk (it hosts resources, but AFAIR it also can draw a on or/off in some cases), the first one retrieves some data so it could be exploited to obtain a item state information.
For that reason the initial design of authentication mechanism included a concept of CredentialExtractor which works in a given context - ie. HttpRequest in Servlet or ContainerRequest in REST services. By this way you can unify a processed credential instance to ie. username/password, oh-token or jwt-token. Currently this design is not used and rest services are secured with jwt and oh-token while servlets are left behind.
I been working on this topic a while ago in opensmarthouse (a public openhab fork I use), please have a look on this change set Reorganization of authentication and security API. · opensmarthouse/opensmarthouse-core@947e116 · GitHub.
Lately I also come to the point that a CredentialExtractorFactory (new api) could simplify adoption of that mechanism. There is also an open question how to threat a partial failure - ie. when cookie is still alive but authorization header (jwt) did expire.

I believe that’s the case - it is done by AuthFilter and JwtHelper, isn’t it? If not, can you provide an example HTTP call which could lead to vulnerability?

It depends, if makes a ton of sense if client side code is willing to parse incoming token and its data. Namely - if the access token is used as an JWT on client end, if not then its just another session key. Obviously making a security check there is welcome, yet severity of vulnerability is arguable.

Its hard for me to follow all your code as there are multiple changes, but I think you also touched the authorization part which involves items. If you plan to go that path, again I can point you at what I did within opensmarthouse fork: Proof of concept support for authorization. · opensmarthouse/opensmarthouse-core@ee3494c · GitHub, this change introduces a permission into the authentication object (an open user session) which can be used for authz functionality. With plugable evaluators (verifiers) filtering of visible items, things, pages, widgets or rules can be achieved. Later I removed permissions from JWT as it had no point there (AFAIR user interface do not make use of JWT), and just read it back from local (managed) user record read from the store. Main point in this design is detaching from a “role”, as it is not expressive enough to cover a variable set of objects such as “things”, “items” or “rules” which are used in openHAB, and start dealing with more abstract structure which can also hold actual action - command/read for item or update/disable/enable for a thing.
I know years back some people were scarred of introducing authz as it would affect rules and other parts of the system but reality is - the context of rule execution is related to the context of trigger and this depends on the user.

1 Like

I didn’t know that it was also possible to corrupt the system in this way. Therefore, adding a security check or restriction to the Karaf commands that handle access control for users should be implemented or it will be strongly recommended to change the Karaf console password. Indeed, once a user has access to the openHAB console, they can completely corrupt the running instance of openHAB and manage the smart home devices connected to the platform.

As stated in the documentation here, there is no authentication for HTTP requests, so the vulnerability affects all HTTP methods that handle resources on the platform. To forge an HTTP request, it can be easily achieved by running Java code that makes an HTTP request to OpenHAB. OpenHAB will resolve the HTTP request because there is no authentication for HTTP requests (the JWT in the header of an HTTP method is not checked). The JWT is only checked when the page is refreshed. Therefore, since the JWT is not checked for the HTTP request, the resources of the openHAB can be modified and obtained.

As you said, to verify the JWT and thus authenticate the HTTP methods, this can be done with the AuthFilter and JwtHelper classes. Unfortunately, these classes are not available to other bundles that manage the platform’s REST resource (because they are located in the internal package of the org.openhab.core.io.rest.auth bundle). This means that no openHAB bundle uses these two classes and therefore no HTTP methods are authenticated in openHAB. To implement the RBAC model in openHAB I had to authenticate each HTTP request to know which resources should be returned to the request based on the roles and groups assigned to openHAB users. As a result, I added a VerifyToken class that can be called for other bundles to be able to authenticate HTTP requests. (see this post where I asked a question about it)

Yes, this is not a highly recommended security feature as long as HTTPS is used. But if HTTPS is not used it is recommended to have such an implementation as a smart home contains very sensitive occupant data and therefore the risk should not be neglected. (this is my opinion)

Thank you for sharing your code. Yes authz should be very useful for openHAB and will greatly improve the security of the platform. For my part, I have only managed access to simple users who do not have access to rules, configurations, etc.

What I want to emphasize by incorporating the RBAC model into openHAB (but not accepted by the openHAB community and not finished for the whole platform) is to incorporate authentication of every HTTP request as a first step. In the documentation, there is the following sentence (here):
openHAB does not (yet) support restricting access through HTTP(S) for certain users - there is no authentication in place, nor is there a limitation of functionality or information that different users can access.
And just after:
Security Warning: It is vitally important that you MUST NOT directly expose your openHAB instance to the Internet (e.g. by opening a port in your firewall)!
As a result, authentication of HTTP requests is not yet implemented in openHAB. Authenticating every HTTP request in openHAB (with the AuthFilter and JwtHelper classes) will greatly increase the security of the platform. Furthermore, this security feature can be easily added to openHAB because the classes (AuthFilter and JwtHelper) for authenticating an HTTP request are already implemented and the client (connects to openHAB) already puts his JWT in every HTTP request. The only thing left to implement is that the functions in the AuthFilter and JwtHelper classes must be called for each REST function to check the JWT and thus authenticate each request made by a user to openHAB.

There are few places where basic HTTP access is being used which I listed above. You can look for more by checking occurrences of javax.servlet.http.HttpServlet or javax.servlet.Servlet types in imports. There is also a base class called BaseOpenHABServlet which was provided initially as part of security PR against eclipse smarthome in order to have a unified handling of that part. It used to work together with OpenHABHttpContext which handled security.
There are some addons which need to expose a http endpoint to handle authentication callback from cloud applications, hence you might find more of them there. In some cases I think they should make sure that redirect coming from external service brings back a browser instance which is same as one which initialized process (so it has a valid openhab session cookie) to reduce risk of pushing a strangers data into system.

There is an authentication but there is no fine grained authorization. Anyone with access to openHAB with “user” rank, can interact with any item defined in the system.

This is the point I made earlier about CredentialExtractor. It was intended to be used as a bridge between an invocation place and actual authentication provider so there is no pinning to JWT, Cookie or Form (user/password) as authentication requirements are different in various places.
Current way OH does it is limited to REST cause earlier way was abandoned and left behind. There was an intermediate need to enable security in OH 3, so its there, but its not complete.

From technical perspective a lot, if not all, of openHAB servlets could be migrated to REST resources, however this makes some basic things (ie. resource handling) more complicated. Implementation of servlet is fairly basic while rest resource works at completely different abstraction level. More over for REST services you normally need to declare what you wish to receive (@Cookie or @Context) while servlet has access to all this information through request object. You can also mimic a servlet by replacing HttpRequest with ContainerRequestContext. :slight_smile:

An authentication attempt in earlier design was possible through AuthenticationManager. The JWT is an implementation detail and should not be assumed to be only one. AuthenticationManager is available to everyone as it is a part of core auth api and it allows to check various credential types, yet JWT was not designed as a credential and it is processed directly by filter. It is again something which was made as part of OH 3.0. Commits to openHAB fork I linked earlier are adjusting that situation so there is a clear separation between AuthenticationProvider (ie. LocalJWT) and credential (JWT, Cookie). With this design it is also possible to provide another JWT authentication provider which will rely on tokens issued by third party IdP.

It is up to you how you wish to solve troubles you found. Depending on how you wish to proceed - you might bring your own auth api to replace one introduced in OH 2.4/2.5 or align to that. I don’t insist on any of these as what OH has currently is fine but in some places smells like a workaround. :slight_smile:

Cheers,
Łukasz