CVE-2022-3959 (published 2022-11-11T16:15Z)

A vulnerability, which was classified as problematic, has been found in drogon up to 1.8.1. Affected by this issue is some unknown functionality of the component Session Hash Handler. The manipulation leads to small space of random values. The attack may be launched remotely. Upgrading to version 1.8.2 is able to address this issue. The name of the patch is c0d48da99f66aaada17bcd28b07741cac8697647. It is recommended to upgrade the affected component. The identifier of this vulnerability is VDB-213464.

CVSS v3 base score: 5.3, MEDIUM (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L)

Weakness information:
cwe_id: CWE-330
cwe_name: Use of Insufficiently Random Values
description: The product uses insufficiently random numbers or values in a security context that depends on unpredictable numbers.
extended_description: When product generates predictable values in a context requiring unpredictability, it may be possible for an attacker to guess the next value that will be generated, and use this guess to impersonate another user or access sensitive information.
         

Fix information:
repo_url: https://github.com/drogonframework/drogon
commit_details: repo_url: https://github.com/drogonframework/drogon
author: Martin Chang
author_date: 2022-11-10 13:41:21+08:00
msg: Avoid HashDoS attacks via random per-session hash initial state (#1433)
repository: repo_url: https://github.com/drogonframework/drogon
repo_name: drogonframework/drogon
description: Drogon: A C++14/17/20 based HTTP web application framework running on Linux/macOS/Unix/Windows
repo_language: C++
owner: drogonframework
file_changes: filename: HttpRequest.h
change_type: ModificationType.MODIFY
diff: @@ -148,21 +148,27 @@ class DROGON_EXPORT HttpRequest
     virtual const std::string &getCookie(const std::string &field) const = 0;
 
     /// Get all headers of the request
-    virtual const std::unordered_map<std::string, std::string> &headers()
-        const = 0;
+    virtual const std::
+        unordered_map<std::string, std::string, utils::internal::SafeStringHash>
+            &headers() const = 0;
 
     /// Get all headers of the request
-    const std::unordered_map<std::string, std::string> &getHeaders() const
+    const std::
+        unordered_map<std::string, std::string, utils::internal::SafeStringHash>
+            &getHeaders() const
     {
         return headers();
     }
 
     /// Get all cookies of the request
-    virtual const std::unordered_map<std::string, std::string> &cookies()
-        const = 0;
+    virtual const std::
+        unordered_map<std::string, std::string, utils::internal::SafeStringHash>
+            &cookies() const = 0;
 
     /// Get all cookies of the request
-    const std::unordered_map<std::string, std::string> &getCookies() const
+    const std::
+        unordered_map<std::string, std::string, utils::internal::SafeStringHash>
+            &getCookies() const
     {
         return cookies();
     }
@@ -267,11 +273,14 @@ class DROGON_EXPORT HttpRequest
     }
 
     /// Get parameters of the request.
-    virtual const std::unordered_map<std::string, std::string> &parameters()
-        const = 0;
+    virtual const std::
+        unordered_map<std::string, std::string, utils::internal::SafeStringHash>
+            &parameters() const = 0;
 
     /// Get parameters of the request.
-    const std::unordered_map<std::string, std::string> &getParameters() const
+    const std::
+        unordered_map<std::string, std::string, utils::internal::SafeStringHash>
+            &getParameters() const
     {
         return parameters();
     }

programming_language: C++
filename: HttpResponse.h
change_type: ModificationType.MODIFY
diff: @@ -19,6 +19,7 @@
 #include <drogon/Cookie.h>
 #include <drogon/HttpTypes.h>
 #include <drogon/HttpViewData.h>
+#include <drogon/utils/Utilities.h>
 #include <json/json.h>
 #include <memory>
 #include <string>
@@ -190,11 +191,14 @@ class DROGON_EXPORT HttpResponse
     virtual void removeHeader(std::string key) = 0;
 
     /// Get all headers of the response
-    virtual const std::unordered_map<std::string, std::string> &headers()
-        const = 0;
+    virtual const std::
+        unordered_map<std::string, std::string, utils::internal::SafeStringHash>
+            &headers() const = 0;
 
     /// Get all headers of the response
-    const std::unordered_map<std::string, std::string> &getHeaders() const
+    const std::
+        unordered_map<std::string, std::string, utils::internal::SafeStringHash>
+            &getHeaders() const
     {
         return headers();
     }
@@ -222,10 +226,14 @@ class DROGON_EXPORT HttpResponse
     virtual const Cookie &getCookie(const std::string &key) const = 0;
 
     /// Get all cookies.
-    virtual const std::unordered_map<std::string, Cookie> &cookies() const = 0;
+    virtual const std::
+        unordered_map<std::string, Cookie, utils::internal::SafeStringHash>
+            &cookies() const = 0;
 
     /// Get all cookies.
