From 80d6e9f08f56bb83ba4dcaece54fc71062e85e02 Mon Sep 17 00:00:00 2001
From: Josh Wright <jshwright@gmail.com>
Date: Mon, 11 Apr 2016 22:36:25 -0400
Subject: [PATCH] Use constant time comparison for http authentication (#1804)

In order to prevent a potential timing attack, it's important to make
sure the password check takes the same amount of time, regardless of
how many characters in the candidate password match the real password.

This commit does increase the verbosity of the authentication check.
Generally it is a good idea for authentication logic to be very clear,
even if that requires some extra verbosity.
---
 homeassistant/components/http.py | 23 +++++++++++++++++------
 1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/homeassistant/components/http.py b/homeassistant/components/http.py
index 7d8fd8620b4..12647be68f7 100644
--- a/homeassistant/components/http.py
+++ b/homeassistant/components/http.py
@@ -5,6 +5,7 @@ For more details about the RESTful API, please refer to the documentation at
 https://home-assistant.io/developers/api/
 """
 import gzip
+import hmac
 import json
 import logging
 import ssl
@@ -200,12 +201,22 @@ class RequestHandler(SimpleHTTPRequestHandler):
                     "Error parsing JSON", HTTP_UNPROCESSABLE_ENTITY)
                 return
 
-        self.authenticated = (self.server.api_password is None or
-                              self.headers.get(HTTP_HEADER_HA_AUTH) ==
-                              self.server.api_password or
-                              data.get(DATA_API_PASSWORD) ==
-                              self.server.api_password or
-                              self.verify_session())
+        if self.verify_session():
+            # The user has a valid session already
+            self.authenticated = True
+        elif self.server.api_password is None:
+            # No password is set, so everyone is authenticated
+            self.authenticated = True
+        elif hmac.compare_digest(self.headers.get(HTTP_HEADER_HA_AUTH, ''),
+                                 self.server.api_password):
+            # A valid auth header has been set
+            self.authenticated = True
+        elif hmac.compare_digest(data.get(DATA_API_PASSWORD, ''),
+                                 self.server.api_password):
+            # A valid password has been specified
+            self.authenticated = True
+        else:
+            self.authenticated = False
 
         if '_METHOD' in data:
             method = data.pop('_METHOD')
-- 
GitLab