From 0309b574e85ecb002fa0b740d4374c241ad7a303 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Thu, 15 Feb 2018 09:51:26 -0500 Subject: [PATCH] mitigate dns rebinding in webui --- daemon/HTTPServer.cpp | 33 ++++++++++++++++++++++++++++----- daemon/HTTPServer.h | 4 +++- libi2pd/Config.cpp | 2 ++ 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 017bc8a4..6f884a9b 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -733,8 +733,9 @@ namespace http { } } - HTTPConnection::HTTPConnection (std::shared_ptr socket): - m_Socket (socket), m_Timer (socket->get_io_service ()), m_BufferLen (0) + HTTPConnection::HTTPConnection (std::string hostname, std::shared_ptr socket): + m_Socket (socket), m_Timer (socket->get_io_service ()), m_BufferLen (0), + expected_host(hostname) { /* cache options */ i2p::config::GetOption("http.auth", needAuth); @@ -833,7 +834,28 @@ namespace http { SendReply(res, content); return; } - + bool strictheaders; + i2p::config::GetOption("http.strictheaders", strictheaders); + if (strictheaders) + { + std::string http_hostname; + i2p::config::GetOption("http.hostname", http_hostname); + std::string host = req.GetHeader("Host"); + auto idx = host.find(':'); + /* strip out port so it's just host */ + if (idx != std::string::npos && idx > 0) + { + host = host.substr(0, idx); + } + if (!(host == expected_host || host == http_hostname)) + { + /* deny request as it's from a non whitelisted hostname */ + res.code = 403; + content = "host missmatch"; + SendReply(res, content); + return; + } + } // Html5 head start ShowPageHead (s); if (req.uri.find("page=") != std::string::npos) { @@ -976,7 +998,8 @@ namespace http { HTTPServer::HTTPServer (const std::string& address, int port): m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service), - m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint (boost::asio::ip::address::from_string(address), port)) + m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint (boost::asio::ip::address::from_string(address), port)), + m_Hostname(address) { } @@ -1061,7 +1084,7 @@ namespace http { void HTTPServer::CreateConnection(std::shared_ptr newSocket) { - auto conn = std::make_shared (newSocket); + auto conn = std::make_shared (m_Hostname, newSocket); conn->Receive (); } } // http diff --git a/daemon/HTTPServer.h b/daemon/HTTPServer.h index f1ca10fc..46477dae 100644 --- a/daemon/HTTPServer.h +++ b/daemon/HTTPServer.h @@ -21,7 +21,7 @@ namespace http { public: - HTTPConnection (std::shared_ptr socket); + HTTPConnection (std::string serverhost, std::shared_ptr socket); void Receive (); private: @@ -46,6 +46,7 @@ namespace http bool needAuth; std::string user; std::string pass; + std::string expected_host; static std::map m_Tokens; // token->timestamp in seconds }; @@ -75,6 +76,7 @@ namespace http boost::asio::io_service m_Service; boost::asio::io_service::work m_Work; boost::asio::ip::tcp::acceptor m_Acceptor; + std::string m_Hostname; }; //all the below functions are also used by Qt GUI, see mainwindow.cpp -> getStatusPageHtml diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 636e4986..558d5e0a 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -83,6 +83,8 @@ namespace config { ("http.auth", value()->default_value(false), "Enable Basic HTTP auth for webconsole") ("http.user", value()->default_value("i2pd"), "Username for basic auth") ("http.pass", value()->default_value(""), "Password for basic auth (default: random, see logs)") + ("http.strictheaders", value()->default_value(true), "Enable strict host checking on WebUI") + ("http.hostname", value()->default_value("localhost"),"Expected hostname for WebUI") ; options_description httpproxy("HTTP Proxy options");