-    const std::unordered_map<std::string, Cookie> &getCookies() const
+    const std::
+        unordered_map<std::string, Cookie, utils::internal::SafeStringHash>
+            &getCookies() const
     {
         return cookies();
     }

programming_language: C++
filename: Utilities.h
change_type: ModificationType.MODIFY
diff: @@ -408,5 +408,22 @@ inline bool fromString<bool>(const std::string &p) noexcept(false)
     }
     throw std::runtime_error("Can't convert from string '" + p + "' to bool");
 }
+
+namespace internal
+{
+DROGON_EXPORT extern const size_t fixedRandomNumber;
+struct SafeStringHash
+{
+    size_t operator()(const std::string &str) const
+    {
+        const size_t A = 6665339;
+        const size_t B = 2534641;
+        size_t h = fixedRandomNumber;
+        for (char ch : str)
+            h = (h * A) ^ (ch * B);
+        return h;
+    }
+};
+}  // namespace internal
 }  // namespace utils
 }  // namespace drogon

programming_language: C++
filename: HttpRequestImpl.h
change_type: ModificationType.MODIFY
diff: @@ -137,8 +137,9 @@ class HttpRequestImpl : public HttpRequest
         pathEncode_ = pathEncode;
     }
 
-    const std::unordered_map<std::string, std::string> &parameters()
-        const override
+    const std::
+        unordered_map<std::string, std::string, utils::internal::SafeStringHash>
+            &parameters() const override
     {
         parseParametersOnce();
         return parameters_;
@@ -291,12 +292,16 @@ class HttpRequestImpl : public HttpRequest
         return defaultVal;
     }
 
-    const std::unordered_map<std::string, std::string> &headers() const override
+    const std::
+        unordered_map<std::string, std::string, utils::internal::SafeStringHash>
+            &headers() const override
     {
         return headers_;
     }
 
-    const std::unordered_map<std::string, std::string> &cookies() const override
+    const std::
+        unordered_map<std::string, std::string, utils::internal::SafeStringHash>
+            &cookies() const override
     {
         return cookies_;
     }
@@ -541,9 +546,15 @@ class HttpRequestImpl : public HttpRequest
     bool pathEncode_{true};
     string_view matchedPathPattern_{""};
     std::string query_;
-    std::unordered_map<std::string, std::string> headers_;
-    std::unordered_map<std::string, std::string> cookies_;
-    mutable std::unordered_map<std::string, std::string> parameters_;
+    std::
+        unordered_map<std::string, std::string, utils::internal::SafeStringHash>
+            headers_;
+    std::
+        unordered_map<std::string, std::string, utils::internal::SafeStringHash>
+            cookies_;
+    mutable std::
+        unordered_map<std::string, std::string, utils::internal::SafeStringHash>
+            parameters_;
     mutable std::shared_ptr<Json::Value> jsonPtr_;
     SessionPtr sessionPtr_;
     mutable AttributesPtr attributesPtr_;

programming_language: C++
filename: HttpResponseImpl.h
change_type: ModificationType.MODIFY
diff: @@ -130,7 +130,9 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse
         removeHeaderBy(key);
     }
 
-    const std::unordered_map<std::string, std::string> &headers() const override
+    const std::
+        unordered_map<std::string, std::string, utils::internal::SafeStringHash>
+            &headers() const override
     {
         return headers_;
     }
@@ -200,7 +202,9 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse
         return defaultCookie;
     }
 
-    const std::unordered_map<std::string, Cookie> &cookies() const override
+    const std::
+        unordered_map<std::string, Cookie, utils::internal::SafeStringHash>
+            &cookies() const override
     {
         return cookies_;
     }
@@ -446,8 +450,11 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse
         statusMessage_ = string_view{message, messageLength};
     }
 
-    std::unordered_map<std::string, std::string> headers_;
-    std::unordered_map<std::string, Cookie> cookies_;
+    std::
+        unordered_map<std::string, std::string, utils::internal::SafeStringHash>
+            headers_;
+    std::unordered_map<std::string, Cookie, utils::internal::SafeStringHash>
+        cookies_;
 
     int customStatusCode_{-1};
     HttpStatusCode statusCode_{kUnknown};

programming_language: C++
filename: Utilities.cc
change_type: ModificationType.MODIFY
diff: @@ -1221,5 +1221,14 @@ bool secureRandomBytes(void *ptr, size_t size)
     return false;
 }
 
+namespace internal
+{
+DROGON_EXPORT const size_t fixedRandomNumber = []() {
+    size_t res;
+    utils::secureRandomBytes(&res, sizeof(res));
+    return res;
+}();
+}
+
 }  // namespace utils
 }  // namespace drogon

programming_language: C++