Skip to content

v1.1.0

Choose a tag to compare

@thewizardplusplus thewizardplusplus released this 17 May 13:17
· 5 commits to master since this release

Added an adapter layer to integrate PoW-based DoS attack protection with HTTP servers and clients.

Change Log

The format is based on Keep a Changelog.

Added

  • Middlewares:
    • LoadLevelMiddleware: tracks the current server load by counting in-flight requests:
      • Intended to be used in conjunction with the dynamic hash difficulty provider.
      • Interacts with the latter via an interface.
    • ResourceMiddleware: sets the request URL as the protected resource in the request context:
      • Optionally enriches the URL with a host:
        • Host can be taken from the request itself.
        • Host can be taken from proxy-provided headers.
    • DoSProtectorMiddleware: implements the core logic of DoS attack protection using the PoW algorithm:
      • If a request lacks the solution header X-Dos-Protector-Solution, it generates a new challenge, signs it, and returns it via the response headers X-Dos-Protector-Challenge and X-Dos-Protector-Signature.
      • If a request includes the solution header X-Dos-Protector-Solution, it parses and validates the solution:
        • If validation fails, the 403 Forbidden error response is returned.
        • If validation succeeds, the request proceeds to the protected handler.
      • All operations are delegated to the corresponding use case via an interface.
  • Models:
    • Introduced adapter-layer models:
      • Challenge: corresponds to the domain-level challenge entity.
      • Solution: corresponds to the domain-level solution entity.
    • Functions:
      • NewChallengeFromEntity() and NewSolutionFromEntity(): convert domain entities into adapter-layer models.
      • ParseChallengeFromQuery() and ParseSolutionFromQuery(): parse adapter-layer models from URL-encoded query strings.
    • Methods:
      • Challenge.ToQuery() and Solution.ToQuery(): serialize adapter-layer models into URL-encoded query strings.
  • Errors:
    • TransformErrorToStatusCode() maps internal errors to appropriate HTTP status codes:
      • Internal error dosProtectorUsecaseErrors.ErrInvalidParameters corresponds to the HTTP status code 400 Bad Request.
      • Internal error powErrors.ErrValidationFailure corresponds to the HTTP status code 403 Forbidden.
      • Other errors correspond to the HTTP status code 500 Internal Server Error.
  • Clients:
    • HTTPClientWrapper: a wrapper around the standard HTTP client (via an interface) that automates interaction with DoSProtectorMiddleware (see above):
      • Sends an initial HEAD request to the target URL to retrieve the challenge and signature from the X-Dos-Protector-Challenge and X-Dos-Protector-Signature headers, respectively.
      • Parses and solves the challenge by invoking the corresponding use case via an interface.
      • Clones the original request and enriches it with the computed solution and signature in the headers X-Dos-Protector-Solution and X-Dos-Protector-Signature.
      • Sends the enriched request to the server as usual.
  • Tests:
    • newTestHTTPClient() and newTestServer() for reusable test setup.
    • Integration tests for middleware and client interaction with constant and dynamic providers.
  • Docs:
    • newExampleHTTPClient() and newExampleServer() for reusable example setup.
    • Demonstrations of usage with constant and dynamic providers.

Changed

  • Refactored usecases/models:
    • Renamed MessageAuthenticationCode fields to Signature for clarity.

Features

  • use of patterns:
    • implementation based on Clean Architecture principles:
      • separate use case layers for server and client;
      • adapter layer for integrating with HTTP servers and clients;
    • input parsing and validation handled internally in the use cases (inputs are passed as raw DTOs);
    • relies on the library github.com/thewizardplusplus/go-pow for PoW algorithm implementation;
  • use cases:
    • server-side:
      • SignChallenge(): generate a message authentication code (MAC) signature for a challenge:
        • MAC signature generation uses a secret key and configurable hashing algorithm;
      • GenerateChallenge(): generate a challenge with specified parameters:
        • number of leading zero bits (hash difficulty);
        • current timestamp rounded to a configurable precision;
        • time to live (TTL);
        • target resource URI;
        • payload consisting of static and random parts;
        • hashing algorithm;
      • GenerateSignedChallenge(): generate a challenge and sign it;
      • VerifySolution(): verify the correctness of a PoW solution;
      • VerifySolutionAndChallengeSignature(): verify both PoW solution and challenge MAC signature;
    • client-side:
      • SolveChallenge(): solve a challenge using the PoW algorithm;
    • providers:
      • extensible provider interfaces for:
        • hash difficulty;
        • target resource URI;
        • static payload part;
      • built-in provider implementations:
        • constant value providers;
        • dynamic providers:
          • hash difficulty based on current server load (active request count);
          • target resource URI and static payload extracted from a context;
  • adapter layer:
    • middlewares:
      • LoadLevelMiddleware: tracks the current server load by counting in-flight requests:
        • intended to be used in conjunction with the dynamic hash difficulty provider (see above);
        • interacts with the latter via an interface;
      • ResourceMiddleware: sets the request URL as the protected resource in the request context:
        • optionally enriches the URL with a host:
          • host can be taken from the request itself;
          • host can be taken from proxy-provided headers;
      • DoSProtectorMiddleware: implements the core logic of DoS attack protection using the PoW algorithm:
        • if a request lacks the solution header X-Dos-Protector-Solution, it generates a new challenge, signs it, and returns it via the response headers X-Dos-Protector-Challenge and X-Dos-Protector-Signature;
        • if a request includes the solution header X-Dos-Protector-Solution, it parses and validates the solution:
          • if validation fails, the 403 Forbidden error response is returned;
          • if validation succeeds, the request proceeds to the protected handler;
        • all operations are delegated to the corresponding use case via an interface;
    • models:
      • introduced adapter-layer models:
        • Challenge: corresponds to the domain-level challenge entity;
        • Solution: corresponds to the domain-level solution entity;
      • functions:
        • NewChallengeFromEntity() and NewSolutionFromEntity(): convert domain entities into adapter-layer models;
        • ParseChallengeFromQuery() and ParseSolutionFromQuery(): parse adapter-layer models from URL-encoded query strings;
      • methods:
        • Challenge.ToQuery() and Solution.ToQuery(): serialize adapter-layer models into URL-encoded query strings;
    • errors:
      • TransformErrorToStatusCode() maps internal errors to appropriate HTTP status codes:
        • internal error dosProtectorUsecaseErrors.ErrInvalidParameters corresponds to the HTTP status code 400 Bad Request;
        • internal error powErrors.ErrValidationFailure corresponds to the HTTP status code 403 Forbidden;
        • other errors correspond to the HTTP status code 500 Internal Server Error;
    • clients:
      • HTTPClientWrapper: a wrapper around the standard HTTP client (via an interface) that automates interaction with DoSProtectorMiddleware (see above):
        • sends an initial HEAD request to the target URL to retrieve the challenge and signature from the X-Dos-Protector-Challenge and X-Dos-Protector-Signature headers, respectively;
        • parses and solves the challenge by invoking the corresponding use case via an interface;
        • clones the original request and enriches it with the computed solution and signature in the headers X-Dos-Protector-Solution and X-Dos-Protector-Signature;
        • sends the enriched request to the server as usual.