Category Archives: Security

Python by the C side

By

C shells by the C shoreMahmoud’s note: This will be my last post on the PayPal Engineering blog. If you’ve enjoyed this sort of content subscribe to my blog/pythondoeswhat.com or follow me on Twitter. It’s been fun!

All the world is legacy code, and there is always another, lower layer to peel away. These realities cause developers around the world to go on regular pilgrimage, from the terra firma of Python to the coasts of C. From zlib to SQLite to OpenSSL, whether pursuing speed, efficiency, or features, the waters are powerful, and often choppy. The good news is, when you’re writing Python, C interactions can be a day at the beach.

 

A brief history

As the name suggests, CPython, the primary implementation of Python used by millions, is written in C. Python core developers embraced and exposed Python’s strong C roots, taking a traditional tack on portability, contrasting with the “write once, debug everywhere” approach popularized elsewhere. The community followed suit with the core developers, developing several methods for linking to C. Years of these interactions have made Python a wonderful environment for interfacing with operating systems, data processing libraries, and everything the C world has to offer.

This has given us a lot of choices, and we’ve tried all of the standouts:

Approach Vintage Representative User Notable Pros Notable Cons
C extension modules 1991 Standard library Extensive documentation and tutorials. Total control. Compilation, portability, reference management. High C knowledge.
SWIG 1996 crfsuite Generate bindings for many languages at once Excessive overhead if Python is the only target.
ctypes 2003 oscrypto No compilation, wide availability Accessing and mutating C structures cumbersome and error prone.
Cython 2007 gevent, kivy Python-like. Highly mature. High performance. Compilation, new syntax and toolchain.
cffi 2013 cryptography, pypy Ease of integration, PyPy compatibility New/High-velocity.

There’s a lot of history and detail that doesn’t fit into a table, but every option falls into one of three categories:

  1. Writing C
  2. Writing code that translates to C
  3. Writing code that calls into libraries that present a C interface

Each has its merits, so we’ll explore each category, then finish with a real, live, worked example.

Writing C

Python’s core developers did it and so can you. Writing C extensions to Python gives an interface that fits like a glove, but also requires knowing, writing, building, and debugging C. The bugs are much more severe, too, as a segmentation fault that kills the whole process is much worse than a Python exception, especially in an asynchronous environment with hundreds of requests being handled within the same process. Not to mention that the glove is also tailored to CPython, and won’t fit quite right, or at all, in other execution environments.

At PayPal, we’ve used C extensions to speed up our service serialization. And while we’ve solved the build and portability issue, we’ve lost track of our share of references and have moved on from writing straight C extensions for new code.

Translating to C

After years of writing C, certain developers decide that they can do better. Some of them are certainly onto something.

Going Cythonic

Cython is a superset of the Python programming language that has been turning type-annotated Python into C extensions for nearly a decade, longer if you count its predecessor, Pyrex. Apart from its maturity, the points that matters to us are:

  • Every Python file is a valid Cython file, enabling incremental, iterative optimization
  • The generated C is highly portable, building on Windows, Mac, and Linux
  • It’s common practice to check in the generated C, meaning that builders don’t need to have Cython installed.

Not to mention that the generated C often makes use of performance tricks that are too tedious or arcane to write by hand, partially motivated by scientific computing’s constant push. And through all that, Cython code maintains a high level of integration with Python itself, right down to the stack trace and line numbers.

PayPal has certainly benefitted from their efforts through high-performance Cython users like gevent, lxml, and NumPy. While our first go with Cython didn’t stick in 2011, since 2015, all native extensions have been written and rewritten to use Cython. It wasn’t always this way however.

A sip, not a SWIG

An early contributor to Python at PayPal got us started using SWIG, the Simplified Wrapper and Interface Generator, to wrap PayPal C++ infrastructure. It served its purpose for a while, but every modification was a slog compared to more Pythonic techniques. It wasn’t long before we decided it wasn’t our cup of tea.

Long ago SWIG may have rivaled extension modules as Python programmers’ method of choice. These days it seems to suit the needs of C library developers looking for a fast and easy way to wrap their C bindings for multiple languages. It also says something that searching for SWIG usage in Python nets as much SWIG replacement libraries as SWIG usage itself.

Calling into C

So far all our examples have involved extra build steps, portability concerns, and quite a bit of writing languages other than Python. Now we’ll dig into some approaches that more closely match Python’s own dynamic nature: ctypes and cffi.

