Why This Matters Now
Visual Overview:
sequenceDiagram
participant User
participant SPA as Single Page App
participant AuthServer as Authorization Server
SPA->>SPA: 1. Generate code_verifier & code_challenge
SPA->>AuthServer: 2. Auth Request + code_challenge
AuthServer->>User: 3. Login Page
User->>AuthServer: 4. Authenticate
AuthServer->>SPA: 5. Authorization Code
SPA->>AuthServer: 6. Token Request + code_verifier
AuthServer->>AuthServer: 7. Verify: SHA256(code_verifier) == code_challenge
AuthServer->>SPA: 8. Access Token
Last week, researchers at SquareX revealed a critical flaw in the passkey authentication mechanism, specifically targeting the WebAuthn protocol. This vulnerability could allow attackers to bypass passkey-based login security, even when strong authentication methods like Face ID are used. As passkeys are increasingly adopted by major tech companies, understanding and mitigating this risk is crucial.
This became urgent because the attack doesn’t target passkey cryptography itself but rather exploits a compromised browser environment. With the widespread adoption of passkeys, any vulnerability in their implementation can have severe consequences.
Understanding the Attack
The attack leverages JavaScript injection to manipulate the WebAuthn API, which is responsible for handling passkey registration and authentication. Here’s a step-by-step breakdown of how it works:
-
Malicious Browser Extension: An attacker convinces a user to install a malicious browser extension, often disguised as a legitimate tool. Alternatively, the attacker can exploit a client-side vulnerability, such as an XSS bug, to inject malicious JavaScript directly into the webpage.
-
Hijacking WebAuthn API: Once the malicious script is executed, it hijacks the WebAuthn API calls made by the legitimate website. This allows the attacker to forge both the registration and login flows.
-
Bypassing Authentication: By manipulating these API calls, the attacker can impersonate the user and bypass the passkey-based login process. Even if the user uses biometric authentication like Face ID, the attacker can still gain unauthorized access.
Real-World Example
Let’s look at a simplified example to illustrate how this attack might be carried out. Suppose a user visits a website that supports passkey authentication. Normally, the registration process involves the following steps:
// Normal WebAuthn registration process
navigator.credentials.create({
publicKey: {
rp: {
name: "Example Corp",
id: "example.com"
},
user: {
id: new Uint8Array([1, 2, 3]),
name: "[email protected]",
displayName: "John Doe"
},
pubKeyCredParams: [{
type: "public-key",
alg: -7 // ES256
}],
attestation: "direct",
challenge: new Uint8Array([/* random bytes */])
}
}).then(function (newCredentialInfo) {
console.log("Registration successful:", newCredentialInfo);
}).catch(function (err) {
console.error("Registration failed:", err);
});
An attacker can inject malicious JavaScript to manipulate this process:
// Malicious script to hijack WebAuthn registration
const originalCreate = navigator.credentials.create;
navigator.credentials.create = function (options) {
// Modify options to bypass authentication
options.publicKey.challenge = new Uint8Array([/* attacker-controlled bytes */]);
return originalCreate.call(navigator.credentials, options).then(function (newCredentialInfo) {
// Log or exfiltrate credential information
console.log("Credential info intercepted:", newCredentialInfo);
return newCredentialInfo;
});
};
Implications for Users
For users, the implications are significant. They may think they’re using a secure, phishing-resistant authentication method, but a compromised browser environment can still lead to unauthorized access. This attack highlights the importance of maintaining a secure browsing environment, including keeping browser extensions up to date and avoiding suspicious downloads.
Implications for Developers
Developers need to be aware of this vulnerability and take steps to mitigate it. Here are some best practices:
-
Secure Browser Extensions: Ensure all browser extensions are from trusted sources. Regularly update them to patch any known vulnerabilities.
-
Protect Against XSS: Implement strict Content Security Policy (CSP) headers to prevent XSS attacks. Validate and sanitize all user inputs to avoid injection vulnerabilities.
-
Validate Challenges: Always validate the challenge sent by the server to ensure it matches the expected value. This helps prevent manipulation of the WebAuthn API.
-
Use Trusted Libraries: Utilize well-maintained and secure libraries for handling WebAuthn operations. Avoid writing custom code unless absolutely necessary.
Example of Secure Challenge Validation
Here’s an example of how to implement challenge validation in the registration process:
// Server-side challenge generation
const crypto = require('crypto');
const challenge = crypto.randomBytes(32);
// Send challenge to client
res.json({ challenge });
// Client-side validation
fetch('/api/challenge')
.then(response => response.json())
.then(data => {
const expectedChallenge = data.challenge;
navigator.credentials.create({
publicKey: {
rp: {
name: "Example Corp",
id: "example.com"
},
user: {
id: new Uint8Array([1, 2, 3]),
name: "[email protected]",
displayName: "John Doe"
},
pubKeyCredParams: [{
type: "public-key",
alg: -7 // ES256
}],
attestation: "direct",
challenge: Uint8Array.from(atob(expectedChallenge), c => c.charCodeAt(0))
}
}).then(function (newCredentialInfo) {
console.log("Registration successful:", newCredentialInfo);
// Send newCredentialInfo to server for verification
}).catch(function (err) {
console.error("Registration failed:", err);
});
});
Common Pitfalls to Avoid
- **Ignoring CS
Security Warnings
- Keep Your Environment Updated: Regularly update your browser and extensions to protect against known vulnerabilities.
- Be Cautious with Extensions: Only install extensions from trusted sources and review their permissions carefully.
- Monitor for Suspicious Activity: Implement monitoring and logging to detect any unusual activity that might indicate an attack.
Conclusion
The recent demonstration by SquareX highlights a critical vulnerability in passkey authentication via WebAuthn. While passkeys offer a more secure alternative to traditional passwords, a compromised browser environment can still pose significant risks. By implementing best practices for browser security, protecting against XSS, and validating challenges, developers can help mitigate this risk and ensure a secure authentication process.
Stay vigilant and proactive in securing your systems. That’s it. Simple, secure, works.