Ssrf Server Side in Grape with Hmac Signatures
Ssrf Server Side in Grape with Hmac Signatures — how this specific combination creates or exposes the vulnerability
Server-side request forgery (SSRF) in a Grape API can occur when an endpoint dynamically builds URLs using attacker-controlled input and then makes outbound HTTP requests. If that request flow includes HMAC-based authentication for an upstream service, the misuse or misunderstanding of HMAC signatures can inadvertently facilitate SSRF or make it harder to detect. For example, an endpoint might accept a target URL and a secret, compute an HMAC over the URL, and forward both to a downstream service that validates the signature before processing the request. An attacker can supply a URL pointing to an internal metadata service (e.g., http://169.254.169.254), while the HMAC they provide matches because the secret is embedded in server-side code. The server trusts the signature and makes the request, effectively acting as a proxy to internal resources. Because HMACs only guarantee integrity and authenticity between parties, they do not enforce network-level restrictions. If the server does not validate the destination, enforce a strict allowlist, or prevent internal IP ranges, the HMAC-enabled flow becomes a trusted channel for SSRF. Additionally, logging or error messages that include the signed payload may leak the HMAC or internal URLs, aiding further reconnaissance. The interaction of Grape routing, parameter parsing, and HMAC verification can therefore create a scenario where an authenticated-looking request triggers an internal SSRF, especially when signature validation is implemented without complementary network controls.
Hmac Signatures-Specific Remediation in Grape — concrete code fixes
Remediation centers on strict input validation, network-level restrictions, and careful handling of HMAC verification in Grape endpoints. Do not rely on HMACs alone to prevent SSRF; treat them as integrity checks, not access controls. Always validate and sanitize user-supplied URLs against a strict allowlist of permitted hosts and ports. Reject URLs with private IP ranges, localhost, or common cloud metadata addresses. Prefer using an allowlist of known, safe domains. Avoid dynamically constructing target URLs from user input. When you must sign requests with HMAC, ensure the data used to compute the signature is canonical and does not include mutable or user-controlled components that could be abused to redirect the request internally.
Example: Secure HMAC verification in Grape
require 'openssl'
require 'base64'
require 'json'
class SecureEndpoint < Grape::API
format :json
helpers do
def valid_hmac?(payload, received_hmac, secret)
expected_hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), secret, payload)
secure_compare(expected_hmac, received_hmac)
end
def secure_compare(a, b)
return false unless a.bytesize == b.bytesize
l = a.unpack 'C*'
res = 0
b.each_byte { |byte| res |= byte ^ l.shift }
res == 0
end
def allowed_host?(uri)
allowed = %w[api.example.com service.example.com]
allowed.include?(uri.host) && !%w[localhost 127.0.0.1 169.254.169.254].include?(uri.host)
end
end
post '/process' do
payload = params[:payload]
hmac = params[:hmac]
secret = ENV['HMAC_SECRET']
# Validate presence
error!('Missing parameters', 400) unless payload && hmac
# Parse and validate destination
uri = URI.parse(payload)
error!('Invalid URL', 400) unless uri.is_a?(URI::HTTP) || uri.is_a?(URI::HTTPS)
error!('Disallowed host', 403) unless allowed_host?(uri)
# Verify HMAC integrity
error!('Invalid signature', 401) unless valid_hmac?(payload, hmac, secret)
# Safe to forward (with additional safeguards in your HTTP client)
# Example using net/http (not shown) with timeouts and no proxy for internal addresses
# ensure outbound request does not follow redirects to internal IPs
{ status: 'ok', host: uri.host }
end
end
In this example, the HMAC is computed over the canonical payload (e.g., the raw URL string) using a server-side secret. The endpoint parses the payload to enforce host allowlisting and rejects private or metadata IPs before any HMAC verification or outbound request. The secure_compare method prevents timing attacks on HMAC validation. Even when HMAC signatures are used, SSRF risks are mitigated by network controls and strict URL validation. Complementary practices include disabling redirect following or ensuring the HTTP client enforces a strict no-proxy policy for internal addresses. MiddleBrick can help verify that such controls are effective by scanning your Grape API and mapping findings to frameworks like OWASP API Top 10 and PCI-DSS.