AWS SSO implements OpenID Connect device code authentication, leaving it vulnerable to device code phishing. This is the form of authentication you’ll encounter when interfacing with AWS SSO from a CLI. An attacker who knows the AWS SSO URL of the victim organization can initiate the flow, and just needs to convince an authenticated user to accept the associated prompt. At this point the attacker can retrieve an SSO access token, valid for 8 hours.
But what if there was a mechanism for an attacker to direct a user to a legitimate login page, resulting in a happy WebAuthn flow, and obtain valid credentials for that user anyway? This seems like the lead-in to someone saying “The Aristocrats”, but unfortunately it’s (a) real, (b) RFC-defined, and (c) implemented in a whole bunch of places that handle sensitive credentials. The villain of this piece is RFC 8628, and while it exists for good reasons it can be used in a whole bunch of ways that have unfortunate security consequences.
A Brief History of Device Code Auth Research
Christophe Tafani-Dereeper published the canonical deep dive on SSO Device Code Authentication Phishing in his June 2021 blog post: Phishing for AWS credentials via AWS SSO device code authentication. I highly recommend reading his post for the core context (and actionable details on protection), before reading the rest of my thoughts!
In November 2022, Matthew Garrett revisited this attack in “Making unphishable 2FA phishable”, where he takes pains to highlight a few possible, more secure alternatives AWS could offer in lieu of the current flow.
What Should AWS Do?
AWS’ implementation is, to the best of my knowledge, RFC-compliant. This post does not contain any vulnerabilities in AWS. However, it seeks to highlight opportunities for increased security on AWS’ side of the shared responsibility model.
The community of AWS Security practitioners has been raising these concerns, both publicly and directly to AWS, for years.
At some point after Christophe’s blog post, AWS changed the Device Authentication Confirmation Prompt - in what appears to be an attempt at better aligning to the RFC’s guideline (“RECOMMENDED to inform the user that they are authorizing a device during the user-interaction step”).
There are a number of other potential hardening measures AWS could pursue. Before enumerating them, it’s important to note that there are likely numerous business, organizational, and technical constraints around this system that I am not privy to. Changing any authentication scheme with this much adoption is always challenging. However, it is still incumbent on AWS to provide customers a secure platform, and AWS SSO’ device code authentication flow is a place where, I feel, they are failing at Job One.
AWS should implement a GuardDuty alert for suspicious AWS SSO authentication. Christophe’s post outlines a detection methodology to “alert when different source IPs generate sso:ListApplications and sso-oidc:CreateToken events within a short time interval.” Offering this detection first-party and out-of-the-box presents opportunities for enhanced, threat informed detection tuning by AWS, and reduces the amount of undifferentiated toil presented to customers who must re-implement this detection themselves. Additionally,
sso-oidc:StartDeviceAuthorizationis not logged to Cloudtrail, as it is unauthenticated, but AWS could potentially leverage that data internally.
AWS should offer an optional mode that implements IP binding, enforcing that the same IP is used for
AWS should allow the creation of a VPC Endpoint (equivalent) for AWS IAM Identity center to allow for control by network of origin. (h/t Renato Nascimento) It is possible to approximate this control through usage of an SCP that denies all actions for SSO roles while not on the VPN. (h/t Arkadiy Tetelman)
All three of these controls should be viable to implement as extensions of the existing feature without any disruption of customer usage.
What Could AWS Do?
AWS could implement SHOULD and RECOMMENDED security controls from the RFC that they are not currently using.
“RECOMMENDED to inform the user that they are authorizing a device during the user-interaction step (see Section 3.3) and to confirm that the device is in their possession”
AWS added an implementation of the first half of this statement, but could abide by the latter half as well.
“The authorization server SHOULD display information about the device so that the user could notice if a software client was attempting to impersonate a hardware device.”
AWS could provide users additional context and transparency on the request - for example IP address information, or the ClientName that is provided during client registration (hypothesized here. Microsoft already updated their device code authentication flow in June 2021 to “[include] a prompt that validates the user is signing into the app they expect”.
“For authorization servers that support the “verification_uri_complete” optimization discussed in Section 3.3.1, it is particularly important to confirm that the device is in the user’s possession, as the user no longer has to type in the code being displayed on the device manually. One suggestion is to display the code during the authorization flow and ask the user to verify that the same code is currently being displayed on the device they are setting up.”
Most clients for Device Code Authentication on AWS support this optimization to reduce user friction. AWS could better prompt users by displaying the code for confirmation.
AWS could allow customers to configure Device Code expiration. Currently, codes expire in 600 seconds. This is a conservative and reasonable security configuration that limits the potential for phishing. However, customers that desire even more resilient postures should be allowed to decrease this, as suits their environment. The RFC is not prescriptive on user code lifetime, allowing for this configurability: “The user code needs to have a long enough lifetime to be useable (allowing the user to retrieve their secondary device, navigate to the verification URI, log in, etc.) but should be sufficiently short to limit the usability of a code obtained for phishing.” Note: Even a short user code lifetime can be bypassed in phishing if an attacker initially directs the victim to a proxy domain that both triggers the flow and redirects the user to the login page.
AWS could undertake a substantial refactor of this flow, as recommended by mjg59, and avoid the current browser authentication UX for the CLI by “having the process listen on localhost, and then have the login flow redirect to localhost (including the token) on successful completion.” They could also implement Proof Key for Code Exchange, which, per oauth.net, “was originally designed to protect the authorization code flow in mobile apps, but its ability to prevent authorization code injection makes it useful for every type of OAuth client, even web apps that use a client secret.” Note: AWS hints at future support for PKCE in their AWS IAM Identity Center OIDC API Reference.
What Can You Do?
Do you think AWS is doing enough to hold up their end of the shared responsibility model? Would you like to see any of these controls added to the AWS SSO device code authentication flow? Let your TAM know!
You can also see the prevention and detection recommendations in AWS Phishing: Four Ways or Christophe’s original blog post.
- Phishing for AWS credentials via AWS SSO device code authentication
- AWS SSO Phishing
- On-device WebAuthn and what makes it hard to do well
- OAuth 2.0 Device Authorization Grant: Section 5
- MITMing AWS IAM Identity Center OIDC Authentication
Thank you to: