惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Spread Privacy
Spread Privacy
P
Palo Alto Networks Blog
P
Proofpoint News Feed
AI
AI
Help Net Security
Help Net Security
S
Securelist
T
Troy Hunt's Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
C
Cisco Blogs
Scott Helme
Scott Helme
Hacker News - Newest:
Hacker News - Newest: "LLM"
Vercel News
Vercel News
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
B
Blog
GbyAI
GbyAI
Recent Commits to openclaw:main
Recent Commits to openclaw:main
D
Darknet – Hacking Tools, Hacker News & Cyber Security
P
Proofpoint News Feed
S
Security Affairs
Cisco Talos Blog
Cisco Talos Blog
AWS News Blog
AWS News Blog
T
Tenable Blog
H
Help Net Security
NISL@THU
NISL@THU
F
Fortinet All Blogs
博客园_首页
G
GRAHAM CLULEY
L
LINUX DO - 最新话题
P
Privacy International News Feed
G
Google Developers Blog
博客园 - Franky
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Security Archives - TechRepublic
Security Archives - TechRepublic
The Register - Security
The Register - Security
L
LangChain Blog
aimingoo的专栏
aimingoo的专栏
T
Tor Project blog
P
Privacy & Cybersecurity Law Blog
量子位
C
Cyber Attacks, Cyber Crime and Cyber Security
Forbes - Security
Forbes - Security
S
Secure Thoughts
Simon Willison's Weblog
Simon Willison's Weblog
D
Docker
Recorded Future
Recorded Future
博客园 - 三生石上(FineUI控件)
L
Lohrmann on Cybersecurity
T
Tailwind CSS Blog

Scott Helme

Connection Allowlist: a network firewall, built into the browser Top 1 Million Analysis – June 2026: The State of Crypto Top 1 Million Analysis – June 2026: Ten Years of Web Security A dead CDN, a wildcard, and an attack waiting to happen: the netdna-ssl.com takeover Why No Passkeys? Naming the Top Sites That Still Don't Support Them The Instructure Canvas Breach (2026): How XSS in a Support Ticket Compromised 275 Million Students Open-Sourcing dbsc-php: a Server Library for Device Bound Session Credentials in PHP DBSC Beta at Report URI Device Bound Session Credentials: Making Stolen Cookies Useless Passkeys, Permissions Policy and Bug Hunting in 1Password's WebAuthn Wrapper XSS Is Deadly for Passkeys: The Hidden Risk of Attestation None Passkeys 101: An Introduction to Passkeys and How They Work Anatomy of a WooCommerce Skimmer: A Technical Deep-Dive Under Attack: Responding to the Rise of Info-Stealer Threats Security considerations when using Passkeys on your website Fighting an active Magecart Campaign Amazing Refresh — A Malicious Chrome Extension Running Malware in the Browser Bringing in the experts; Having our Passkeys implementation Security Tested Launching Passkeys support on Report URI! 🗝️ When “One in a Billion” Happens Every Day: Scaling Redis at Report URI Leverage our treasure trove of Threat Intelligence data XSS Ranked #1 Top Threat of 2025 by MITRE and CISA DNS-PERSIST-01; Handling Domain Control Validation in a short-lived certificate World
Open-Sourcing passkeys-php: A Security-Focused WebAuthn Library for PHP
Scott Helme · 2026-05-20 · via Scott Helme

We've open-sourced passkeys-php, the WebAuthn server library we use at Report URI to protect logins with passkeys, security keys, and platform authenticators like Touch ID, Face ID, and Windows Hello.

It started as a set of local security fixes for our own production passkeys implementation. Now, rather than carrying those patches privately, we’re releasing them as a small, auditable, MIT-licensed PHP library for everyone else building normal passkey login flows.

To get started: composer require report-uri/passkeys-php
Packagist: https://packagist.org/packages/report-uri/passkeys-php

Why We Built It

Our passkeys-php is a maintained fork of the excellent lbuchs/WebAuthn, forked at upstream v2.2.0. We wanted to preserve what made that library appealing: it was small, lightweight, and understandable enough that you could actually read the code guarding your logins.

The catch was that the upstream is effectively dormant. When we had Report URI's passkeys integration penetration tested, the assessment surfaced several WebAuthn conformance issues. We wrote fixes and submitted them as PRs upstream, but they haven't been merged. Rather than carry a stack of local patches indefinitely — and leave everyone else on the same library exposed — we're shipping the fixes inline and in the open.

What We Fixed

Each fix is its own commit on main so you can audit exactly what changed and why if you'd like, but the summary is below. These were not cosmetic changes; they were the kinds of edge cases that matter when a library is responsible for deciding whether an authentication ceremony is valid.

  • Tighter origin check. The previous RP-ID match treated the RP ID as a substring suffix, so example.com would match the host evil-example.com. It
    now requires an exact match or a true subdomain.
  • Cross-origin rejection. Registration and authentication now reject ceremonies where clientDataJSON.crossOrigin === true, per WebAuthn Level 3.
  • Attestation none hardening. The none attestation statement must be an empty CBOR map, per WebAuthn §8.7. Non-empty maps are now rejected.
  • Backup flag validation. Authenticator data with the Backup State bit set but Backup Eligible unset is now rejected, per spec.
  • Token Binding rejection. Ceremonies asserting Token Binding are rejected, since the library doesn't implement it.

We Deleted Attestation

The headline change is that attestation verification is gone entirely; the library now supports only the none attestation format. Our penetration test and our own internal security reviews showed that serious risk was concentrated almost entirely in attestation-statement handling — the TPM, Packed, U2F, Android Key, Android SafetyNet and Apple formats, plus the FIDO Metadata Service plumbing and root-CA trust set. That code path is also the part of WebAuthn that our typical users don't use: browsers and platform authenticators issue attestation: "none" by default, and demanding attestation actively harms passkey UX and privacy.

So we removed it — over 1,100 lines of it. Now, getCreateArgs() always requests attestation: "none" (which the spec requires the client to honour by stripping the statement, whatever authenticator the user holds), and only fmt: "none" with an empty attStmt is accepted. The library is now positioned for the common case: SaaS-style passkey auth where the relying party only needs to know the user controls a credential bound to the RP — not which authenticator produced it. If you genuinely need enterprise attestation with a managed CA set, this isn't the library for you, and we think that's the right trade: a large, dangerous, rarely-exercised attack surface deleted instead of subtly-broken verifiers shipped to people who wouldn't enable them anyway.

Getting Started

The library autoloads under PSR-4 as ReportUri\Passkeys, with the main entry point aligned with the spec name:

use ReportUri\Passkeys\WebAuthn;
$server = new WebAuthn('My App', 'example.com');

There's a working registration and login demo in _test/ to get you going, and this is currently deployed on the Report URI production site so you can always test it there too!

Passkeys are one of the best things to happen to authentication in years, but only if the server side gets the verification right. That’s the part users never see, and the part a library has to get exactly right.

passkeys-php is our attempt to keep that code small, readable, auditable, and safe for the common case. Issues and PRs welcome.


Have you enjoyed this post or found it helpful?
☕️ Consider buying me a coffee to say thanks!
🔔 Subscribe for free notifications when I publish!
🤩 Become a member and support my content!

Tags: Report URI, Passkeys, PHP