Security guidelines for FaceVerify deployments.
[!CAUTION] Face images are biometric data. Handle with care.
Recommendations:
# Store embeddings instead of images
embedding = verifier.extract_embedding("face.jpg").embedding
# Save to secure storage
import numpy as np
np.save("embeddings/user_123.npy", embedding)
Always require authentication for verification endpoints:
from functools import wraps
def require_auth(f):
@wraps(f)
def decorated(*args, **kwargs):
auth = request.headers.get("Authorization")
if not validate_token(auth):
return {"error": "Unauthorized"}, 401
return f(*args, **kwargs)
return decorated
@app.post("/verify")
@require_auth
def verify():
...
Prevent abuse with rate limiting:
from flask_limiter import Limiter
limiter = Limiter(app, default_limits=["100 per hour"])
@app.post("/verify")
@limiter.limit("10 per minute")
def verify():
...
[!WARNING] Always validate uploaded images.
ALLOWED_EXTENSIONS = {'.jpg', '.jpeg', '.png'}
MAX_FILE_SIZE = 10 * 1024 * 1024 # 10MB
def validate_image(file):
# Check extension
ext = Path(file.filename).suffix.lower()
if ext not in ALLOWED_EXTENSIONS:
raise ValueError("Invalid file type")
# Check size
file.seek(0, 2)
size = file.tell()
file.seek(0)
if size > MAX_FILE_SIZE:
raise ValueError("File too large")
Higher threshold = Lower FAR = More secure
| Threshold | Approximate FAR |
|---|---|
| 0.60 | ~1% |
| 0.70 | ~0.1% |
| 0.80 | ~0.01% |
[!IMPORTANT] For security applications, use threshold >= 0.70
FaceVerify does not include liveness detection. For production security systems:
Log all verification attempts:
import logging
logger = logging.getLogger("faceverify.audit")
def verify_with_audit(image1, image2, user_id):
result = verifier.verify(image1, image2)
logger.info(
"Verification attempt",
extra={
"user_id": user_id,
"verified": result.verified,
"confidence": result.confidence,
"timestamp": result.timestamp.isoformat(),
}
)
return result
[!CAUTION] Never log:
- Raw face images
- Full embedding vectors
- Personal identifiable information (PII)