Both ctypes and cffi leverage C’s Foreign Function Interface (FFI), a sort of low-level API that declares callable entrypoints to compiled artifacts like shared objects (.so files) on Linux/FreeBSD/etc. and dynamic-link libraries (.dll files) on Windows. Shared objects take a bit more work to call, so ctypes and cffi both use libffi, a C library that enables dynamic calls into other C libraries.

Shared libraries in C have some gaps that libffi helps fill. A Linux .so, Windows .dll, or OS X .dylib is only going to provide symbols: a mapping from names to memory locations, usually function pointers. Dynamic linkers do not provide any information about how to use these memory locations. When dynamically linking shared libraries to C code, header files provide the function signatures; as long as the shared library and application are ABI compatible, everything works fine. The ABI is defined by the C compiler, and is usually carefully managed so as not to change too often.

However, Python is not a C compiler, so it has no way to properly call into C even with a known memory location and function signature. This is where libffi comes in. If symbols define where to call the API, and header files define what API to call, libffi translates these two pieces of information into how to call the API. Even so, we still need a layer above libffi that translates native Python types to C and vice versa, among other tasks.

ctypes

ctypes is an early and Pythonic approach to FFI interactions, most notable for its inclusion in the Python standard library.

ctypes works, it works well, and it works across CPython, PyPy, Jython, IronPython, and most any Python runtime worth its salt. Using ctypes, you can access C APIs from pure Python with no external dependencies. This makes it great for scratching that quick C itch, like a Windows API that hasn’t been exposed in the os module. If you have an otherwise small module that just needs to access one or two C functions, ctypes allows you to do so without adding a heavyweight dependency.

For a while, PayPal Python code used ctypes after moving off of SWIG. We found it easier to call into vanilla shared objects built from C++ with an extern C rather than deal with the SWIG toolchain. ctypes is still used incidentally throughout the code for exactly this: unobtrusively calling into certain shared objects that are widely deployed. A great open-source example of this use case is oscrypto, which does exactly this for secure networking. That said, ctypes is not ideal for huge libraries or libraries that change often. Porting signatures from headers to Python code is tedious and error-prone.

cffi

cffi, our most modern approach to C integration, comes out of the PyPy project. They were seeking an approach that would lend itself to the optimization potential of PyPy, and they ended up creating a library that fixes many of the pains of ctypes. Rather than handcrafting Python representations of the function signatures, you simply load or paste them in from C header files.

For all its convenience, cffi’s approach has its limits. C is really almost two languages, taking into account preprocessor macros. A macro performs string replacement, which opens a Fun World of Possibilities, as straightforward or as complicated as you can imagine. cffi’s approach is limited around these macros, so applicability will depend on the library with which you are integrating.

On the plus side, cffi does achieve its stated goal of outperforming ctypes under PyPy, while remaining comparable to ctypes under CPython. The project is still quite young, and we are excited to see where it goes next.

A Tale of 3 Integrations: PKCS11

We promised an example, and we almost made it three.

PKCS11 is a cryptography standard for interacting with many hardware and software security systems. The 200-plus-page core specification includes many things, including the official client interface: A large set of C header-style information. There are a variety of pre-existing bindings, but each device has its own vendor-specific quirks, so what are we waiting for?

Metaprogramming

As stated earlier, ctypes is not great for sprawling interfaces. The drudgery of converting function signatures invites transcription bugs. We somewhat automated it, but the approach was far from perfect.

Our second approach, using cffi, worked well for our first version’s supported feature subset, but unfortunately PKCS11 uses its own CK_DECLARE_FUNCTION macro instead of regular C syntax for defining functions. Therefore, cffi’s approach of skipping #define macros will result in syntactically invalid C code that cannot be parsed. On the other hand, there are other macro symbols which are compiler or operating system intrinsics (e.g. __cplusplus, _WIN32, __linux__). So even if cffi attempted to evaluate every macro, we would immediately runs into problems.

So in short, we’re faced with a hard problem. The PKCS11 standard is a gnarly piece of C. In particular:

  1. Many hundreds of important constant values are created with #define
  2. Macros are defined, then re-defined to something different later on in the same file
  3. pkcs11f.h is included multiple times, even once as the body of a struct

In the end, the solution that worked best was to write up a rigorous parser for the particular conventions used by the slow-moving standard, generate Cython, which generates C, which finally gives us access to the complete client, with the added performance bonus in certain cases. Biting this bullet took all of a day and a half, we’ve been very satisfied with the result, and it’s all thanks to a special trick up our sleeves.

