aws-amplify / amplify-js

A declarative JavaScript library for application development using cloud services.
https://docs.amplify.aws/lib/q/platform/js
Apache License 2.0
9.41k stars 2.11k forks source link

You can confirm emails you don't own if multifactor is turned on in Cognito #2102

Open bionicles opened 5 years ago

bionicles commented 5 years ago

Describe the bug if multifactor is turned on in cognito then you can confirm any email address with just your phone

To Reproduce Steps to reproduce the behavior:

  1. Make a user pool with multifactor turned on
  2. use Auth.signUp with the target email and your own phone number
  3. enter the code sent to your phone
  4. congrats, you just "confirmed" any email address in your cognito user pool

Expected behavior This vulnerability/exploit is possible because the signUp and confirmSignUp function only requires the SMS code and not the email code to confirm the user.

To fix the vulnerability, signUp must send email and phone codes simultaneously and confirmSignUp must simultaneously verify them.

  1. Auth.signUp(userDataObject)
  2. Auth.confirmSignUp(emailCode, phoneCode)

Screenshots This screenshot shows Jeff Bezos Email Confirmed on the bitpharma.com Cognito User Pool - we did this entirely using AWS amplify Auth and not through AWS console jeff-bezos-confirmed-bitpharma

Desktop (please complete the following information):

Additional context This issue prevents us from launching our web platform with a clear conscience because it prevents us from trusting the integrity of the AWS Amplify Cognito Auth system, which also means we can't use AWS AppSync.

That means we can't use the awesome Serverless GraphQL Graph Database we built. We reported the issue to jeff@amazon.com directly 64+ days ago and have opened 2 github issues, contributed code to fix the problem, exchanged emails, phone call, and DMs with AWS Cognito team (raja) and now we're forced to scrap thousands and thousands of dollars worth of engineering and STILL have to rebuild a new solution. UGH! PLEASE FIX!

This issue was closed: https://github.com/aws-amplify/amplify-js/issues/1959

This issue was ignored: https://github.com/aws-amplify/amplify-js/issues/1685

We tweeted Andy Jassy about this: https://twitter.com/ajassy/status/1062130529963655169

We tweeted Jeff Bezos about this: https://twitter.com/bitpharma/status/1062368063478288384

Today we used it to sign up Jeff Bezos' email with bitpharma.com user pool. Still no word from anyone... I'm pissed because this is a critical cybersecurity vulnerability and no one at AWS seems to care! This could cause serious headaches if not patched ASAP because hackers can exploit this vulnerability to clog any cognito user pool by registering many many emails they do not own...

@yuntuowang @nidsharm @mlabieniec @powerful23 @mbahar @richardzcode @elorzafe @jordanranz @manueliglesias

This library is too important to leave unsecured. Are you too busy to patch this vulnerability in the cybersecurity of the first step of signup in AWS Amplify Cognito Auth?

bionicles commented 5 years ago

sent this email today to google cloud platform and amazon web services:

Dear GCP/AWS,

If this issue we care about also exists on Google Cloud Platform then I don’t see how we justify the hassle of switching bitpharma.com from AWS when we need to pitch investors

I’m building an express server for this, but I shouldn’t have to. I’m an Immunologist working alone on this and GCP/AWS teams are software experts for many years

Yes, you’re right, we can block accounts w/ unverified emails from accessing resources, but burner numbers are easy to get. I get ROBO DIALS multiple times per week. Likewise it’s easy to get fake emails. If we inspect both phone number and email address and the relation between them before sending codes then we can filter out a lot of noise.

We want to simultaneously verify phone and email for many reasons:

  1. to simultaneously check the integrity of phone and email before spending $$$ to send verification codes

  2. to dramatically simplify customers’ UX because if we simultaneously verify phone and email then users only fill out one verification form instead of two forms (this was what got me interested)

  3. To reduce the number of trusted lines of code in our cybersecurity stack

Do you think fewer forms, faster/better/easier on-boarding (lower bounce rate), less trusted codebase, simpler UX, and stronger “borders” are worth a few day’s work?

Here’s some code to solve the problem:

