Clickjacking in Loopback with Basic Auth
Clickjacking in Loopback with Basic Auth — how this specific combination creates or exposes the vulnerability
Clickjacking is a client-side UI redress attack where an invisible or disguised element tricks a user into performing an unintended action. When Basic Authentication is used in a Loopback application, the browser may automatically send credentials with cross-origin requests if the endpoint accepts credentials and the request path is not protected by anti-CSRF or frame-embedding defenses. This combination creates an exploitable scenario where an authenticated session can be abused via embedded iframes.
Consider a Loopback endpoint that relies solely on HTTP Basic Auth (username:password in the Authorization header). If this endpoint renders HTML or is accessible to cross-origin framing, an attacker can embed the endpoint in an <iframe> on a malicious site. Because the browser includes the Basic Auth credentials automatically for same-origin requests, a signed-in user’s browser may load the iframe and trigger state-changing operations (GET with side effects or unsafe methods) without the user’s awareness. MiddleBrick’s unauthenticated scan checks for missing Content-Security-Policy: frame-ancestors and other UI redress protections across 12 checks, including Input Validation and Unsafe Consumption, which can surface these misconfigurations.
Basic Auth over unencrypted channels compounds the risk: credentials are sent in an easily decoded Base64 string. If the page is served over HTTP or the site is vulnerable to other injection vectors, an attacker may combine eavesdropping with UI redress. Even when served over HTTPS, the absence of anti-CSRF tokens and restrictive frame policies allows an authenticated session to be hijacked through embedded malicious forms or links. The scan’s OWASP API Top 10 mapping highlights these as risks around Broken Object Level Authorization (BOLA)/IDOR and improper authorization boundaries, emphasizing the need for explicit frame control and request integrity checks.
Basic Auth-Specific Remediation in Loopback — concrete code fixes
To mitigate clickjacking when using Basic Auth in Loopback, enforce strict frame-embedding rules and avoid relying on Basic Auth alone for state-changing operations. Always serve sensitive endpoints over HTTPS and add CSP headers that prevent framing. Below are concrete code examples and configurations.
1. Enforce HTTPS and add Content-Security-Policy frame-ancestors
Ensure your Loopback application serves only over TLS and sets a restrictive CSP. This prevents the browser from loading the app in an attacker-controlled frame.
// server/middleware.json
{
"initial:before": [
{
"limitLength": false,
"parse": false,
"static": false,
"next": true,
"path": "/(.*)",
"middleware": "loopback::compression"
},
{
"path": "/(.*)",
"middleware": "csp-middleware",
"options": {
"contentSecurityPolicy": {
"defaultSrc": ["'self'"],
"scriptSrc": ["'self'", "'unsafe-inline'"],
"styleSrc": ["'self'", "'unsafe-inline'"],
"imgSrc": ["'self'", "data:"],
"connectSrc": ["'self'"],
"fontSrc": ["'self'"],
"objectSrc": ["'none'"],
"baseUri": ["'self'"],
"formAction": ["'self'"],
"frameAncestors": ["'none'"]
}
}
}
]
}
2. Disable credentials in cross-origin requests for safe endpoints
For endpoints that do not require authentication in embedded contexts, ensure they do not invite credentialed framing. Use explicit route configurations to opt out of unnecessary exposure.
// server/component-config.json
{
"SecurityComponent": {
"cors": {
"origin": false,
"credentials": false
}
}
}
3. Example Loopback controller with safe Basic Auth handling
When Basic Auth is required, enforce strict referrer and origin checks server-side and avoid GET endpoints that mutate state. Always use POST for actions and validate the Origin header.
// server/controllers/user.controller.js
const loopback = require('loopback');
const BasicAuth = loopback.createModel('BasicAuth', {
username: { type: String, required: true },
password: { type: String, required: true }
}, {
base: 'User'
});
module.exports = function(BasicAuthController) {
BasicAuthController.protectedAction = function(req, res) {
const origin = req.headers.origin;
const allowedOrigin = 'https://your-trusted-domain.com';
if (origin !== allowedOrigin) {
return res.status(403).json({ error: 'Forbidden' });
}
// Perform action only for same-origin or validated referrer
return res.json({ status: 'ok' });;
};
BasicAuthController.remoteMethod(
'protectedAction',
{
accepts: [{ arg: 'ctx', type: 'object', http: { source: 'context' } }],
returns: { arg: 'result', type: 'object' },
http: { path: '/protected', verb: 'get' }
}
);
};
4. Middleware to validate Origin and mitigate frame-based attacks
Add a small custom middleware to reject requests that do not match an allowlist, which helps reduce the attack surface for clickjacking when Basic Auth is in use.
// server/application.js
this.middleware('initial:before').push(function(req, res, next) {
const allowedOrigins = ['https://your-trusted-domain.com', 'https://app.your-trusted-domain.com'];
const origin = req.headers.origin;
if (origin && allowedOrigins.includes(origin)) {
res.set('Access-Control-Allow-Origin', origin);
res.set('Access-Control-Allow-Credentials', 'true');
} else if (origin) {
// Block potentially malicious framing
res.status(403).send('Origin not allowed');
return;
}
next();
});