Parsing Expression Grammars

Parsing expression grammars (PEGs) combine the power of a true parser generating an abstract syntax tree, not unlike the one used for Python itself, with the convenience of regular expressions. One might think of PEGs as recursive regular expressions. There are several good libraries for Python, including parsimonious and parsley. We went with the former for its simplicity.

For this application, we defined a two grammars, one for pkcs11f.h and one for pkcs11t.h:

PKCS11F GRAMMAR

    file = ( comment / func / " " )*
    func = func_hdr func_args
    func_hdr = "CK_PKCS11_FUNCTION_INFO(" name ")"
    func_args = arg_hdr " (" arg* " ); #endif"
    arg_hdr = " #ifdef CK_NEED_ARG_LIST" (" " comment)?
    arg = " " type " " name ","? " " comment
    name = identifier
    type = identifier
    identifier = ~"[A-Z_][A-Z0-9_]*"i
    comment = ~"(/\*.*?\*/)"ms

PKCS11T GRAMMAR

    file = ( comment / define / typedef / struct_typedef / func_typedef / struct_alias_typedef / ignore )*
    typedef = " typedef" type identifier ";"
    struct_typedef = " typedef struct" identifier " "? "{" (comment / member)* " }" identifier ";"
    struct_alias_typedef = " typedef struct" identifier " CK_PTR"? identifier ";"
    func_typedef = " typedef CK_CALLBACK_FUNCTION(CK_RV," identifier ")(" (identifier identifier ","? comment?)* " );"    member = identifier identifier array_size? ";" comment?
    array_size = "[" ~"[0-9]"+ "]"
    define = "#define" identifier (hexval / decval / " (~0UL)" / identifier / ~" \([A-Z_]*\|0x[0-9]{8}\)" )
    hexval = ~" 0x[A-F0-9]{8}"i
    decval = ~" [0-9]+"
    type = " unsigned char" / " unsigned long int" / " long int" / (identifier " CK_PTR") / identifier
    identifier = " "? ~"[A-Z_][A-Z0-9_]*"i
    comment = " "? ~"(/\*.*?\*/)"ms
    ignore = ( " #ifndef" identifier ) / " #endif" / " "

Short, but dense, in true grammatical style. Looking at the whole program, it’s a straightforward process:

  1. Apply the grammars to the header files to get our abstract syntax tree.
  2. Walk the AST and sift out the semantically important pieces, function signatures in our case.
  3. Generate code from the function signature data structures.

Using only 200 lines of code to bring such a massive standard to bear, along with the portability and performance of Cython, through the power of PEGs ranks as one of the high points of Python in practice at PayPal.

Wrapping up

It’s been a long journey, but we stayed afloat and we’re happy to have made it. To recap:

  • Python and C are hand-in-glove made for one another.
  • Different C integration techniques have their applications, our stances are:
    • ctypes for dynamic calls to small, stable interfaces
    • cffi for dynamic calls to larger interfaces, especially when targeting PyPy
    • Old-fashioned C extensions if you’re already good at them
    • Cython-based C extensions for the rest
    • SWIG pretty much never
  • Parsing Expression Grammars are great!

All of this encapsulates perfectly why we love Python so much. Python is a great starter language, but it also has serious chops as a systems language and ecosystem. That bottom-to-top, rags-to-riches, books-to-bits story is what makes it the ineffable, incomparable language that it is.

C you around!

Kurt and Mahmoud

Stop by PayPal’s Booth in the Black Hat Career Zone to Talk Security and Learn about REAPER!

By

This year’s Black Hat conference is a big one for PayPal because it is the first time we are attending as a conference sponsor. In 2016 we’ve made a concerted effort to show up at a number of events to discuss security careers and hear about the experiences of you, our peers and colleagues.

I will be at the booth along with several other PayPal InfoSec professionals from various security disciplines on August 3rd and 4th. Along with various swag and security puzzles, we want to highlight some interesting academic research conducted this year by our Threat Intelligence team.

REAPER was presented at the Anti Phishing Working Group’s 2016 e-Crime Symposium last month. It’s a methodology for automating a solution for mass credential harvesting and OSINT collection. We will have copies of the paper and business card-sized flyers linking to the paper at the booth. For those not attending, we’ve linked to the full length paper here.

We’d love to hear your thoughts on the research; feel free to drop us a line with your comments at infosec@paypal.com or tweet us at @PayPalSecurity. Hope to see you at the conference!

Securing your JS apps w/ Stateless CSRF

By

