Clickjacking in Hanami with Dynamodb
Clickjacking in Hanami with Dynamodb — how this specific combination creates or exposes the vulnerability
Clickjacking is a client-side UI redress attack where an invisible or misleading interface layer tricks a user into performing unintended actions. In a Hanami application that uses DynamoDB as the persistence layer, the risk arises not from DynamoDB itself, but from how Hanami serves pages and API endpoints that lack appropriate anti-CSRF and framing defenses. An attacker can embed a hidden form or iframe that targets a DynamoDB-backed resource in Hanami—for example, a state-changing route such as POST /settings/update_profile—and if the request relies on unverified origins or missing frame-busting headers, the malicious action may execute with the victim’s credentials.
Because DynamoDB stores application state, a successful clickjacking sequence can lead to unauthorized updates to user records, such as changing email addresses, toggling administrative flags, or initiating data export actions. Hanami’s routing and view layer can inadvertently expose endpoints that perform writes without requiring a same-origin check or a cryptographically secure token in the request. When combined with weak Content Security Policy (CSP) frame-ancestors rules, an attacker’s page can render the Hanami UI in a way that obscures the true target, making user interaction directly affect DynamoDB-stored data.
In a black-box scan of a Hanami service using DynamoDB, middleBrick’s checks for Clickjacking evaluate HTTP headers, frame rendering behavior, and whether state-changing endpoints require explicit anti-CSRF tokens. The scanner does not assume authentication, so it tests unauthenticated surfaces to identify whether actions can be triggered via embedded content. Findings typically highlight missing X-Frame-Options, weak CSP frame-ancestors, or endpoints that perform sensitive DynamoDB operations without origin verification.
Dynamodb-Specific Remediation in Hanami — concrete code fixes
Remediation focuses on enforcing strict origin validation and adding anti-CSRF protections for requests that mutate DynamoDB-backed resources. Below are concrete Hanami examples using Ruby that demonstrate secure patterns.
1. Enforce same-origin policy with a before action
Use a before action in your Hanami app to verify the request’s origin for state-changing routes. This mitigates clickjacking by ensuring requests originate from your trusted domain.
module Web::Controllers::Settings
class UpdateProfile
include Web::Action
before :verify_same_origin
def call(params)
# Proceed only if origin matches
user_repo = UserRepository.new
user_repo.update_profile(params[:user_id], params[:profile])
# DynamoDB interaction via your repository
end
private
def verify_same_origin
request_origin = request.env['HTTP_ORIGIN']
allowed_origin = 'https://your-app.example.com'
unless request_origin == allowed_origin
self.status = 403
response.body = { error: 'Forbidden origin' }.to_json
throw(:halt)
end
end
end
end
2. Apply CSP with strict frame-ancestors
Set a strong Content Security Policy header that prevents embedding in frames. This is critical for pages that trigger DynamoDB writes.
module Web::Middleware
class ContentSecurityPolicy
def initialize(app)
@app = app
end
def call(env)
status, headers, body = @app.call(env)
headers['Content-Security-Policy'] = "default-src 'self'; frame-ancestors 'none'; script-src 'self'; style-src 'self'"
[status, headers, body]
end
end
end
# In your application configuration
use Web::Middleware::ContentSecurityPolicy
3. Use anti-CSRF tokens in forms and API calls
Generate and validate per-session tokens for any form that results in DynamoDB mutations. Hanami provides session management you can leverage to bind tokens to the user session.
# In a Hanami view template (slim)
= form_tag update_profile_path, method: :post do
= hidden_field_tag :csrf_token, session[:csrf_token]
= text_field_tag :email
= submit_tag 'Update'
# In your controller
class Web::Controllers::Settings::UpdateProfile
include Web::Action
before :generate_csrf_token
def call(params)
if params[:csrf_token] == session[:csrf_token]
# Proceed to update DynamoDB
user_repo = UserRepository.new
user_repo.update_profile(params[:user_id], params.except(:csrf_token))
else
self.status = 422
response.body = { error: 'Invalid CSRF token' }.to_json
end
end
private
def generate_csrf_token
session[:csrf_token] ||= SecureRandom.hex(16)
end
end
4. Secure DynamoDB client configuration and least-privilege IAM
Ensure the Hanami service’s AWS credentials are scoped to least privilege for the DynamoDB tables it accesses. While this does not prevent clickjacking, it limits the impact of compromised tokens that might be abused via a UI attack.
# config/initializers/aws.rb
Aws.config.update({
region: 'us-east-1',
credentials: Aws::Credentials.new(
ENV['AWS_ACCESS_KEY_ID'],
ENV['AWS_SECRET_ACCESS_KEY']
)
})
# Repository example with scoped table name
class UserRepository
def initialize
@dynamodb = Aws::DynamoDB::Client.new
@table = 'myapp_users'
end
def update_profile(user_id, attrs)
@dynamodb.update_item({
table_name: @table,
key: { 'user_id' => { s: user_id } },
update_expression: 'SET email = :email',
expression_attribute_values: {
':email' => { s: attrs[:email] }
}
})
end
end