Dns Rebinding in Grape with Basic Auth
Dns Rebinding in Grape with Basic Auth — how this specific combination creates or exposes the vulnerability
DNS Rebinding is an application-layer attack that manipulates DNS responses to make a victim’s browser believe a remote host is both attacker-controlled and an internal host. When combined with HTTP Basic Auth in a Grape-based API, the interaction can bypass same-origin protections and credential expectations in specific deployment configurations.
Consider a Grape API that protects a sensitive endpoint with HTTP Basic Auth:
class ProtectedAPI < Grape::API
format :json
before do
authenticated? || error!('Unauthorized', 401)
end
helpers do
def authenticated?
request.authorization && request.authorization[:basic] &&
request.authorization[:basic][:password] == ENV['API_KEY']
end
end
get :admin do
{ secret: 'internal-data' }
end
end
In a typical setup, the API is served from api.example.com and requires Basic Auth with a static API key. An attacker registers a domain (e.g., evil.com) and configures it to initially resolve to the attacker’s server, then rebind to a private IP such as 127.0.0.1 or an internal service like 192.168.1.10. When a logged-in user visits a page containing a malicious script, the browser makes a request to api.example.com/admin with the stored Basic Auth credentials (username/password or the base64-encoded token). Due to the rebinding, the request reaches an internal host that may not enforce the same authentication or may expose a management interface without external protections.
Grape by itself does not prevent DNS Rebinding; the framework processes the request as a normal HTTP call once it arrives. The vulnerability surface arises from two factors:
- The API trusts the request host header or IP-based assumptions rather than validating the origin strictly.
- Basic Auth credentials are sent automatically by the browser to the resolved host, even if it pivots to an internal address, enabling the attacker to relay or replay authenticated requests to internal services that lack proper access controls.
This combination means that an attacker can effectively probe internal infrastructure using authenticated requests issued by the victim, potentially bypassing network segregation because the API endpoint does not validate the canonical hostname or enforce strict source checks. The API’s authentication mechanism (Basic Auth) remains valid, but the context of the request target is manipulated.
Basic Auth-Specific Remediation in Grape — concrete code fixes
Remediation focuses on ensuring that the request target is authoritative and that credentials are not inadvertently relayed to non-expected origins. Below are concrete changes you can apply to a Grape API to reduce DNS Rebinding risk when using Basic Auth.
1. Validate the Host Header
Reject requests where the Host header does not match your expected domain. This prevents the browser from sending requests to internal IPs even if DNS is manipulated.
class ProtectedAPI < Grape::API
format :json
before do
allowed_hosts = ['api.example.com', 'www.api.example.com']
unless allowed_hosts.include?(request.host)
error!('Forbidden', 403)
end
authenticated? || error!('Unauthorized', 401)
end
helpers do
def authenticated?
request.authorization && request.authorization[:basic] &&
request.authorization[:basic][:password] == ENV['API_KEY']
end
end
get :admin do
{ secret: 'internal-data' }
end
end
2. Avoid Using Request Host for Authorization Decisions
Do not rely on request.host, request.domain, or request.port to determine access. Instead, enforce authorization via tokens or scopes and keep Basic Auth for primary credential verification only.
3. Use Secure Flag and HttpOnly for Session Cookies (if any)
If your API sets cookies (e.g., for session management alongside Basic Auth), ensure the Secure and HttpOnly flags are set to reduce exposure over insecure channels.
# config/initializers/session_store.rb (if using cookies)
Rails.application.config.session_store :cookie_store,
key: '_your_app_session',
secure: Rails.env.production?,
httponly: true
4. Enforce Strict Transport Security and CORS
Serve your API exclusively over HTTPS and configure CORS to limit origins. This reduces the window for protocol-switching attacks that rely on rebinding HTTP to HTTPS contexts.
class ProtectedAPI < Grape::API
format :json
before do
allowed_origin = 'https://app.example.com'
unless request.env['HTTP_ORIGIN'] == allowed_origin
error!('Forbidden', 403)
end
authenticated? || error!('Unauthorized', 401)
end
helpers do
def authenticated?
request.authorization && request.authorization[:basic] &&
request.authorization[:basic][:password] == ENV['API_KEY']
end
end
get :admin do
{ secret: 'internal-data' }
end
end
By combining host validation with strict transport and origin policies, you ensure that even if DNS is manipulated, the request will either be rejected or not be processed against internal endpoints when authenticated via Basic Auth.