代码之家  ›  专栏  ›  技术社区  ›  Thomas Sablik

防止poco服务器应用程序中的目录遍历攻击

  •  0
  • Thomas Sablik  · 技术社区  · 7 年前

    我有一个poco服务器应用程序项目。此服务器应用程序用作Web服务器。现在我想加强它的抵抗目录遍历攻击,我正在寻找最好的方法来确保服务器提供的文件是从内部的 wwwRoot . 结构是

    project
    |-src
    | |-main.cpp
    |-CMakeLists.txt
    |-conanfile.txt
    |-build
      |-...
    

    例如,当我使用 build 作为 www. , conanfile.txt 在外面 www. 但与 localhost:8080/../conanfile.txt 我可以打开它。我知道我可以搜索点段的路径,但我听说它不是真正安全的,因为有黑客像编码路径。由于poco是服务器应用程序的框架,我假设已经有这样一个函数来检查 filePath 在里面 www. 但我找不到。

    这个 src/main.cpp 包含:

    #include <Poco/Net/HTTPServer.h>
    #include <Poco/Net/ServerSocket.h>
    #include <Poco/Util/ServerApplication.h>
    #include <Poco/Net/HTTPRequestHandler.h>
    #include <Poco/Net/HTTPRequestHandlerFactory.h>
    #include <Poco/Net/HTTPServerRequest.h>
    #include <Poco/Net/HTTPServerResponse.h>
    #include <Poco/Path.h>
    #include <string>
    
    class FileHandler: public Poco::Net::HTTPRequestHandler {
    public:
        explicit FileHandler(const Poco::Path &wwwRoot);
    protected:
        void handleRequest(Poco::Net::HTTPServerRequest &request,
                           Poco::Net::HTTPServerResponse &response) override;
    private:
        Poco::Path wwwRoot;
    };
    
    FileHandler::FileHandler(const Poco::Path &aWwwRoot) : wwwRoot(aWwwRoot) {}
    
    void FileHandler::handleRequest(Poco::Net::HTTPServerRequest &request,
                       Poco::Net::HTTPServerResponse &response) {
        Poco::Util::Application &app = Poco::Util::Application::instance();
        app.logger().information("FileHandler Request from " + request.clientAddress().toString() + ": " + request.getURI());
    
    
        Poco::Path path(wwwRoot.absolute(), request.getURI());
        std::string filePath(path.toString());
        app.logger().information(filePath);
        response.sendFile(filePath, "text/html");
    }
    
    class HTTPRequestHandlerFactory: public Poco::Net::HTTPRequestHandlerFactory {
    public:
        explicit HTTPRequestHandlerFactory(const Poco::Path &wwwRoot);
    protected:
        Poco::Net::HTTPRequestHandler* createRequestHandler(
                const Poco::Net::HTTPServerRequest& request) override;
    private:
        Poco::Path wwwRoot;
    };
    
    HTTPRequestHandlerFactory::HTTPRequestHandlerFactory(const Poco::Path &aWwwRoot) : wwwRoot(aWwwRoot) {}
    
    Poco::Net::HTTPRequestHandler* HTTPRequestHandlerFactory::createRequestHandler(
            const Poco::Net::HTTPServerRequest &) {
        return new FileHandler(wwwRoot);
    }
    
    class ServerApplication : public Poco::Util::ServerApplication {
    protected:
        void initialize(Application& self) override;
        int main(const std::vector<std::string> &args) override;
    };
    
    void ServerApplication::initialize(Application& self) {
        loadConfiguration();
        Poco::Util::ServerApplication::initialize(self);
    }
    
    int ServerApplication::main(const std::vector<std::string> &) {
    
        Poco::Net::ServerSocket svs(8080);
        Poco::Net::HTTPServer srv(new HTTPRequestHandlerFactory(Poco::Path(".").absolute()),
                                  svs, new Poco::Net::HTTPServerParams);
        srv.start();
        waitForTerminationRequest();
        srv.stop();
        return Application::EXIT_OK;
    }
    
    int main(int argc, char **argv) {
      ServerApplication app;
      return app.run(argc, argv);
    }
    

    这个 CMakeLists.txt 包含:

    cmake_minimum_required (VERSION 3.5.1)
    project (Sandbox)
    
    if(NOT CMAKE_BUILD_TYPE)
      set(CMAKE_BUILD_TYPE Debug)
    endif()
    
    set(CMAKE_CXX_FLAGS "-Wall -Wextra")
    set(CMAKE_CXX_FLAGS_DEBUG "-g")
    set(CMAKE_CXX_FLAGS_RELEASE "-O3")
    set(CMAKE_CXX_STANDARD 14)
    
    include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
    conan_basic_setup(TARGETS)
    
    add_executable(${PROJECT_NAME} src/main.cpp)
    target_link_libraries(${PROJECT_NAME} PRIVATE CONAN_PKG::Poco)
    

    这个 conanfile.txt文件 包含:

    [requires]
    Poco/1.9.0@pocoproject/stable
    
    [generators]
    cmake
    

    建造 项目建成了

    0 回复  |  直到 7 年前
        1
  •  1
  •   Günter Obiltschnig    7 年前

    您将不得不解码请求路径并逐步构建本地路径并检查“.”路径段。这里有一个代码片段可以做到这一点,还可以处理在提供文件时应该注意的其他一些事情。你需要写 mapContentType() 方法,或做类似的事情。

    Poco::URI uri(request.getURI());
    std::string decodedPath = uri.getPath();
    
    Poco::Path requestPath(decodedPath, Poco::Path::PATH_UNIX);
    Poco::Path localPath(wwwRoot.absolute());
    localPath.makeDirectory();
    
    bool valid = true;
    for (int i = 0; valid && i < requestPath.depth(); i++)
    {
        if (requestPath[i] != "..")
            localPath.pushDirectory(requestPath[i]);
        else
            valid = false;
    }
    if (valid)
    {
        localPath.setFileName(requestPath.getFileName());
        Poco::File requestedFile(localPath.toString());
        if (requestedFile.exists())
        {
            std::string contentType = mapContentType(localPath.getExtension());
    
            if (request.getMethod() == Poco::Net::HTTPRequest::HTTP_HEAD)
            {
                response.set("Last-Modified", Poco::DateTimeFormatter::format(dateTime, Poco::DateTimeFormat::HTTP_FORMAT));
                response.setContentLength64(requestedFile.getSize());
                response.setContentType(contentType);
                response.send();
            }
            else if (request.getMethod() == Poco::Net::HTTPRequest::HTTP_GET)
            {
                response.sendFile(localPath.toString(), contentType);
            }
            else
            {
                response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_METHOD_NOT_ALLOWED);
                response.send();
            }
        }
        else
        {
            response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_NOT_FOUND);
            response.send();
        }
    }
    else
    {
        response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_NOT_FOUND);
        response.send();
    }