Clickjacking in Hanami with Cockroachdb
Clickjacking in Hanami with Cockroachdb — how this specific combination creates or exposes the vulnerability
Clickjacking is a client-side UI vulnerability where an attacker tricks a user into interacting with a hidden or disguised element inside an invisible or transparent page. In a Hanami application that uses Cockroachdb as the backend datastore, the risk arises not from Cockroachdb itself, but from how Hanami serves pages and frames that may lack proper anti-clickjacking protections. If a Hanami view embeds third-party content in an <iframe> or fails to set the X-Frame-Options header or Content-Security-Policy frame-ancestors directive, an attacker can overlay invisible controls on top of authenticated pages, such as fund transfers or profile updates, that ultimately commit actions against the Cockroachdb-backed persistence layer.
Because Hanami is a full-stack Ruby framework, it often renders server-generated HTML with embedded state tokens, and if those pages are inadvertently framed, the token and user session remain valid within the hidden context. Cockroachdb, as the distributed SQL store, will faithfully persist whatever operations Hanami executes, including unauthorized state changes triggered via clickjacked interactions. For example, an attacker might load the Hanami dashboard in an iframe, set the opacity to zero, and place a button or form submission over a sensitive action like changing an email address. When the victim clicks what they believe is a benign page, the hidden form submits with the user’s credentials and session, and Hanami processes the request, writing the change to Cockroachdb.
In practice, this combination becomes critical when Hanami serves administrative or sensitive endpoints without frame-protection headers. Even if Cockroachdb enforces strong consistency and permissions, the application layer must ensure that responses include frame-deny policies. Without Content-Security-Policy: frame-ancestors or explicit X-Frame-Options, the browser will render the page in a frame regardless of the underlying database security model. Therefore, the exposure stems from missing HTTP headers and insecure view composition in Hanami, which allow an attacker to leverage the user’s authenticated session to perform actions that ultimately mutate data in Cockroachdb.
Cockroachdb-Specific Remediation in Hanami — concrete code fixes
Remediation focuses on preventing pages from being embedded in frames and ensuring that state-modifying requests cannot be triggered via invisible forms. In Hanami, you can enforce this at the application level by configuring default headers and tightening view rendering. Below are concrete steps and code examples tailored for a Hanami app backed by Cockroachdb.
1. Set HTTP headers to prevent framing
Ensure every response includes Content-Security-Policy with frame-ancestors and X-Frame-Options. In Hanami, you can use a middleware or a before action to inject these headers.
# config/initializers/security_headers.rb
module SecurityHeaders
def self.registered(app)
app.before do
response['X-Frame-Options'] = 'DENY'
response['Content-Security-Policy'] = "frame-ancestors 'none'"
end
end
end
Hanami.configure do |config|
config.middleware.insert_after Rack::Runtime, SecurityHeaders
end
This configuration ensures that browsers will not render any Hanami page inside a frame, mitigating clickjacking regardless of how the Cockroachdb layer processes the request.
2. Use strong authenticity tokens and verify origins
Hanami includes built-in CSRF protection which should be leveraged to ensure that state-modifying POST, PUT, PATCH, and DELETE requests originate from your own pages. Combine this with strict referrer checks on sensitive endpoints.
# app/actions/web/account/update_email.rb
module Web::Account
class UpdateEmail
include Hanami::Action
def handle(request)
# Verify origin and referer as an additional safeguard
referer = request.env['HTTP_REFERER']
unless referer&.start_with?(request.env['HTTP_HOST'])
raise Hanami::Action::UnauthorizedError, 'Invalid referer'
end
# Ensure CSRF token is validated (Hanami does this automatically for forms)
# Proceed only if request is authenticated and token matches
user = request.session[:user_id]
new_email = params[:email]
# Safe Cockroachdb interaction using Hanami::Repository
account_repo = AccountRepository.new
account_repo.update_email(user, new_email)
response.status = 200
response.body = { message: 'Email updated' }.to_json
end
end
end
# db/repositories/account_repository.rb
class AccountRepository
def initialize
@db = Cockroachdb::Database.new(ENV.fetch('DATABASE_URL'))
end
def update_email(user_id, new_email)
# Cockroachdb SQL with explicit parameterization to avoid injection
@db.execute(
'UPDATE users SET email = $1 WHERE id = $2',
new_email, user_id
)
end
end
In this example, the action verifies the HTTP Referer header and relies on Hanami’s CSRF token validation. The Cockroachdb interaction uses parameterized queries via Hanami::Repository to prevent SQL injection, ensuring that even if clickjacking bypasses UI layers, unauthorized data mutation is still blocked by server-side checks.
3. Isolate sensitive actions behind additional UI and server-side checks
For critical operations, consider requiring re-authentication or a one-time token. This ensures that even if a page is framed, the attacker cannot forge a valid request without the user’s explicit consent.
# app/actions/web/account/change_password.rb
module Web::Account
class ChangePassword
include Hanami::Action
def handle(request)
# Require explicit re-auth for sensitive changes
unless request.session[:reauth_at] && request.session[:reauth_at] > 10.minutes.ago
redirect_to '/reauth?next=/account/change_password'
return
end
# Proceed with Cockroachdb update using Hanami::Repository
password_repo = PasswordRepository.new
password_repo.update(request.session[:user_id], params[:new_password])
response.status = 200
response.body = { message: 'Password changed' }.to_json
end
end
end
By requiring recent re-authentication, you reduce the impact of clickjacking vectors, as an attacker cannot force a user to enter credentials again without their knowledge.