HIGH api rate abusehanamisaml

Api Rate Abuse in Hanami with Saml

Api Rate Abuse in Hanami with Saml — how this specific combination creates or exposes the vulnerability

Rate abuse in a Hanami application that uses SAML for authentication can occur when an attacker sends many authentication requests or login attempts in a short time. Because SAML flows often involve redirects and POST bindings that submit assertions to the application, each assertion can be treated as an independent authentication event. Without strict rate controls on SAML endpoints and login paths, an attacker can exhaust server resources, trigger account lockouts, or probe for weak assertions.

In Hanami, which is a Ruby web framework, this risk is realized when routes handling SAML responses (e.g., the Assertion Consumer Service) do not enforce request or session-level rate limits. For example, an unauthenticated POST to /saml/consume that processes a SAMLResponse parameter may be invoked repeatedly. Even if the identity provider enforces rate limits, the consumer endpoint in Hanami may not, enabling attackers to submit malformed or malicious assertions to test validation logic or harvest metadata.

Another vector involves account enumeration through timing differences: submitting many SAML authentication requests for different usernames can reveal which users exist based on response time or error messages. Because Hanami applications often integrate SAML via gems that rely on XML parsing and signature verification, heavy XML processing on each request can amplify resource exhaustion. Attackers may also attempt to reuse or replay captured SAML responses to bypass login controls if replay protection is not implemented.

These risks are not theoretical; they map to common weaknesses in the OWASP API Top 10 and broader web application security practices. For instance, insufficient rate limiting pairs with authentication mechanisms to enable credential stuffing, brute force, or denial-of-service against the SAML flow. Because middleBrick scans unauthenticated attack surfaces and flags rate limiting issues across 12 parallel checks including Rate Limiting and Authentication, it can surface these concerns in a single report.

To illustrate a typical SAML request/response exchange in Hanami, consider the following SAML POST binding example. This snippet shows the kind of payload your endpoint might receive and should validate strictly.

<?xml version="1.0" encoding="UTF-8"?>
<samlp:AuthnRequest
    xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
    ID="_123456"
    Version="2.0"
    IssueInstant="2025-01-01T12:00:00Z"
    ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
    AssertionConsumerServiceURL="https://app.example.com/saml/consume">
  <saml:Issuer>https://idp.example.com/saml/metadata</saml:Issuer>
</samlp:AuthnRequest>

And an example SAMLResponse that the consumer might process:

<?xml version="1.0" encoding="UTF-8"?>
<samlp:Response
    xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
    ID="_response789"
    Version="2.0"
    IssueInstant="2025-01-01T12:00:05Z"
    InResponseTo="_123456"
    Destination="https://app.example.com/saml/consume"
    Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified">
  <saml:Issuer>https://idp.example.com/saml/metadata</saml:Issuer>
  <samlp:Status>
    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
  </samlp:Status>
  <saml:Assertion>
    <saml:Issuer>https://idp.example.com/saml/metadata</saml:Issuer>
    <saml:Subject>
      <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">[email protected]</saml:NameID>
      <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
        <saml:SubjectConfirmationData <ResponseLocation"https://app.example.com/saml/consume" NotOnOrAfter="2025-01-01T12:05:00Z"/>
      </saml:SubjectConfirmation>
    </saml:Subject>
    <saml:Conditions NotBefore="2025-01-01T11:55:00Z" NotOnOrAfter="2025-01-01T12:05:00Z">
      <saml:AudienceRestriction>
        <saml:Audience>https://app.example.com/metadata</saml:Audience>
      </saml:AudienceRestriction>
    </saml:Conditions>
  </saml:Assertion>
</samlp:Response>

Without rate limiting on the consume endpoint, an attacker can submit many such requests or replay captured responses. This makes SAML integrations in Hanami particularly sensitive to missing controls at the application layer, even when identity providers apply their own throttling.

Saml-Specific Remediation in Hanami — concrete code fixes

Remediation focuses on limiting the rate of SAML authentication requests and responses at the Hanami application layer. You should enforce rate limits on the SAML consumer route and add replay protection by tracking InResponseTo values and timestamps.

Below is a Hanami controller example that demonstrates how to add basic rate limiting and SAML response validation. This approach keeps processing secure without relying on external proxies.

require "hanami/controller"
require "base64"
require "xmlsimple"

class SamlController < Hanami::Action
  # Simple in-memory store for demonstration; use Redis in production
  @@processed_ids = {}
  @@request_counts = Hash.new(0)

  def consume
    # Rate limit by IP for the SAML endpoint (e.g., 30 requests per minute)
    client_ip = request.env["HTTP_X_FORWARDED_FOR"] || request.ip
    key = "saml_login_#{client_ip}"
    @@request_counts[key] += 1
    if @@request_counts[key] > 30
      raise Hanami::Controller::ActionNotAllowed, "Too many requests"
    end

    # Parse and validate SAMLResponse
    saml_response = params[:SAMLResponse]
    raise ArgumentError, "Missing SAMLResponse" if saml_response.to_s.strip.empty?

    decoded = Base64.strict_decode64(saml_response)
    doc = XmlSimple.xml_in(decoded, "ForceArray" => false, "KeyAttr" => false)
    response_id = doc["Response"].is_a?(Hash) ? doc["Response"]["@ID"] : doc["Response"]["@ID"]
    issuer = extract_value(doc, "Response/Issuer")
    status = extract_value(doc, "Response/Status/StatusCode/@Value")

    # Replay protection: track InResponseTo/ID
    if response_id&start_with?("_")
      if @@processed_ids[response_id]
        raise SecurityError, "Replay detected"
      end
      @@processed_ids[response_id] = true
      # Expire old IDs periodically in production
    end

    raise SecurityError, "Invalid status" unless status == "urn:oasis:names:tc:SAML:2.0:status:Success"

    name_id = extract_value(doc, "Response/Assertion/Subject/NameID")
    # Proceed with user lookup and session creation
    session[:user_email] = name_id
    response.body = "Login successful"
  rescue => e
    response.status = 400
    response.body = "Error: #{e.message}"
  end

  private

  def extract_value(doc, path)
    parts = path.split("/")
    val = doc
    parts.each { |p| val = val.is_a?(Array) ? val.find { |h| h.key?(p) }&.fetch(p, nil) : val.fetch(p, nil) rescue nil }
    val
  end
end

In production, replace the in-memory counters and store with a distributed cache such as Redis to coordinate limits across multiple Hanami processes and to set TTLs. Also enforce strict XML validation and canonicalization before signature verification to prevent XML bomb attacks that could abuse CPU.

Additionally, ensure that your SAML gem or library is configured to reject unsigned or poorly formed assertions and to validate audience and destination values. Combine this with application-level rate limits on authentication endpoints to mitigate abuse effectively.

Frequently Asked Questions

Why does combining Hanami and SAML increase rate abuse risk?
Hanami applications may lack built-in throttling on SAML consumer endpoints. Since SAML assertions can be submitted repeatedly via POST bindings, attackers can exploit missing rate limits to probe the assertion validation logic or exhaust server resources.
What counts as effective remediation for SAML rate abuse in Hanami?
Effective remediation includes rate limiting on the SAML consume route (e.g., per-IP limits with Redis), replay protection via InResponseTo/ID tracking, strict XML parsing limits, and validating issuer, status, audience, and destination in assertions.