Firebase Authentication, Password Reset, Different Domain, Causing Chrome Warning - browser

I am hosting with FireBase and using Firebase Auth with SDK for Flutter. If I induce a password reset email then the user is directed to a slightly different domain than the hosting domain for my app, i.e. <domain>.firebaseapp.com rather than: <domain>.web.app, the user then creates the new password and instinctively (90% of users so far) hit 'yes' to saving the password they just set in chromes database.
Then they go to my app and try to login. This is where the issue comes: Chrome detects the same password is in use as has been saved elsewhere, i.e. it spots a saved password for that different domain. As a result it lights up the usual SSL padlock with a big red "dangerous" and gives a terrifying warning saying that my website is deceptive and has just stolen all the users money and probably their dog.
This is an absolute show-stopper. I tried, thinking that human procedure would get me round this quickly, to warn users not to save their new password at the point of setting it, which spectacularly failed, in tests I tried putting the first sentence of the password reset email as "Please do not save your password immediately after setting it, but only when you are at the point of logging into the app." 4/5 testers didn't notice that sentence, they are all too used to password reset emails and ignored all content and just hit the link, the one person who did read the warning refused to go any further as they'd only read first half of sentence and understood that they weren't allowed to save password at all.
I could start creating a new domain and some cnames, but for a start that might not work - I can imagine some SSL issues doing that, also I'd rather liked the domain firebase made. If I went down the route of creating a password reset page myself, I presume I'd have to have named routes in the flutter navigator to accept a url (currently the app never shows any more detail beyond the # and this was quite deliberate), also I guess I'd need to access the token somehow to verify it etc. I'd really rather just use the built in mechanism, even if there isn't currently an option to redirect the user to my app afterwards they perform the reset.
A slightly tangential subject, but I've never come across the 'dangerous' tag in chrome when using the same password on two sites, until this time - for my app... Is there something specific to my flutter web app or firebase hosting causing this? Perhaps instead of dealing with the flow described above I can somehow eliminate that warning? While the warning seems like a reasonable one (using the same password all over the place is a silly), it strikes me as suspicious that I haven't seen it before until it happened on my app.
Thanks for any help

Related

How should signup form error responses be displayed

I have a subscription based application that is build using MERN. I've recently submitted the application to be security tested and one of the responses that I received was that the application should not specifically tell the user why their signup application has been rejected for all cases. For example, if they enter a username or email that has already been registered, I shouldn't return an error message that says "Sorry, this username is already registered", as this would allow the user to build a list of users and emails that have registered with our site.
I understand why we need to prevent this, but I don't understand how I can tell the user why there signup submission failed without telling them that it's because that email has already been registered. It seems pointless to reject their signup form without giving them a specific reason, does anyone know what the best thing to do here is?
I have a subscription based application that is build using MERN
The fact you're using MongoDB, Express, React and NodeJS is irrelevant to how your end-users and visitors use your product.
I've recently submitted the application to be security tested...
Watch out - most "security consultants" I've come across that offer to do "analysis" just run some commodity scripts and vulnerability scanners against a website and then lightly touch-up the generated reports to make them look hand-written.
one of the responses that I received was that the application should not specifically tell the user why their signup application has been rejected for all cases
Hnnnng - not in "all" cases, yes - but unfortunately usability and security tend to be opposite ends of a seesaw that you need to carefully balance.
If you're a non-expert or otherwise inexperienced, I'd ask your security-consultant for an exhaustive list of those cases where they consider harmful information-disclosure is possible and then you should run that list by your UX team (and your legal team) to have them weigh-in.
I'll add (if not stress) that the web-application security scene is full of security-theatre and cargo-cult-programming practices, and bad and outdated advice sticks around in peoples' heads for too long (e.g. remember how everyone used to insist on changing your password every ~90 days? not anymore: it turns out that due to human-factors reasons that changing passwords frequently is often less secure).
For example, if they enter a username or email that has already been registered, I shouldn't return an error message that says "Sorry, this username is already registered", as this would allow the user to build a list of users and emails that have registered with our site.
Before considering any specific scenarios, first consider the nature of your web-application and your threat-model and ask yourself if the damage to the end user-experience is justified by the security gains, or even if there's any actual security gained at all.
For example, and using that issue specifically (i.e. not informing users on the registration page if a username and/or e-mail address is already in-use), I'd argue that for a public Internet website with a general-audience that usernames (i.e. login-names, screen-names, etc) are not particularly sensitive, and they're usually mutable, so there is no real end-user harm by disclosing if a username is already taken or not.
...but the existence or details of an e-mail address in your user-accounts database generally should not be disclosed to unauthenticated visitors. However, I don't think this is really possible to hide from visitors: if someone completes your registration form with completely valid data (excepting an already-in-use e-mail address) and the website rejects the registration attempt with a vague or completely useless error message then a novice user is going to be frustrated and give-up (and think your website is just broken), while a malicious user (with even a basic knowledge of how web-applications work) is going to instantly know it's because the e-mail address is in-use because it will work when they submit a different e-mail address - ergo: you haven't actually gained any security benefit while simultaneously losing business because your registration process is made painfully difficult.
However, consider alternative approaches:
One possible alternative approach for this problem specifically is to make it appear that the registration was successful, but to not let the malicious user in until they verify the e-mail address via emailed link (which they won't be able to do if it isn't their address), and if it is just a novice-user who is already registered and didn't realise it then just send them an email reminding them of that fact. This approach might be preferable on a social-media site where it's important to not disclose anything relating to any other users' PII - but this approach probably wouldn't be appropriate for a line-of-business system.
Another alternative approach: don't have your own registration system: just use OIDC and let users authenticate and register via Google, Facebook, Apple, etc. This also saves your users from having to remember another password.
As for the risk of information-harvesting: I appreciate that bots that brute-force large amounts of form-submissions sounds like a good match for never revealing information, a better solution is to just add a CAPTCHA and to rate-limit clients (both by limiting total requests-per-hour as well as adding artificial delays to user registration processing (e.g. humans generally don't care if a registration form POST takes 500ms or 1500ms, but that 1000ms difference will drastically affect bots.
In all my time building web-applications, I've never encountered any serious attempts at information-harvesting via automated registration form or login form submissions: it's always just marketing spam, and adding a CAPTCHA (even without rate-limiting) was all that was needed to put an end to that.
(The "non-serious" attempts at information-harvesting that I have seen were things like non-technical human-users manually "brute-forcing" themselves by typing through their keyboard: they all give-up after a few dozen attempts).
I understand why we need to prevent this, but I don't understand how I can tell the user why there signup submission failed without telling them that it's because that email has already been registered. It seems pointless to reject their signup form without giving them a specific reason, does anyone know what the best thing to do here is?
I'm getting the feeling maybe you got scammed by your security "consultants" making-up overstated risks in their report to you - rather than your web-application actually being at risk of being exploited.

Node.js brute force prevention

I have a MERN stack project running on Heroku, today someone has started to flood my server with many login requests (brute force). Every request has a different IP address so I cannot block the IP. This has caused a website outage.
How can I block it then? How can I allow login only using my website?
A typical solution you will see used by many login pages is one of several techniques that require human-like interaction and are hard for scripts to duplicate.
You have, for sure, seen the captcha systems that ask the user to interpret some image that is not easy or practical for computers to analyze.
There is also a no-captcha system that asks the user to click a particular spot on the screen with the mouse and it analyzes the movement to see if it appears human-like. These are often shown as a click on "I'm not a robot".
Many sites (like some U.S. airlines and a number of financial sites) now require the user to set up "challenge" questions (like: "Where were you born?" or "What's your favorite ice cream flavor?") and if a login request arrives without a previous placed signed cookie for this user (or other familiar browser detection metrics), then the challenge question is required before you can even attempt a login.
A more draconian approach (that could have more of an impact on the end-user) is to keep track of failed login attempts per account and after a certain number, you start slowing down the responses (this slows down the attackers systems) and after some higher number of failed responses, you immediately fail every request and require the end-user to confirm their login request via an email message sent to their registered email address. This is an inconvenience for the end-user, but prevents more than N guesses on any individual account without end-user confirmation. After some period of time, you can clear the prior login attempt numbers for any given account, freeing it up to work normally again.

Delphi & Twebbrowser - How to recover a security token supplied by a login page?

I am using the Twebbrowser in Delphi (2009) to log into cpanel on my ISP and add a new remote host IP address for a MySQL database. The user name and password are filled in by code as is clicking the submit button, using code gleaned from several places here.
Navigating directly to the hosts page causes the cpanel login page to be shown first. My program detects this and logs me in.
This uses a line like
WebBrowser1.Navigate'https://thedomain.sgcpanel.com:2083/cpsess1819495779/frontend/Crystal/sql/managehost.html');
which reaches the hosts page OK but I notice that the security token (cpsess1819495779) is changed to something else each time, presumably being supplied by the login page.
However if I try to login first as a separate operation and then navigate to the hosts page using
WebBrowser1.Navigate('https://thedomain.sgcpanel.com:2083');
followed by
WebBrowser1.Navigate'https://thedomain.sgcpanel.com:2083/cpsess1819495779/frontend/Crystal/sql/managehost.html');
I get a server message saying the url for the hosts page has an invalid security token - presumably the cpsess1819495779 bit
Question
How can I use Twebbrowser to get hold of the security token generated by the login page in order to use it to build the correct url for the hosts page so that I pass the correct security token each time.
It's probably something to do with cookies etc but I don't know how to deal with those (yet)
BTW as the Twebbrowser is not visible I did spend quite a few days trying to do the same thing using Indy's TIdHTTP but have given up with that as am getting too many errors I can't sort out.
I may as well answer this myself to close the question and maybe avoid any more down votes for posting a question after extensive research failed to produce the answer and that was framed without much of my code for brevity.
The API documentation for cpanel (the application used by many ISPs to manage MySQL, email etc) is here: https://documentation.cpanel.net/display/SDK/Guide+to+cPanel+API+2
part of that says
Security token After you log in to your server, it automatically appends a security token to the URL for your session. Security tokens
help prevent authorized use of a website through XSRF (Cross-Site
Request Forgery). Security tokens contain the string cpsess and a
10-digit number.
Logging in manually in IE / Chrome etc. does indeed show the token eg cpsess1819495779 inserted into the original url that was navigated to. So if I navigate to
https://thedomain.sgcpanel.com:2083/cpsess0000000000/frontend/Crystal/sql/managehost.html
(to logon to cpanel), the part of the url displayed in the browser after cpsess gets changed to something like this, where the number changes each time.
https://secureukm11.sgcpanel.com:2083/cpsess1819495779/frontend/Crystal/sql/managehost.html
However, using Twebbrowser to show that modified url using
memo1.Lines.Add(WebBrowser1.LocationURL);
or
ShowMessage('URL: ' + Webbrowser1.OleObject.Document.Url);
simply shows the original url with the zeros, not the real security token.
So the answer to my question seems to be it can't be done in Twebbrowser as the url is only changed at the server and and the security token is not transmitted back to the browser.

Best practices for passwords on registration?

I have a website which users register an account. On the registration field, the form fields are:
Name
Email
Confirm email
Username
But there is no password field. When they hit submit, they are emailed a password which is very complex, such as LHJVjhwnv%uu5 or RbWM9!jeDZUQb.
I have appealed to my developer to instead make it so that the users can set their own password on the registration form. To confirm that password on the form, and then be sent a confirmation link to their specified email. Then this way they can at least log in to their account and verify their email via confirmation link. Or if they didn't, every time they log into the site it could remind them to verify their email etc or else they can't do much on the site (example). This way even if they don't get the confirmation link, they can still update their account email to a different email and have it resent. At least at this stage, they can log into their account, instead of not at all.
The response I have received from the developer is as follows
"The problem with providing the password on registration is that
you'll have loads of fake accounts. So people that just register with
a non-existent email address. At least with the email validation
you're proving the user exists, to a certain extent. If they register with the wrong email, they can just re-register."
I'd like to ask you all if the current approach the developer has employed is acceptable?
If not, what are some good reasons I could use to convince the developer to change?"
I've tried to explain the following
Every day there are 9-10 people who register and then directly use the "password reset" form right after. This form involves them putting in their email address that they signed up with, and then it emails them a link to SET a new password. So if they are setting a new password anyway, why not just have them set it in the first place on the registration form? Why would there be 9-10 people every single day using the password reset field, directly after registration? I'm pretty sure its because they are seemingly struggling with these complex passwords (which I am not against) that are being emailed to them and are missing a key or character, or do not seem to be aware of copy/paste or something like that. If they could just set their own password the first time around, they wouldn't need to run to the password reset field right after because of their emailed password not working. I thought it was weird how everyday theres always password reset emails. Not for everyone, but a good 9-10 people a day ever since I started using Mandrillapp to track the outgoing emails. This is backed up by the next point.
Every day there are at least 2-3 people who fill out the contact form indicating that the password they received is not working. Could all be avoided if they just could set it on their own. There may be even more that just don't bother contacting.
Out of nearly 8000 accounts, 50% have never logged in. My strong suspicion is that the Registration email containing their password goes to their junk folder/spam folder. This is despite me having proper SPF, DKIM, etc setup. 2 months ago, I decided to start using Mandrill to send mail to ensure it goes to the inbox, but still there's at least 1-2 people/day that say that they did not get their email.. which perplexes me. If they could define their own password, they wouldn't have to worry about waiting for their password via email, or not getting it entirely. This just further highlights my initial concern.
Thank you for your time!
I assume you already have a working password-reset page in place, so you can use just the same code to do the registration:
Let the user register with his email.
Send a link with a token to the user, a hash of the token is stored in the database.
If the user clicks the link and if the token is valid, welcome him and let him enter his own password.
This is exactly what you already have for password resetting, your site becomes no more (un)secure because an attacker could as well use the password reset function.
Of course weak passwords are a problem, so rejecting weak passwords is a must. Again this is the same you would have to do on the password-reset page. For password-resets you wouldn't send plaintext passwords neither.
Unconfirmed accounts can be deleted after a certain period, it means the user didn't do anything with it. If necessary the user can register again. This only works if the user is not allowed to login before doing the confirmation, what supports the procedure above. Of course it depends on the website if this confirmation is that important though.
The main reason not to send passwords in a mail is security: Mail isn't a secure medium. If you put a password in there, then many people can see it - consider allowing people to use your service without any kind of password instead to understand what I mean.
The main drawback of allowing people to chose their own password is that 95% will use 123456 or password.
Most big sites use this approach to balance security, business needs and comfort:
Allow user to set their own password. Reject the most simple ones (there are libraries for this). Note: Complex password rules drive customers away.
Send a confirmation link via mail.
Don't allow login until the link has been clicked.
If they try to login anyway, tell them that they have to click the link first plus provide a "send confirmation link again" link in case the first mail was lost.
I have appealed to my developer to instead make it so that the users can set their own password on the registration form....
This opens you up to a plethora of weak password and reuse attacks. Reuse has been empirically studied and reported between 50% and 76%. Other academic studies have stated nearly all users (almost 100%) reuse passwords.
So assigning passwords helps with major practical problems. After you assign the password, then you are subject to the same attack, though because a user may reuse the assigned password on another site.
...
I'd like to ask you all if the current approach the developer has employed is acceptable?
Yes, its acceptable as long as the password meets security requirements. I even prefer it, especially when user selected passwords are not checked against bad password lists.
Bad password lists are important because we know attackers use them. There are literally millions of passwords on them because of all the past breaches (did I mention password reuse is a pandemic problem?). The lists are easy to find, and one researcher recently released his list of 6,000,000+. See How I Collect Passwords.
Aaron is correct about email and plain text. You can actually place another security control to limit the exposure. Namely, require that your mail server use SSL/TLS or fail the connection.
Or, generate the password and display it to the user on the screen. Instruct the user to print the password so they don't forget it. I even tell my users to write them down and keep them in their wallet or purse.
The primary threat is a network based attacker attempting to gain unauthorized access to the server through weak/wounded/bad passwords. So an out-of-band/out-of-channel email is not too great a concern. And a lost wallet or purse is not too great a concern. The concern is the network based attacker guessing passwords or using {username,passwords} tuples from breaches of other sites.
Every day there are 9-10 people who register and then directly use the "password reset" form right after. This form involves them putting in their email address that they signed up with, and then it emails them a link to SET a new password.
OK, that's a security defect since the user can circumvent the security control.
For what its worth, I regularly use a random password generator to generate passwords for accounts. I don't even bother writing them down. When I need to access the account, I simply go through the Lost Password process.
That's how low value these things are to me. Every damn site wants a user to manage an account and password. I'm tired of expending the energy to manage all the accounts, so I don't even waste the cycles on it.
The problem with providing the password on registration is that you'll have loads of fake accounts. So people that just register with a non-existent email address. At least with the email validation you're proving the user exists, to a certain extent. If they register with the wrong email, they can just re-register
OK, so this is a different problem. BOT registrations are usually mitigated with a CAPTCHA. I've never really studied what to use for Real Users/Fake Accounts.
What is the benefit of a fake account? It seems to me the user is trying to get half pregnant. They either have an account, or they don't have an account.
Out of nearly 8000 accounts, 50% have never logged in. My strong suspicion is that the Registration email containing their password goes to their junk folder/spam folder. This is despite me having proper SPF, DKIM, etc setup.
Well, that's a different problem (that you should confirm through testing). This speaks to displaying the password for the user and telling them print the page.
There's a lot more to the subject of password management. You should read Chapter 7 of Peter Gutmann's Engineering Security.
I have appealed to my developer...
Finally, you are the boss. Fire the developer or contractor if they are not following instructions or coding against requirements. I'd be damned before I begged someone who I was paying for services.
Programmers are a dime a dozen, and you can find plenty of them at places like Rent-A-Coder. The Indians and Pakistanis work for next to nothing (under $10 USD per day in some cases). I don't know how they can work for so little and survive...

block the browser instance after invalid login attempts

We have security requirement for web application. We need to block the browser instance (includes all tabs) after 3 invalid login attempts. It should be irrespective of user ids.
For example, I open a browser instance and use three different users to login and all fails and the moment i try fourth attempt, it should error on login page saying close the browser instance and try on new instance.
My question is how to identify the browser instance at server side. What are the strategies?
One option is using session id using cookie. But, I would like to make it work even if Users clears cookie in between attempts.
Any other ideas?
Anything you try to do browser side is practically pointless. It won't stop a single malicious user, and will only frustrate your clueless users who forgot their passwords and are trying everything they can think of.
The best way to handle something like this is to "stand on the shoulders of giants" so to speak. How are the big names like Google/Facebook handling this? If your focus is purely on security, and don't really care about user experience, then this won't be your ideal answer. If, however, you have to balance between the two, this is how I'd do it.
Look at what Google does. You get a few attempts per user AND per IP address (you'll need to start recording this if you aren't already). After a few failed attempts, you show them a CAPTCHA. If they keep trying, you are no longer dealing with a bot, and you can adjust accordingly. You have to deal with this by account and IP because malicious users will just change their IP to keep hammering on one account, so you need to be able to handle both cases.
Try to help the user by showing them how (hopefully) easy it is to use the "forgot your password" feature. Maybe if you see enough username attempts from the same IP, you can escalate this to a "lock out" mode. But be careful, malicious users can use many IP addresses, and sometimes regular users all connect through one IP. Also make sure they can't lock out your (admin) account (or everyone in your DB).

Resources