diff --git a/src/misc.cpp b/src/misc.cpp index d248bd537..3f2fa27aa 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -645,6 +645,20 @@ QString misc::accurateDoubleToString(const double &n, const int &precision, bool return QString::number(std::floor(n*prec)/prec, 'f', precision); } +// Implements constant-time comparison to protect against timing attacks +// Taken from https://crackstation.net/hashing-security.htm +bool misc::slowEquals(const QByteArray &a, const QByteArray &b) +{ + int lengthA = a.length(); + int lengthB = b.length(); + + int diff = lengthA ^ lengthB; + for(int i = 0; i < lengthA && i < lengthB; i++) + diff |= a[i] ^ b[i]; + + return (diff == 0); +} + namespace { // Trick to get a portable sleep() function class SleeperThread : public QThread { diff --git a/src/misc.h b/src/misc.h index 9e7cba903..ccc33b0e8 100644 --- a/src/misc.h +++ b/src/misc.h @@ -106,6 +106,10 @@ namespace misc bool naturalSort(QString left, QString right, bool& result); #endif + // Implements constant-time comparison to protect against timing attacks + // Taken from https://crackstation.net/hashing-security.htm + bool slowEquals(const QByteArray &a, const QByteArray &b); + void msleep(unsigned long msecs); } diff --git a/src/webui/requesthandler.cpp b/src/webui/requesthandler.cpp index 26633bd4d..b53baf8bf 100644 --- a/src/webui/requesthandler.cpp +++ b/src/webui/requesthandler.cpp @@ -136,7 +136,10 @@ void RequestHandler::action_public_login() md5.addData(request().posts["password"].toLocal8Bit()); QString pass = md5.result().toHex(); - if ((request().posts["username"] == pref->getWebUiUsername()) && (pass == pref->getWebUiPassword())) + bool equalUser = misc::slowEquals(request().posts["username"].toUtf8(), pref->getWebUiUsername().toUtf8()); + bool equalPass = misc::slowEquals(pass.toUtf8(), pref->getWebUiPassword().toUtf8()); + + if (equalUser && equalPass) { sessionStart(); print(QByteArray("Ok."), CONTENT_TYPE_TXT);