Client: Lib.signUp(userData) Lib.confirmSignUp(emailCode, phoneCode)

Server: const signup = (req, res) => { // do email and phone already exist in DB? const db_email = db.search(req.email)[0]; const db_phone = db.search(req.phone)[0]; // run other security checks on phone and email if (db_email === undefined && db_phone === undefined){ // make and send email code const emailCode = makeCode() sendEmailCode(emailCode, req.email); // make and send phone code const phoneCode = makeCode() sendPhoneCode(phoneCode, req.phone); } };
const confirmsignup = (req, res) => { if (req.emailCode === emailCode && req.phoneCode === phoneCode){ // success -- do stuff } else { // fail } }

Just imagine a DDOS which signs up for your site with fake numbers or emails. Do you expect customers to pay to send billions of needless texts and emails?

If we look at both before we send codes then we save millions of dollars AND increase probability users will sign up, because nobody likes forms. And people use your forms many many times every day. Just multiply the hassle of an extra form across all the users on all the platforms hosted on GCP and AWS — that is literally years of people’s lives wasted just so we can dodge writing some simple code.

How do you justify that?

can you please just get your engineers to simplify + secure sign-up?

If I’m wrong here then please tell me and explain your reasoning...

BAH

adrianhall commented 5 years ago

@bionicles,

As you know, we (AWS) have reviewed your GitHub issues (#1685, #1959, and #2102), replied multiple times, and spoke with you on the phone. Just to summarize:

We understand that you “expect the system to send verification to both the user's phone and email” during signup. However, as we state in our documentation, this is not yet a feature Cognito supports:

Important If a user signs up with both a phone number and an email address, and your user pool settings require verification of both attributes, a verification code is sent via SMS to the phone. The email address is not verified, so your app needs to call GetUser to see if an email address is awaiting verification. If it is, the app should call GetUserAttributeVerificationCode to initiate the email verification flow and then submit the verification code by calling VerifyUserAttribute.

While most customers' use cases have been satisfied with the ability to verify either by phone number OR email address, we understand that your particular application has the requirement to verify both phone number AND email address. We've therefore provided you instructions on how your application can verify both the user's phone and email in the Cognito Developer Guide and GitHub issue #1959. As we’ve also shared, we’re happy to help you implement this in your app.

We understand that you’d prefer the service offer the feature above more easily, but this is not a security issue in the service as it’s working as documented. Your screenshot in issue #2102 does not demonstrate a security vulnerability. In your example, the user shows confirmed. A viewer might incorrectly assume that the jeff@ email address was used to confirm the user, however if you click on the username you can view the user details page where we clearly show that jeff@ email address itself is not verified. The user was confirmed via phone, matching the Cognito documentation. We do appreciate your feedback, and agree that we could probably make the UI clearer. We will move quickly on trying to make those tweaks. We will also explore your feature request of verifying users by both email and phone number for our longer-term roadmap, however, we understand if Cognito does not yet meet your immediate needs for this project.

Thank you for sharing your feedback,

(Posted on behalf of...) Saroj Thatte GM, Amazon Cognito

bionicles commented 5 years ago

we'll use email only for now and avoid multifactor. it does seem like a security + UX issue and a priority. thanks for the reply

bionicles commented 5 years ago

@adrianhall

https://en.wikipedia.org/wiki/Vulnerability_(computing) A resource (either physical or logical) may have one or more vulnerabilities that can be exploited by a threat agent in a threat action. The result can potentially compromise the confidentiality, integrity or availability of resources (not necessarily the vulnerable one) belonging to an organization and/or other parties involved (customers, suppliers).

confidentiality is a set of rules that limits access to information, integrity is the assurance that the information is trustworthy and accurate availability is a guarantee of reliable access to the information by authorized people

Yes you’re right, information could be kept confidential in this case, BUT...

How do you possibly argue “CONFIRMED” in huge letters next to jeff@amazon.com on something he did not sign up for is at all “trustworthy and accurate?”

How do you possibly argue that it’s “guaranteed reliable access” when literally anyone can put any email is already in use and then the actual owner of the email account can’t sign up?

bionicles commented 5 years ago

Tired of games. Just sent the following email to Adrian Hall and Saroj Thatte and Jeff Bezos:

I dont know how long I have to be relentless about this cognito multifactor vulnerability until someone fixes it but, here goes...

https://github.com/aws-amplify/amplify-js/issues/2102 https://en.wikipedia.org/wiki/Vulnerability_(computing)

I already demonstrated the integrity issue by signing up Jeff's email with my phone number

Since Adrian Hall and Saroj Thatte treat this vulnerability like a "feature request" ("your screenshot in issue #2102 does not demonstrate a security vulnerability"), I did another experiment.

I pretended to be Jeff and signed up again with a different number. Jeff can't sign up for our user pool now because his email is in use. Do you think this is working as intended?

availability-test-fail-screenshot from 2018-11-17 16-15-22

this is definitely a major open security vulnerability in AWS cognito multifactor because it is a technical problem which allows threat actors to attack integrity and availability of the cognito user pool by signing up email accounts that are not theirs, but Adrian and Saroj argue it isn't a security vulnerability and act like they're in no rush to deal with it.

This issue prevented our medical research startup from trusting multifactor authentication for over 2 months. This isn't a "feature request" because the cognito FAQ clearly states the service already does multi factor authentication and customers need multifactor for HIPAA compliance but cognito multifactor doesn't work properly.

https://aws.amazon.com/cognito/faqs/ https://www.hipaajournal.com/hipaa-password-requirements/ https://www.hhs.gov/sites/default/files/ocr/privacy/hipaa/administrative/securityrule/remoteuse.pdf?language=es

"we could probably make the UI clearer" "we will explore your feature request for our long term road map"

These are excuses. There's no excuse for this.

How is the fact we can confirm any email in our user pool, and deny the email account owner access, a "LONG TERM ROAD MAP" feature request and not a security vulnerability?

I've worked on a tiny medical research startup for over a year without funding or pay because I love LIFE and I want to help others.

AWS Cognito teams' laziness and delays prevent us from doing a great job. Now I'm so tired of contacting AWS Cognito Team to get help with my startup, with no action or response, it makes me sick.

How do you feel about that?

Bion Howard, Founder & CEO, bitpharma.com medium.com/bit-pharma

bionicles commented 5 years ago

cognito-supposedly-hipaa-compliant-screenshot from 2018-11-17 16-35-08

bionicles commented 5 years ago

hipaa-requires-2factor-screenshot from 2018-11-17 16-52-22

bionicles commented 5 years ago

https://en.wikipedia.org/wiki/Health_Information_Technology_for_Economic_and_Clinical_Health_Act https://en.wikipedia.org/wiki/Health_Insurance_Portability_and_Accountability_Act https://en.wikipedia.org/wiki/False_advertising ?

ArmorDarks commented 5 years ago

I'm surprised how incompetent AWS team showing off itself in this issue. Shame.

bionicles commented 5 years ago

I forgive AWS for this delay because I didn’t realize the severity of the issue myself either. Azure and GCP also verify these fields independently.

Only noticed this because I’m a perfectionist building a startup and want to use fewer forms, but now I realize it’s deeper than UX.

Don’t worry, the good news is, we found it, and when we fix it, the system will be even more secure. It’s better we found it when the stakes weren’t so high than to find it later by hackers using it maliciously.

It’s probably possible to fix fast and easily but I’m not certain, can you please take a fresh look?

Bion Howard (a biologist) medium.com/bit-pharma bitpharma.com

janaz commented 5 years ago

The "CONFIRMED" status means that the account itself is confirmed. It's one of the states the account can be in. This should not be confused with email or phone number verification. I understand that it may be misleading from the UX point of view, because the status appears next to the email address in the UI.

There are special attributes in the user pool record that track the verification process for the attributes.

If the user verified their email, then email_verified is set to true. If the user verified their phone number, then the phone_number_verified is set to true.

I don't think that the jeff@amazon.com account in your user pool has the email_verified attribute set to true.

bionicles commented 5 years ago

1, More Forms, (not so bad, just crappy UX)

  1. Confirm Accounts with Any Email, (not so bad, sure)

  2. Deny Accounts with Any Email <----- critical issue

bionicles commented 5 years ago

@elorzafe @adrianhall Here's some code to fix this issue (from above)

Client: Auth.signUp(userData) Auth.confirmSignUp(emailCode, phoneCode)

Server: const signup = (req, res) => { // do email and phone already exist in DB? const db_email = db.search(req.email)[0]; const db_phone = db.search(req.phone)[0]; // run other security checks on phone and email if (db_email === undefined && db_phone === undefined){ // make and send email code const emailCode = makeCode() sendEmailCode(emailCode, req.email); // make and send phone code const phoneCode = makeCode() sendPhoneCode(phoneCode, req.phone); } };

const confirmsignup = (req, res) => { if (req.emailCode === emailCode && req.phoneCode === phoneCode){ // success -- do stuff } else { // fail } }

How do you make the codes available to both the user and to the confirm script?

It would really be awesome to be able to make medical apps on Amplify / Cognito! We wanted to use Firebase but they are not HIPAA compliant and their sales never got back to us on that, so we're depending on AWS to make this secure for medical records applications ... Can you help us out with this fix / request?

undefobj commented 5 years ago

Hello @bionicles

Per the note above the ability to deny login until both the email AND phone number have been confirmed isn’t currently supported by Cognito but they have taken it as a feature request. However if you would still like to use Cognito as part of your overall solution to provide this functionality, we brainstormed on this a bit internally and have the suggested example flow below:

  1. Using a Preauthentication Trigger, configure it to check that the email and phone number of a user is in the VERIFIED state otherwise fail and deny the login attempt
  2. Have the user perform Sign-Up with email and phone number as normal against User Pools
  3. The user will receive an SMS code as normal and can perform the confirmation step
  4. Create an API Gateway endpoint (/verifyEmail) which takes the user email address as a parameter and invokes a Lambda function. This Lambda function generates a code and stores it as an attribute of that user’s profile in User Pools using AdminUpdateUserAttributes. The function then calls SES to verify the email address by emailing the user sending this code along in the email.
  5. When the user clicks the email, it sends a response to an API Gateway endpoint (/confirmEmail) with the email and code generated in the previous step, which runs a Lambda function. This Lambda uses AdminGetUser to compare the code passed in with the code stored in the profile and if they match, it clears out the code and sets email_verified = true using AdminUpdateUserAttributes.
    • The email could be a clickable hyperlink which is the URI to the /confirmEmail endpoint with email and code as query parameters
  6. Now that both the phone and email are in a verified state, the Preauthentication Trigger will pass and the user can login as normal.

Solution-Diagram

As this is a suggestion of one way to accomplish your use case, and not an official built-in product feature, please let us know if you have any further questions.

bionicles commented 5 years ago

@undefobj Thanks, considering this...

Ever get robo dialed? I do, a lot.

Even comes from my own telephone number sometimes. Clearly, it is easy for anyone to generate phone numbers these days. Email lists are also available. What stops some jerk from going to any Cognito multifactor service and signing up every email in a huge list? If that's some insurance company, or hospital, then all of those customers are screwed, they can't access their health records, because their email already exists in the user pool. That breaks the HIPAA law because portability / patient access is critical to patients owning their records!

I don't think this proposal solves either the availability threat issue or the additional form issue.

This proposal doesn't resolve the availability threat because we still add the email to the user pool based only on a phone number.

This proposal also still requires every single user to deal with an extra form (1. signup 2. confirm phone, 3. confirm email) for the user when the intended UX is to have 1. signup 2. confirm forms; then 1. login, 2. confirm for returns.

How does cognito team intend to deal with robo-signups risk? That's the whole point of this github issue. Captcha was defeated by neural nets 6 years ago ... you can obfuscate your IP address... I'm just not sure why it takes a year to add this feature to Cognito. Do we have to wait around for somebody to exploit this in order to get AWS to fix it?

I don't want to deal with cognito hole where scripts can sign up many many emails to our service. I also don't want every user to have to fill out 2 forms when they could theoretically figure out 1. I just want to click "enable simultaneous multifactor" in the Cognito console, and be done.

It's not right for AWS to force customers to jump through hoops to solve this issue. That's tons of extra work for many different groups, when cognito team could fix it on the service side so people. I really appreciate you taking the time to brainstorm, but an idea is not a tested fix.

If 100 customers have to implement this idea over and over and over for AWS, vs AWS just implementing it in the cognito API once, that's 100x more work for the AWS community.

Wouldn't it just be easier to add the feature than to keep endlessly discussing, brainstorming, emailing, chatting, delaying, waiting, passing the buck, getting distracted with other stuff?

undefobj commented 5 years ago

If the approach detailed above does not meet your needs, Amazon Cognito as it is today is not a good fit for your specific requirements. The Cognito team has been briefed on your requirements and based on customer demand for similar functionality and competing feature requests will consider it for future roadmap..

bionicles commented 5 years ago

@undefobj It’s a bug, not a feature.

HIPAA compliance eligibility is already advertised as a production feature of cognito, this vulnerability prevents the Cognito system from being highly available in that setting. All we need is a list of public emails and a way to get burner phone numbers and we can prevent anyone from using Cognito multifactor. How is the fix for that a “feature?”

mcqj commented 5 years ago

I have to agree with @bionicles. This is a serious bug, not a feature request.

It's not necessarily a security hole as its not allowing one person access to another's account. But being able to block a user from signing up is a huge flaw.

We've been using Cognito without ever having identified this issue. We'll now disable multi-factor signup in all of our applications and notify all of our customers accordingly. I've been guilty of consuming the koolaid of AWS knowing and caring more about security than us mere mortals.

What's much more worrying than the flaw itself, is the determination to defend the system and not acknowledge that it is a serious issue. Time to re-evaluate the degree to which we should embrace the infrastructure as a service model.

bionicles commented 4 years ago

look, i get you have megacorporation issues and maybe can't open source cognito (and I disagree) however, huge numbers of corporations, governement organizations and people depend on Cognito Multifactor, by law, because HIPAA (and common sense) demands multifactor authentication, but this 1 little piece of AWS has been broken / screwed up for years. 

you need it for hipaa compliance. you need cognito to use appsync which is the best API on AWS, you need it for 50 billion reasons. but right now if healthcare.gov or pentagon.mil uses AWS and has MFA turned on (they should) then any 8 year old with a working cellphone can deny any user access, let alone state-funded hackers who can automate exploits

Am I too perfectionist to expect people to actually own the emails they confirm in my AWS auth service?

Do you think it would be possible for you to figure out how we can get working MFA on AWS? I just circled back to web dev after doing AI for some time, and ran right back into this same stupid issue which I told you about in the summer of 2018. That's like, 18 months that huge corporations have had a huge vulnerability because some manager with no github account thinks this is a feature request. 

why do you expect huge organizations to trust their cybersecurity to closed-source code they can't double-check, lead by a manager who doesn't have a github account? 

it's totally out of character for amazon. honestly makes Amazon look like lazy, slack-ass hucksters. gee, medical records depend on one of my services? guess i'll hide the code and not update it for YEARS!

just imagine you trust the keys to the door to your house to an invisible security guard who doesn't move. does that sound like a good idea? i think not, but that's what every person relying on AWS cognito does every day

AWS has 1234567890 services i dont need, and the core stuff I actually do need, does not work, I can't see the code, and I can't make pull requests

WTF are you thinking? TWO PIZZAS? PIZZA ISNT EVEN HEALTHY! Frustrated, BAH

loelindstrom commented 4 months ago

@bionicles @adrianhall Hey! Ended up here when I was googling security in cognito.

Just curious how it all ended? What's the state now 5 years later? (Might perhaps be good for others to know as well who end up in this thread through google.)

bionicles commented 4 months ago

Ah, I don't know if it's fixed, I stopped using AWS. A friend was able to make a demo app with Cognito relatively recently, it's doable, I just think it's sketchy in general to avoid simultaneous multifactor auth, maybe i'll make a saas for that, right now i'm sucked into details of the postgresql wire protocol but maybe next month