# WebAuthn & Passkeys

Security testing for FIDO2, WebAuthn, and passkey implementations.

> **Skill Level**: Intermediate to Advanced\
> **Prerequisites**: Authentication concepts, cryptography basics, web security

## Overview

```
WebAuthn/FIDO2 provides phishing-resistant authentication using:
- Public key cryptography
- Hardware authenticators (YubiKey, etc.)
- Platform authenticators (Touch ID, Windows Hello)
- Passkeys (synced across devices)

Components:
- Relying Party (RP): The website/service
- Authenticator: Hardware or platform key
- Client: Browser implementing WebAuthn API
```

## Attack Surface

```
Potential weaknesses:
1. RP implementation bugs
2. Authenticator vulnerabilities
3. Attestation bypass
4. Fallback authentication
5. Account recovery flows
6. Session management post-auth
7. Origin validation issues
```

## Registration Flow Testing

### Intercept Registration

```javascript
// Monitor registration in browser console
navigator.credentials.create({
    publicKey: {
        challenge: new Uint8Array([...]),
        rp: { name: "Target", id: "target.com" },
        user: { id: new Uint8Array([...]), name: "user@target.com", displayName: "User" },
        pubKeyCredParams: [{ type: "public-key", alg: -7 }],  // ES256
        authenticatorSelection: { authenticatorAttachment: "platform" },
        timeout: 60000,
        attestation: "none"
    }
}).then(cred => console.log(cred));
```

### Test Cases

```
Registration attacks to test:

1. Replay registration response
   - Capture authenticatorData and clientDataJSON
   - Replay to different user account

2. Tamper with clientDataJSON
   - Modify origin field
   - Modify challenge

3. Weak attestation
   - Accept "none" attestation when direct required
   - Accept self-attestation

4. No challenge validation
   - Use expired/static challenge

5. Multiple credential registration
   - Register same authenticator to multiple accounts
```

## Authentication Flow Testing

### Intercept Authentication

```javascript
// Monitor authentication in browser console
navigator.credentials.get({
    publicKey: {
        challenge: new Uint8Array([...]),
        rpId: "target.com",
        allowCredentials: [{
            type: "public-key",
            id: new Uint8Array([...]),
            transports: ["usb", "nfc", "ble", "internal"]
        }],
        userVerification: "preferred",
        timeout: 60000
    }
}).then(assertion => console.log(assertion));
```

### Test Cases

```
Authentication attacks to test:

1. Signature replay
   - Capture assertion signature
   - Replay on different session

2. Counter validation bypass
   - Authenticators maintain sign counter
   - Counter going backwards = cloned key
   - Check if RP validates counter

3. User verification bypass
   - Set userVerification: "discouraged"
   - Bypass biometric/PIN requirement

4. Cross-origin attack
   - Modify origin in clientDataJSON
   - Test RP ID matching
```

## Common Vulnerabilities

### Weak Challenge Generation

```python
# Vulnerable: Predictable challenge
def generate_challenge():
    return base64.b64encode(str(time.time()).encode())

# Should be:
def generate_challenge():
    return base64.b64encode(os.urandom(32))
```

### Missing RP ID Validation

```javascript
// Test with subdomain
// If RP ID is "target.com", test from "evil.target.com"
// Should fail but misconfigured RPs may accept

// In browser on evil.target.com:
navigator.credentials.get({
    publicKey: {
        challenge: challenge,
        rpId: "target.com",  // RP ID of legitimate site
        allowCredentials: [...]
    }
});
```

### Fallback Authentication Bypass

```
1. Register WebAuthn credential
2. Trigger "lost authenticator" flow
3. Check if weaker auth method available:
   - Email link
   - SMS OTP
   - Security questions
   - Password reset

If fallback exists, WebAuthn security is undermined.
```

### Origin Confusion

```python
# Check how RP validates origin in clientDataJSON

# clientDataJSON contains:
{
    "type": "webauthn.get",
    "challenge": "...",
    "origin": "https://target.com",  # Must match RP
    "crossOrigin": false
}

# Test cases:
# origin: "https://target.com."  (trailing dot)
# origin: "https://Target.com"   (case sensitivity)
# origin: "https://target.com:443" (explicit port)
# crossOrigin: true (from iframe)
```

### Counter Bypass