Hey there! You might have stumbled upon this post because you’re interested in securing your JS apps, or maybe you’ve heard about the other things we have open sourced.

Today we’re releasing jwt-csrf, a stateless CSRF solution for securing your JavaScript apps!

It’s something we’ve built and battle tested over the last year while building PayPal Checkout. In addition to talking about jwt-csrf, I’d like to talk about our journey of re-architecting PayPal Checkout and share our learnings and discoveries.

If you’ve checked out with PayPal in the last year or so, woohoo! You know what we work on 🙂 By the way, if any of this is interesting to you, we’re hiring! DM me at @mark_stuart

Why stateless?

About a year ago, we were stuck in a jam where we had way too much state on our server-side and caused us to take a step back and re-think many aspects of our architecture.

If you’re familiar with Express, you know about req.session, which is basically a global variable that is scoped to a user’s session and hangs off of the request object. This usually isn’t a problem for solo developers or really small development teams, but as soon as you add more developers to the mix, you will reach a point where most of your issues are around maintaining state.

“Shared mutable state is the root of all evil”. — Someone smart

Just a couple examples of our pain —

  • Slow experimentation Our client-side was unable to evolve without code changes in our server-side.
  • Brittle middleware — Our common middleware functions had to be stacked in a particular order, otherwise they wouldn’t work. Some of these middleware would depend on some values in req.session that were randomly set by other middleware. If you use Express, this one should ring home.

Okay, so global mutable state is bad. But, what’s the alternative?

We decided that we were going to go completely stateless. Rather than building “god” endpoints that do a lot of orchestration and rely on stateful flags in req.session, we built atomic APIs that do 1 thing, and 1 thing only. Ex: Get cart details, Add a credit card, etc.

Along with that, we had to make changes to the way we authorize users with CSRF. If you’re unfamiliar with CSRF, here’s a quick crash course.

What is CSRF?

CSRF (or “cross site request forgery”) ensures that requests made to your server-side are legitimate and originate from your app. That last part is key.

If a user is currently logged in with PayPal, they have session cookies dropped in their browser that are scoped for paypal.com. If that user then visits a site that has been compromised, the site can make requests to paypal.com on the user’s behalf (with the user’s cookies). This could be really dangerous… imagine an attacker adding their bank account to the user’s PayPal account, then transferring the user’s PayPal balance to the attacker’s account. Yikes!

Luckily, this attack is avoidable with CSRF protection.

The most common CSRF pattern is the synchronizer pattern, where a CSRF token is generated server-side, dumped on a page’s first render, and passed back to the server-side on subsequent requests (usually as a hidden form param or AJAX request header). When the token’s validated on subsequent requests, it’s validated against a secret key that hangs off of req.session.

By the way, there’s nothing wrong with this! We open sourced lusca under the krakenjs umbrella. It’s an excellent option for CSRF protection if you’re building an Express app with sessions enabled. But, we’re going stateless.

Okay, so now you’re thinking… how do you provide CSRF protection without a session? You said you went stateless! Enter jsonwebtoken (JWT).

jsonwebtoken

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed.

Since there’s no state on the server-side to compare the token against, we’re going to store our state inside of the token.

Encrypted Sample JWT —

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

Decrypted Sample JWT —

{alg:'HS256',typ:'JWT'}.{time:timestamp,logged_in:true}.signature

When this token is decrypted, it contains a header, payload, and a signature. The most important being the payload and signature.

The payload contains the user’s claims that they are who they say they are. You can define whatever you want inside the payload. But it’s usually a good idea to add a timestamp, some uniquely identifiable information like a user’s account ID, and some indication of if they’re logged in or not. That way, when the token is validated, you can check if the token is expired, check if the user account ID matches, and they’re logged in (Ex: if they’re hitting an API that requires authentication).

The signature verifies that the sender is who they say they are and the message wasn’t tampered along the way. It’s constructed by digitally signing (via a secret) the header, payload, and secret.

If the signature is valid, the payload is legitimate.

Good news! jwt-csrf takes care of generating and verifying JWTs using various CSRF patterns. Here’s how that works.

jwt-csrf

jwt-csrf provides server-side and client-side (optional) code to do all of the heavy lifting of generating/validating JWTs using CSRF patterns.

On the server-side, if you’re using Express, you can use it as middleware. And even if you’re not using Express, it’s available programatically! We baked in 3 strategies for generating and validating tokens. It defaults to the double submit pattern.

On the client-side (optional), we provided some code that patches XHR to send the token along with each request.

