Security Feature: Hashed API Password for Rest API

Hello HA Community,

I have been thinking a lot about security lately as we all have been. And I have come up with an idea that will help boost security and protect our API passwords by not needing to store them on external services like IFTTT, Stringify and others.

NB: I am not a developer, I am a network and security engineer by trade so I do not have the means to implement this myself.

Currently, if I want to execute a script externally, I will run a http POST to a url like the below:
https://myurl.duckdns.org:8123/api/services/script/lights_on?api_password=MYSECUREPASSWORD

Now we can all see the problem with this. My password is stored in cleartext on an external service and the security of my whole HA ecosystem is dependent on protecting that password. If someone were to get that password they could do horrible things to me and my family. They would have undetected access into my home network and do unimaginable things.

My proposed solution is a hashed API password. The hash would take two inputs, being:
1.) The URI (path) of the request, in this example it would be “api/services/script/lights_on”
2.) My actual password, in this example it would be “MYSECUREPASSWORD”

So the http POST request would look more like:
https://myurl.duckdns.org:8123/api/services/script/lights_on?api_hash=fg34h3#$%T34gf24TG@$t

This would result in a unique hash for each unique API call to my HA. For example, “api/services/script/lights_on” would have a different hash to “api/services/script/lights_off”. Furthermore, if the URI (path) were to be discovered, or if IFTTT was to be compromised, my API password has not been revealed.

I know this would not be trivial to implement, but I believe a lot of the community would be very appreciative of something like this.

You don’t have to use the URL parameter you can set the X-HA-Access header equal to your password instead and since you are using SSL the headers will be encrypted.

I also understand that the URL parameter is encrypted when using HTTPS. I am more interested in protecting the “data at rest” than the “data in transit” in this example. How likely is it that someone is going to be sniffing network traffic to find something interesting in the URI? I think the real danger is storing this information (“data at rest”) in plain text on external services.

Ahhh okay, that’s fair.

This should be pretty easy to do, not sure why it hasn’t been done already? I just put something together real quick and it is working. I was able to sha256 12345 which is the password I had set in my config and then send the API the following call. I didn’t remove regular password, just added sending a hash as well.

curl --header "X-HA-Access: 5994471abb159f6cc74b4f511b99806da59b3caf5a9c173cacfc5" 192.168.1.2:8123/api/config

I am sure there is a better way to do it than what I did, but I might try to take a stab at it and open a PR if it doesn’t work out maybe a more experienced HA dev will implement it correctly.

Thanks for taking a crack at this.

It will need to be a hash of the http path and the password, otherwise you run into the same issue of just applying the repeated hashed value to an API call (The hashed value basically becomes your new password for API calls). This way the hashed value will be different for each different type of API request. So when the API is receiving the request, it will be able need access to the http path and the password.

So in your example, you will be hashing “/api/config12345”

Man you are right again, I am just not thinking. That would be more difficult. I’ll think on it.

Industry standard is OAuth 2.0, I am sure it is on somebody’s Todo list.

OAuth2 is IMHO somewhat orthogonal to this request, since here we are talking about some sort of fine grained permission at API resources level. I really like this idea. Gpslogger component implemented it on its own - you can call gpslogger API using separate password.
I guess (without looking at code) that it should not be complex to implement: in the authorization module in addition to authorizing calls with plain password we would authorize calls with hashed password (based on plain password and path).

Idea of OAuth2 is you create different client for your different 3rd party integration. It could be very fine grained. Signature every single call is what OAuth 1.0 done. Industry moved to OAuth 2.0 has its reason. See https://www.oauth.com/oauth2-servers/differences-between-oauth-1-2/