Passkeys ????????? WebAuthn ?????????????????????
Passkeys ????????????????????????????????? passwordless authentication ????????????????????????????????? FIDO Alliance ????????? W3C ????????? public-key cryptography ????????? passwords ??????????????????????????????????????????????????????????????????????????????????????????????????? ?????????????????? biometrics (fingerprint, Face ID), security keys (YubiKey) ????????? device PIN
WebAuthn (Web Authentication API) ???????????? browser API ???????????????????????????????????????????????????????????? passkeys ???????????????????????????????????? authenticators ???????????? Touch ID, Windows Hello, Android biometrics ??????????????? shared secret ????????????????????? client ????????? server ?????????????????????????????? phishing, credential stuffing ????????? data breaches
Infrastructure as Code (IaC) ?????????????????? passkeys ????????????????????? ????????? provision ????????? manage WebAuthn infrastructure ???????????? code (Terraform, Pulumi) ?????????????????? database ?????????????????????????????? credentials, API servers, CDN, monitoring ??????????????? reproducible, version-controlled ????????? scalable
????????????????????? WebAuthn Server
Setup WebAuthn server ?????????????????? passkey authentication
# === WebAuthn Server Setup ===
# 1. Install dependencies (Node.js)
cat > package.json << 'EOF'
{
"name": "webauthn-server",
"version": "1.0.0",
"dependencies": {
"@simplewebauthn/server": "^9.0.0",
"@simplewebauthn/types": "^9.0.0",
"express": "^4.18.0",
"express-session": "^1.17.0",
"redis": "^4.6.0"
}
}
EOF
npm install
# 2. Docker Compose
cat > docker-compose.yml << 'EOF'
version: '3.8'
services:
webauthn-api:
build: .
ports:
- "3000:3000"
environment:
- RP_NAME=MyApp
- RP_ID=example.com
- ORIGIN=https://example.com
- REDIS_URL=redis://redis:6379
- DATABASE_URL=postgres://user:pass@postgres:5432/webauthn
depends_on:
- redis
- postgres
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis-data:/data
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: webauthn
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
volumes:
- pg-data:/var/lib/postgresql/data
- ./schema.sql:/docker-entrypoint-initdb.d/schema.sql
volumes:
redis-data:
pg-data:
EOF
# 3. Database Schema
cat > schema.sql << 'EOF'
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
username VARCHAR(255) UNIQUE NOT NULL,
display_name VARCHAR(255),
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE credentials (
id VARCHAR(512) PRIMARY KEY,
user_id UUID REFERENCES users(id),
public_key BYTEA NOT NULL,
counter BIGINT DEFAULT 0,
device_type VARCHAR(50),
backed_up BOOLEAN DEFAULT false,
transports TEXT[],
created_at TIMESTAMPTZ DEFAULT NOW(),
last_used_at TIMESTAMPTZ
);
CREATE INDEX idx_credentials_user ON credentials(user_id);
EOF
echo "WebAuthn server setup complete"
Infrastructure as Code ?????????????????? Passkeys
Terraform configuration ?????????????????? WebAuthn infrastructure
# === Terraform Infrastructure ===
cat > main.tf << 'EOF'
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = var.region
}
# VPC
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.5.0"
name = "webauthn-vpc"
cidr = "10.0.0.0/16"
azs = ["a", "b"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24"]
enable_nat_gateway = true
}
# RDS PostgreSQL for credentials
resource "aws_db_instance" "webauthn" {
identifier = "webauthn-db"
engine = "postgres"
engine_version = "16.1"
instance_class = "db.t3.medium"
allocated_storage = 20
max_allocated_storage = 100
storage_encrypted = true
db_name = "webauthn"
username = "webauthn_admin"
password = var.db_password
vpc_security_group_ids = [aws_security_group.db.id]
db_subnet_group_name = aws_db_subnet_group.main.name
backup_retention_period = 7
multi_az = true
deletion_protection = true
tags = { Service = "webauthn" }
}
# ElastiCache Redis for sessions/challenges
resource "aws_elasticache_cluster" "sessions" {
cluster_id = "webauthn-sessions"
engine = "redis"
node_type = "cache.t3.medium"
num_cache_nodes = 1
parameter_group_name = "default.redis7"
port = 6379
security_group_ids = [aws_security_group.redis.id]
subnet_group_name = aws_elasticache_subnet_group.main.name
}
# ECS Fargate for API
resource "aws_ecs_service" "webauthn_api" {
name = "webauthn-api"
cluster = aws_ecs_cluster.main.id
task_definition = aws_ecs_task_definition.api.arn
desired_count = 2
launch_type = "FARGATE"
network_configuration {
subnets = module.vpc.private_subnets
security_groups = [aws_security_group.api.id]
}
load_balancer {
target_group_arn = aws_lb_target_group.api.arn
container_name = "webauthn-api"
container_port = 3000
}
}
# ALB with HTTPS
resource "aws_lb" "main" {
name = "webauthn-alb"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.alb.id]
subnets = module.vpc.public_subnets
}
resource "aws_lb_listener" "https" {
load_balancer_arn = aws_lb.main.arn
port = 443
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
certificate_arn = var.certificate_arn
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.api.arn
}
}
# CloudWatch Alarms
resource "aws_cloudwatch_metric_alarm" "auth_errors" {
alarm_name = "webauthn-auth-errors"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 2
metric_name = "AuthenticationErrors"
namespace = "WebAuthn"
period = 300
statistic = "Sum"
threshold = 50
alarm_description = "High authentication error rate"
alarm_actions = [var.sns_topic_arn]
}
variable "region" { default = "ap-southeast-1" }
variable "db_password" { sensitive = true }
variable "certificate_arn" {}
variable "sns_topic_arn" {}
EOF
echo "Terraform infrastructure configured"
Implement Passkeys ?????? Web Application
Implementation ???????????? server ????????? client
#!/usr/bin/env python3
# webauthn_service.py ??? WebAuthn Passkeys Implementation
import json
import logging
import hashlib
import base64
import os
from typing import Dict, List, Optional
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("webauthn")
class WebAuthnService:
"""WebAuthn passkey registration and authentication"""
def __init__(self, rp_id="example.com", rp_name="MyApp"):
self.rp_id = rp_id
self.rp_name = rp_name
self.origin = f"https://{rp_id}"
self.users = {}
self.credentials = {}
self.challenges = {}
def generate_registration_options(self, user_id, username):
"""Generate options for passkey registration"""
challenge = base64.urlsafe_b64encode(os.urandom(32)).decode()
options = {
"challenge": challenge,
"rp": {
"name": self.rp_name,
"id": self.rp_id,
},
"user": {
"id": base64.urlsafe_b64encode(user_id.encode()).decode(),
"name": username,
"displayName": username,
},
"pubKeyCredParams": [
{"alg": -7, "type": "public-key"}, # ES256
{"alg": -257, "type": "public-key"}, # RS256
],
"timeout": 60000,
"attestation": "none",
"authenticatorSelection": {
"authenticatorAttachment": "platform",
"residentKey": "required",
"userVerification": "required",
},
"excludeCredentials": self._get_user_credentials(user_id),
}
self.challenges[user_id] = challenge
return options
def verify_registration(self, user_id, credential):
"""Verify registration response"""
expected_challenge = self.challenges.get(user_id)
if not expected_challenge:
return {"success": False, "error": "Challenge not found"}
# In production: verify attestation, extract public key
cred_id = credential.get("id", "")
self.credentials[cred_id] = {
"user_id": user_id,
"public_key": credential.get("publicKey", ""),
"counter": 0,
"device_type": credential.get("authenticatorAttachment", "platform"),
"backed_up": credential.get("backedUp", False),
}
del self.challenges[user_id]
return {"success": True, "credential_id": cred_id}
def generate_authentication_options(self, user_id=None):
"""Generate options for passkey authentication"""
challenge = base64.urlsafe_b64encode(os.urandom(32)).decode()
options = {
"challenge": challenge,
"rpId": self.rp_id,
"timeout": 60000,
"userVerification": "required",
}
if user_id:
options["allowCredentials"] = self._get_user_credentials(user_id)
self.challenges[user_id] = challenge
else:
# Discoverable credentials (usernameless)
options["allowCredentials"] = []
self.challenges["_anonymous"] = challenge
return options
def verify_authentication(self, credential):
"""Verify authentication response"""
cred_id = credential.get("id", "")
stored = self.credentials.get(cred_id)
if not stored:
return {"success": False, "error": "Credential not found"}
# In production: verify signature, check counter
stored["counter"] += 1
return {
"success": True,
"user_id": stored["user_id"],
"counter": stored["counter"],
}
def _get_user_credentials(self, user_id):
return [
{"id": cid, "type": "public-key"}
for cid, cred in self.credentials.items()
if cred["user_id"] == user_id
]
# Demo
service = WebAuthnService(rp_id="example.com", rp_name="MyApp")
# Registration
reg_options = service.generate_registration_options("user-001", "john@example.com")
print(f"Registration Options:")
print(f" RP: {reg_options['rp']['name']} ({reg_options['rp']['id']})")
print(f" Challenge: {reg_options['challenge'][:30]}...")
print(f" Algorithms: {[p['alg'] for p in reg_options['pubKeyCredParams']]}")
# Simulate registration
result = service.verify_registration("user-001", {
"id": "cred-abc123",
"publicKey": "mock-public-key",
"authenticatorAttachment": "platform",
"backedUp": True,
})
print(f"\nRegistration: {result}")
# Authentication
auth_options = service.generate_authentication_options("user-001")
print(f"\nAuth Options: challenge={auth_options['challenge'][:30]}...")
auth_result = service.verify_authentication({"id": "cred-abc123"})
print(f"Authentication: {auth_result}")
Security ????????? Best Practices
Security considerations ?????????????????? passkeys
# === Security Best Practices ===
cat > security_config.yaml << 'EOF'
passkeys_security:
server_side:
challenge:
- "Generate cryptographically random challenge (32+ bytes)"
- "Store challenge server-side (Redis with TTL 5min)"
- "Validate challenge on response (prevent replay)"
- "One-time use only (delete after verification)"
credential_storage:
- "Store public key only (never private key)"
- "Encrypt credential data at rest"
- "Use parameterized queries (prevent SQL injection)"
- "Implement rate limiting on registration/authentication"
origin_validation:
- "Verify origin matches expected RP ID"
- "HTTPS required (no HTTP)"
- "Validate RP ID against allowed list"
counter_verification:
- "Track signature counter per credential"
- "Reject if counter goes backward (cloned authenticator)"
- "Alert on counter anomalies"
client_side:
- "Use Conditional UI (autofill) for seamless UX"
- "Support both platform and cross-platform authenticators"
- "Graceful fallback for unsupported browsers"
- "Clear error messages for user guidance"
infrastructure:
- "HTTPS everywhere (TLS 1.3)"
- "Database encryption at rest (AES-256)"
- "Redis with AUTH and TLS"
- "VPC isolation for backend services"
- "WAF for API protection"
- "DDoS protection (CloudFlare/AWS Shield)"
compliance:
- "FIDO2 certification for authenticators"
- "WebAuthn Level 2 specification compliance"
- "GDPR: user can delete passkeys"
- "Audit logging for all auth events"
EOF
python3 -c "
import yaml
with open('security_config.yaml') as f:
data = yaml.safe_load(f)
sec = data['passkeys_security']
print('Passkeys Security Best Practices:')
print('\nServer-side:')
for item in sec['server_side']['challenge'][:3]:
print(f' - {item}')
print('\nInfrastructure:')
for item in sec['infrastructure'][:4]:
print(f' - {item}')
"
echo "Security guide ready"
Monitoring ????????? Analytics
?????????????????? passkey authentication
#!/usr/bin/env python3
# passkey_monitor.py ??? Passkeys Monitoring & Analytics
import json
import logging
from typing import Dict, List
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("monitor")
class PasskeyMonitor:
def __init__(self):
pass
def dashboard(self):
return {
"adoption_metrics": {
"total_users": 50000,
"passkey_users": 12500,
"adoption_rate": "25%",
"trend": "+5% month-over-month",
"by_platform": {
"iOS_Safari": 45,
"Android_Chrome": 30,
"Windows_Chrome": 15,
"macOS_Safari": 10,
},
},
"auth_metrics_24h": {
"total_authentications": 85000,
"passkey_auths": 21250,
"password_auths": 63750,
"passkey_success_rate": "99.8%",
"password_success_rate": "94.2%",
"avg_auth_time_passkey_ms": 850,
"avg_auth_time_password_ms": 3500,
},
"security_metrics": {
"phishing_attempts_blocked": 0,
"credential_stuffing_blocked": 245,
"suspicious_counter_anomalies": 1,
"failed_auth_attempts": 42,
},
"recommendations": [
"Promote passkeys to remaining 75% users (in-app prompts)",
"Add conditional UI for seamless passkey autofill",
"Investigate 1 counter anomaly (possible cloned authenticator)",
"Consider removing password option for passkey-enrolled users",
],
}
monitor = PasskeyMonitor()
dash = monitor.dashboard()
adoption = dash["adoption_metrics"]
print(f"Passkeys Dashboard:")
print(f" Adoption: {adoption['adoption_rate']} ({adoption['passkey_users']:,}/{adoption['total_users']:,})")
print(f" Trend: {adoption['trend']}")
auth = dash["auth_metrics_24h"]
print(f"\nAuthentication (24h):")
print(f" Passkey: {auth['passkey_auths']:,} ({auth['passkey_success_rate']}), avg {auth['avg_auth_time_passkey_ms']}ms")
print(f" Password: {auth['password_auths']:,} ({auth['password_success_rate']}), avg {auth['avg_auth_time_password_ms']}ms")
sec = dash["security_metrics"]
print(f"\nSecurity: Phishing={sec['phishing_attempts_blocked']}, Stuffing={sec['credential_stuffing_blocked']}")
print(f"\nRecommendations:")
for r in dash["recommendations"]:
print(f" - {r}")
FAQ ??????????????????????????????????????????
Q: Passkeys ????????? Password ???????????????????????????????????????????
A: Password ???????????? shared secret ???????????? user ????????? server ????????? ??????????????????????????? phishing, brute force, credential stuffing, data breach ????????? server ????????? hack password ????????????????????? Passkeys ????????? public-key cryptography server ??????????????????????????? public key private key ?????????????????? device ????????? user ???????????????????????? ????????? server ????????? hack ??????????????? credentials ??????????????????????????? ????????????????????? phishing 100% ??????????????? browser verify origin ??????????????????????????? UX ?????????????????? ????????? scan fingerprint ???????????? Face ID ??????????????????????????? password ????????????????????? ???????????? browser/OS ?????????????????? (Chrome 108+, Safari 16+, Edge 108+), device ????????????????????????????????????????????? ???????????? recovery flow
Q: Infrastructure as Code ???????????????????????????????????? passkeys ??????????
A: ????????????????????????????????????????????? app ???????????? ?????????????????????????????????????????? production WebAuthn infrastructure ?????????????????? components Database (credentials), Cache (challenges), API server, Load balancer, Monitoring IaC ???????????? Reproducible ??????????????? environment ???????????????????????????????????????????????????, Version control ????????? change ????????? track, Disaster recovery ??????????????? infrastructure ????????????????????? code, Multi-environment dev/staging/prod ????????? code ??????????????? ?????????????????? startup/???????????????????????? ????????? managed services (Auth0, Firebase Auth, Supabase) ??????????????????????????? passkeys ????????????????????? manage infrastructure ????????? ?????????????????? enterprise ????????? IaC + self-hosted ????????? control ?????????????????????
Q: Passkeys sync ???????????? devices ???????????????????
A: ????????? ????????????????????? 2022 Apple, Google, Microsoft ?????????????????? synced passkeys Apple iCloud Keychain sync passkeys ???????????? iPhone, iPad, Mac, Google Password Manager sync ???????????? Android devices ????????? Chrome, Microsoft sync ???????????? Windows devices ???????????? Microsoft account Cross-platform ????????? QR code scan ????????? device ???????????? ???????????? iPhone scan QR ?????? Windows Chrome ???????????????????????? ????????? ecosystem ????????????????????? (Apple ??? Android) ?????????????????? sync ??????????????????????????? ??????????????????????????????????????? passkey ?????????????????? device ???????????? ????????????????????? QR cross-device authentication ??????????????? ????????? users ??????????????????????????????????????? passkeys (1 per ecosystem)
Q: Library ?????????????????????????????????????????? implement WebAuthn?
A: ????????????????????????????????? Node.js ????????? @simplewebauthn/server (??????????????? ?????????????????????) ???????????? fido2-lib, Python ????????? py_webauthn (Flask/Django) ???????????? python-fido2, Go ????????? go-webauthn/webauthn, Java ????????? java-webauthn-server (Yubico), .NET ????????? Fido2.AspNet Frontend ????????? @simplewebauthn/browser ???????????? native WebAuthn API ?????????????????? Managed services Auth0, Okta, Firebase Auth, Supabase Auth ?????????????????? passkeys built-in ????????????????????? implement ????????? ??????????????? ??????????????????????????? SimpleWebAuthn (Node.js) ???????????? py_webauthn (Python) ?????????????????????????????? documentation ??????