If you’re wondering if this is safe to use in production, yes it is! We’ve been serving millions of users every day for over a year now.

Thank you!

Big thanks to Praveen Gorthy, the original author of jwt-csrf!

If you have any questions/issues, please file an issue. Contributions are welcome too; of all kinds! Docs, code, tests, etc. If you’re new to open source, no worries. I’ll help you through it!

Let’s keep the conversation going! — Tweet me @mark_stuart

— Mark Stuart, Lead Engineer/Architect at PayPal

Hack the planet!

Dates Revised for Security-Related Changes

By

We’ve revised some of the dates originally published in the Security-Related Changes Required to Avoid Service Disruption post from earlier this year.

The dates have been revised in order to give merchants additional time to plan for any necessary changes and to give developers additional time to update their integrations.

The dates in the original post reflect the current deadlines. In summary, here are the date revisions:

  • The TLS1.2 Upgrade date moves to June 2017.
  • The HTTPS for IPN Postback date moves to June 2017.
  • The SHA-256 Upgrade dates: Merchants must be compliant by September 30, 2016 as we will begin our permanent upgrade of the remaining endpoints in October 2016. Take action by June 17, 2016 to verify if your system is SHA-256 compliant.
  • The SFTP Server move dates remain the same.
  • The API Authentication Credential Certificate dates remain the same.

Developers should continue to reference the 2017-2018 Merchant Security Roadmap microsite for all the latest details and up-to-date information regarding these security changes.

Adam Colson

Author: Adam Colson

About the author: Adam is a Product Manager at Braintree | PayPal, focusing on the PayPal developer experience since August 2015. When Adam isn’t helping to enable global e-commerce through APIs, he can also be found hacking away at the Internet of Things or tinkering in his garage.

@adamc | LinkedIn

Security-Related Changes Required to Avoid Service Disruption

By

REVISED May 12, 2016Please note that some of the deadlines have changed since this post was originally published. This post reflects the latest deadline dates for security updates.

Beginning in early 2016, PayPal will introduce a number of security-related product updates.

These updates are part of an industry-wide initiative to improve security standards. Some of these updates, like the TLS upgrade, are mandated by the PCI Security Council and are required by every website that transmits or processes cardholder data.

Merchants and developers may have to update their integrations in order to be in compliance and ensure that their applications continue to function as expected.

For PayPal customers, these updates include:

TLS 1.2 Upgrade

The most secure protocol for sharing information on the web today is Transport Layer Security (TLS) version 1.2. PayPal is enabling support for TLS 1.2 for all secure connections and in 2016 will start requiring its use. You will need to verify that your environment supports TLS 1.2 and if necessary make appropriate updates. PayPal is updating its services to require TLS v1.2 for all HTTPS connections in June of 2017. After that time, all TLS v1.0 and TLS v1.1 API connections will be refused.

Learn more

IP Address Update for PayPal SFTP

If your integration is set-up to systematically exchange files with PayPal’s Secure FTP Reporting / Batch Servers, please note that the IP addresses for these servers are changing. If your integration is hardcoded to the current IP addresses, you will need to upgrade accordingly. You must act by April 14, 2016.

Learn more

IPN Verification Postback to HTTPS

If you are using PayPal’s Instant Payment Notification (IPN) service, you will need to ensure that HTTPS is used when posting the message back to PayPal for verification. After June of 2017 HTTP postbacks will no longer be supported.

Learn more

Merchant API Credential Upgrade

The certificates issued by PayPal as API Credentials for use with the Classic API are being upgraded to SHA-256 signed 2048-bit certificates. If you currently connect to PayPal using Certificate API Credentials, you will need to have a new certificate issued and start using it for all API requests. Depending on when your certificate expires, you will have to upgrade between Jan 31, 2016 and Jan 1, 2018.

Learn more

SSL Certificate Upgrade

PayPal is in the process of upgrading the SSL certificates used to secure our web sites and API endpoints. These new certificates will be signed using the SHA-256 algorithm and VeriSign’s 2048-bit G5 Root Certificate. You will need to ensure that your environment supports the use of the SHA-256 signing algorithm and discontinue the use of SSL connections that rely on the VeriSign G2 Root Certificate. This action must be taken by June 17, 2016 in order to avoid any disruption of service.

Learn more

PayPal SDK Updates

For developers using one of PayPal’s SDK libraries, depending on the runtime environment and version your application uses, a code change or SDK update may be required in order to enable TLS v1.2. Java 6 u115 b32, Java 7 or Java 8 (preferred) and Android 4.x environments require TLS v1.2 to be enabled in order to maintain functionality.