```python
# Authenticators maintain a signature counter
# Cloned keys don't sync counters

# Test: Accept decreasing counter
# 1. Authenticate (counter = 100)
# 2. Clone/modify to send counter = 50
# 3. If accepted, counter validation is broken

def verify_assertion(stored_counter, received_counter):
    if received_counter <= stored_counter:
        raise SecurityError("Possible cloned authenticator")
    # Update stored counter
```

## Passkey-Specific Testing

### Synced Credentials

```
Passkeys sync across devices via:
- iCloud Keychain (Apple)
- Google Password Manager
- Microsoft Account

Test scenarios:
1. Credential export/import
2. Cross-platform sync security
3. Account recovery with synced credentials
4. Revocation of synced credentials
```

### Hybrid/Cross-Device Auth

```
FIDO2 CTAP 2.2 allows phone as authenticator:
1. User scans QR code on desktop
2. Authenticates on phone via BLE proximity
3. Desktop receives credential

Test:
- BLE relay attacks
- QR code capture/replay
- Man-in-the-middle on transport
```

## Testing Tools

### Browser DevTools

```javascript
// Chrome: Enable WebAuthn emulator
// DevTools → More tools → WebAuthn

// Firefox: about:webauthn for debugging

// View credential details
navigator.credentials.get({
    publicKey: {
        challenge: new Uint8Array(32),
        rpId: location.hostname,
        userVerification: "discouraged"
    }
}).then(c => {
    console.log("Credential ID:", btoa(String.fromCharCode(...new Uint8Array(c.rawId))));
    console.log("Client Data:", JSON.parse(new TextDecoder().decode(c.response.clientDataJSON)));
});
```

### WebAuthn Debugger

```bash
# Chrome extension for debugging
# "WebAuthn Developer Tool"

# Allows:
# - Virtual authenticator creation
# - Credential inspection
# - Attestation testing
```

### Burp Suite

```
1. Intercept registration/authentication requests
2. Modify challenge, origin, credential data
3. Test signature validation
4. Check for timing attacks

Extensions:
- "FIDO2/WebAuthn Tester" (if available)
```

### Python Testing

```python
from fido2.client import Fido2Client
from fido2.webauthn import PublicKeyCredentialCreationOptions
from fido2.server import Fido2Server

# Create test server
server = Fido2Server({"id": "localhost", "name": "Test"})

# Generate registration options
options, state = server.register_begin(
    {"id": b"user_id", "name": "test", "displayName": "Test User"},
    credentials=[]
)

# Test with malformed options
# Modify challenge, origin, etc.
```

## Bypass Techniques

### Attestation Bypass

```
If RP requires specific attestation:

1. "none" attestation - No verification
2. "self" attestation - Self-signed
3. "packed" attestation - May accept any

Test: Change attestation statement format
Test: Provide invalid attestation but valid signature
```

### User Verification Bypass

```javascript
// Force authentication without biometric/PIN
options.userVerification = "discouraged";

// Check if RP accepts UV=false when UV=required configured
// Some implementations don't enforce UV flag
```

### Resident Credential Attacks

```
Resident/discoverable credentials stored on authenticator:
- Don't need allowCredentials list
- Can enumerate usernames

Test:
1. Register resident credential
2. Check if username leaked in assertion
3. Test for credential enumeration
```

## Account Recovery Testing

```
When user loses authenticator:

1. What recovery options exist?
   - Backup codes (should be WebAuthn-protected)
   - Email link (weak)
   - Support process (social engineering)

2. Can attacker trigger recovery?
3. Does recovery bypass MFA entirely?
4. Are backup codes WebAuthn-generated?
```

## Implementation Checklist

```
For pentesters to verify:

[ ] Challenge is cryptographically random (32+ bytes)
[ ] Challenge expires (< 5 minutes)
[ ] Challenge is single-use
[ ] Origin validation is strict
[ ] RP ID validation is correct
[ ] Signature counter is validated
[ ] User verification flag checked if required
[ ] Attestation verified (if required)
[ ] No weaker fallback auth methods
[ ] Credential binding to user account
[ ] Rate limiting on authentication
```

## Related Topics

* [OIDC](/enumeration/webservices/oidc-open-id-connect.md) - WebAuthn + OIDC integration
* [OAuth](/enumeration/webservices/oauth.md) - OAuth with WebAuthn
* [JWT](/enumeration/webservices/jwt.md) - Token-based auth comparison


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://www.pentest-book.com/others/webauthn-passkeys.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
