Bola Idor in Hanami with Hmac Signatures
Bola Idor in Hanami with Hmac Signatures — how this specific combination creates or exposes the vulnerability
Broken Object Level Authorization (BOLA) occurs when an API fails to enforce object ownership or authorization checks on a per-request basis. In Hanami, a Ruby web framework that encourages explicit, object-oriented design, this typically surfaces in actions that load a domain object (such as an Order or Project) using an identifier provided by the client without verifying that the current actor has the right to access it.
HMAC signatures are often used to ensure integrity and authenticity of requests, for example by signing a payload or a set of parameters on the client and verifying the signature on the server to detect tampering. In Hanami, you might use HMAC signatures to validate that a webhook or an API request has not been modified. However, using HMAC signatures for integrity does not automatically enforce authorization. A common misconfiguration is to verify the HMAC signature and then load a sensitive resource directly from the parameters (e.g., an id) without confirming that the authenticated subject is allowed to access that specific resource.
Consider a Hanami endpoint that updates a user profile. The client sends user_id and an HMAC signature over some payload. If the server only validates the HMAC to ensure the request has not been altered, but then performs UserRepository.find(user_id) and applies the update without confirming the current user is that user (or an admin), a BOLA vulnerability exists. An attacker who knows or guesses another user’s ID can tamper with the HMAC (if the signing scope is too permissive) or, more commonly, rely on a weak authorization boundary to modify or read another user’s data. In Hanami, this can happen when service objects or actions use raw IDs from params without scoping queries to the current actor or tenant.
In a RESTful design, a vulnerable route might look like PUT /api/v1/accounts/:account_id/profile. The controller extracts account_id from the route, verifies an HMAC over the body, and then loads the account directly. If the controller does not check that the current session or token is associated with that account, any authenticated user who can guess valid numeric IDs can access and modify any account. This is a classic BOLA/IDOR issue. The presence of HMAC signatures might give a false sense of security: integrity is enforced, but authorization is not. Attackers can leverage predictable identifiers, insufficient scoping, or overly permissive signature policies to bypass intended access controls.
Another scenario involves batch operations where a Hanami service processes multiple resources identified by an array of IDs signed in a payload. If the HMAC covers the IDs but the service iterates over each ID and performs an action without confirming that the actor is permitted to act on each item, BOLA is present across the batch. This can be particularly problematic when combined with mass assignment or unsafe parameter filtering, leading to privilege escalation or unauthorized data access.
Logging and error handling in Hanami can inadvertently amplify BOLA risks. Verbose errors might disclose whether a given ID exists or whether a signature verification failed, aiding enumeration. Additionally, if background jobs or asynchronous tasks process signed requests, they must re-validate authorization based on the current actor context rather than trusting the original request’s assumptions.
To summarize, combining Hanami’s explicit architecture with HMAC signatures does not prevent BOLA unless authorization checks are consistently applied. The vulnerability arises when integrity mechanisms (HMAC) replace or are mistakenly thought to cover authorization. Without scoping queries to the current user or tenant and validating permissions on the loaded object, attackers can traverse relationships, guess identifiers, or exploit weak parameter filtering to access or modify unauthorized resources.
Hmac Signatures-Specific Remediation in Hanami — concrete code fixes
Remediation focuses on ensuring that HMAC verification is one layer and does not replace proper authorization. In Hanami, you should scope data access to the current actor and verify permissions on the loaded object before performing any operation. Below are concrete patterns and code examples.
1. Always scope queries to the current actor
Instead of loading a resource by ID alone, scope the query to the current user or tenant. For example, if you have a current_user available in your endpoint or controller, use it to scope the repository query.
# app/operations/users/show.rb
class Users::Show
include Hanami::Operation
def call(params)
user_id = params[:id]
# Ensure the user can only fetch their own profile
user = UserRepository.new.where(id: user_id, account_id: current_user.account_id).one
if user
Response::Ok.new(user)
else
Response::NotFound.new(error: 'Not found')
If you don’t have a current user, use the request’s authentication context to validate ownership or membership before proceeding.
2. Validate permissions after loading the object
Use a policy or authorization check after loading the domain object. This ensures that even if an ID is valid, the actor must be explicitly allowed to perform the action.
# app/policies/account_policy.rb
class AccountPolicy
def initialize(user, account)
@user = user
@account = account
end
def update?
user.admin? || user.account_id == account.id
end
end
# app/operations/accounts/update.rb
class Accounts::Update
include Hanami::Operation
def call(params)
account = AccountRepository.find(params[:id])
policy = AccountPolicy.new(current_user, account)
if policy.update?
# proceed with update
else
Response::Forbidden.new(error: 'Not authorized')
3. Use HMAC for integrity, not authorization
When using HMAC signatures, keep the verification separate from authorization. Verify the signature to ensure the payload has not been altered, then apply standard authorization checks.
# app/operations/webhooks/handler.rb
class Webhooks::Handler
include Hanami::Operation
def call(params)
# 1) Verify HMAC signature over the payload
verified = verify_hmac(params[:payload], params[:signature])
unless verified
return Response::BadRequest.new(error: 'Invalid signature')
end
# 2) Authorize based on the resource and actor
resource = ResourceRepository.find(params[:resource_id])
if resource.allowed?(current_user)
# process the verified and authorized event
else
Response::Forbidden.new(error: 'Access denied')
4. Avoid exposing sequential or guessable IDs
Use UUIDs or other non-sequential identifiers and ensure that permissions are checked for each lookup. Even with HMAC, predictable IDs make enumeration and BOLA easier.
# Using UUIDs in Hanami with ROM
# config/initializers/repositories.rb
Roma.repositories.define do
resource :projects, entity: Project do
define_mapper :project do
model Project
key :id, Types::UUID
end
end
end
# In an operation
project = ProjectRepository.find(params[:project_id]) # UUID-based
unless project.owned_by?(current_user)
raise UnauthorizedError
5. Secure background and async processing
If you defer work to jobs, pass the actor identifier and re-check permissions in the job context rather than relying on the original request’s HMAC or parameters alone.
# app/jobs/profile_update_job.rb
class ProfileUpdateJob
include Sidekiq::Job
def perform(user_id, encrypted_params, hmac)
user = UserRepository.find(user_id)
# Re-validate HMAC if the job is triggered by a signed webhook
raise 'Invalid' unless verify_hmac(encrypted_params, hmac)
# Re-authorize in the job context
raise 'Forbidden' unless user.allowed_to_update?(current_actor_in_job_context)
user.update!(decrypted_params(encrypted_params))
end
end
By combining HMAC integrity checks with strict, scoped authorization and explicit permission checks, you mitigate BOLA risks in Hanami applications. Remember that Hmac Signatures-Specific Remediation is about layering controls: integrity first, then authorization scoped to the actor and object, and finally secure handling of identifiers and asynchronous tasks.
Related CWEs: bolaAuthorization
| CWE ID | Name | Severity |
|---|---|---|
| CWE-250 | Execution with Unnecessary Privileges | HIGH |
| CWE-639 | Insecure Direct Object Reference | CRITICAL |
| CWE-732 | Incorrect Permission Assignment | HIGH |