If you’re using one of PayPal’s REST SDKs, the best practice is to stay up to date with the latest SDK version and latest versions of the code libraries required by the PayPal SDK. PayPal provides server and client SDKs for Java, .Net, PHP, Python, Ruby, Node.js, Android, and iOS. Detailed test instructions can also be found at https://github.com/paypal/TLS-update.

Developers should reference the 2017-2018 Merchant Security Roadmap microsite for all the latest details and up-to-date information regarding these security changes. You can also visit the PayPal Developer site for more information on PayPal security guidelines and best practices.

Adam Colson

Author: Adam Colson

About the author: Adam is a Product Manager at Braintree | PayPal, focusing on the PayPal developer experience since August 2015. When Adam isn’t helping to enable global e-commerce through APIs, he can also be found hacking away at the Internet of Things or tinkering in his garage.

@adamc | LinkedIn

TLS 1.2 Upgrade Technical White Paper

By

REVISED May 12, 2016Please note that the deadline for the TLS update has been moved out to June 2017

As a leader in Financial Technology, PayPal’s mission is to provide simple, affordable, secure and reliable financial services and digital payments. To accomplish this mission, we constantly evaluate our security posture – which includes complying with industry standards, laws and regulations – to create an environment our merchants and consumers can trust.

Beginning June 2017, PayPal will begin the process of discontinuing support for TLS 1.0 and 1.1, meaning that all communications with PayPal API (including SDK) must use TLS 1.2.

You can read more about PayPal’s official position on mandating the TLS 1.2 upgrade, the rationale for the upgrade as well as resources for merchants and developers to help them through the upgrade process by downloading the Foundation for June 2017 TLS 1.2 Upgrade Technical White Paper.

For information on all the security-related updates that are required this year, visit the 2016-2017 Merchant Security Roadmap Microsite.

Acceptance of FIDO 2.0 Specifications by the W3C accelerates the movement to end passwords

By

What if we could eliminate, or at least significantly mitigate the risk of passwords? On February 17, 2016, the World Wide Web Consortium (W3C) announced that the creation of the Web Authentication Working Group to move the world closer to this goal. The mission of the group is to define a client-side API that provides strong authentication functionality to Web Applications. The group’s technical work will be accelerated by the acceptance of the FIDO 2.0 Web APIs. This specification, whose co- authors include PayPal’s Hubert Le Van Gong and Jeff Hodges, help simplify and improve the security of authentication.  As the steward for the Web platform, the W3C is uniquely positioned to focus the attention of Web infrastructure providers and developers on the shortcomings of passwords and the necessity of their replacement.

The FIDO2.0 protocol employs public key cryptography, relying on users’ devices to generate key pairs during a registration process. The user’s device retains the generated private key and delivers the public key to the service provider. The service provider retains this key, associates it with a user’s account, and when a login request is received, issues a challenge that must be signed by the private key holder as a response.

When challenged, the FIDO implementation stack signals the user to authenticate using the mechanism employed at registration time. This might be via PIN, biometric reader, or an alternative modality. A local comparison of the current authentication request is made to the stored registration value. A successful match unlocks the associated private key; the challenge is signed and returned to the service provider.

This approach dramatically alters the economics of attacks on service providers and their password stores. For each service provider that a user interacts with, a unique private/public key pair is generated. Not only does this ensure that service providers are unable to use protocol artifacts to collude in user-unwanted ways, it renders the public key store of little to no value to fraudsters. Attacks at scale through exfiltration of passwords are no longer a viable means of generating revenue – the ultimate goal of fraudsters.

Early version of the FIDO protocols, UAF and U2F, were developed with deployments by PayPal and others. Much has been learned through the process with the Fido 2.0 specifications designed to bring together the best features of U2F and UAF. With the contribution of the Fido 2.0 APIs to the W3C, they will be sedimented into the Web Platform enabling authoring tools, hosting providers, and others to interoperate will a broad range of devices that will support the Fido 2.0 protocols. 

At PayPal, we are committed to a more secure and privacy-respecting web experience for all internet users. We realize that an easy-to-use, secure, and privacy-respecting means of authentication benefits everyone and having the same protections regardless of the site enhances the overall security of the Web. We look forward to actively participating in the W3C Web Authentication Working Group to continue our pursuit of ubiquitous, simple, secure, and privacy-respecting authentication on the Web.