2

What I'm trying to build

  • REST-API using Express and SQLite
  • 5 to 10 authors should be able to post articles to /articles
  • except them, no one is allowed to post anything

My approach to build it

  • authors are stored in the database
  • password matched with regex and hashed with salt
  • provide a login route for authors to login
  • after login, a JWT is sent to the author

I have built APIs like that a couple of times for school, but never in production.

I am really worried if this approach may isn't safe. I thought about using Auth0 or some other IdaaS-providers, but I'd rather do it by myself, especially because I am not sure if I the free plans of these providers cover all features I need.

To conclude, what are the security risks of builing the authentication by yourself? Can I make my approach more secure? Are there better "workflows" to implement a form of authentication for my problem?

3
  • I am having the same problem and would recommend you to use open source software that is already built for this. I know auth0, aws and other solutions are bit pricey as they count by number of users, and hence i was looking for the same. Have you looked at passport js ? Nodejs Passport Commented Jan 28, 2021 at 21:27
  • Yep, if I build it myself, I am going to use passport.js.
    – Fanbneyl
    Commented Jan 31, 2021 at 13:57
  • you can also have a look at authentication-flows-js
    – OhadR
    Commented May 6, 2021 at 12:46

2 Answers 2

4

You're right to worry. A common advice is to never ever draft your own authentication mechanism, because you will get it wrong. Pick an existing one; understand how it works; use it in your project.

This works for cryptography too. Don't invent your own patterns. I'm not exactly sure what you mean by “password matched with regex and hashed with salt,” for instance, but it sounds wrong. You're not supposed to use regular expressions when checking for passwords, and you're not supposed to do anything with the password before hashing it. Use something such as PBKDF2, which would handle all the hashing and salting for you, transparently (alternatives do exist).

Even better, don't even bother validating passwords at all. Even if you use PBKDF2—which would give strong guarantees that if your database leaks, a hacker couldn't find the original passwords—it would provide no protection if the server itself is compromised. If a hacker has root access to your server, he can just grab the plain passwords from the HTTP POST to the login page. As easy as that. Instead, delegate authentication to a third party, such as Google or Facebook through OpenID or OAuth 2.0. It works this way:

  1. The person arrives on your website and wants to login.
  2. He gets redirected to Google login page and does all the stuff there. It's a black box for you: it can be as simple as clicking on his name if he's already logged in, or as complicated as entering the password and confirming his identity with a smartphone—something you'll pay for with every SMS sent if you implement it on your own.
  3. Google redirects the user back to your site, telling you that the login was successful.

Now, even if your servers are compromised, you can be sure that you won't need to disclose to your users that a hacker got all their passwords. And with many libraries for many different languages and ecosystems, it is relatively easy to integrate OpenID or OAuth 2.0 in your web app.


To address the comment below:

And what if you do not like or trust Google or Facebook?

While Google and Facebook providers are the most popular, they are far from being the only providers there. A more complete list shows that even those who mistrust every US-based provider can find an option, such as VK and Yandex for Russian-based websites.

And also, what if only users that are authorized by you may login?

Both OpenID and OAuth tell you only that a given user was authenticated and has a specific set of metadata (email address, avatar, etc.) and a specific set of roles. Now, it belongs to your application to decide what to do with this information. You may log the person in. Or you may decide that only the users with specific OpenID IDs can login, and every other person should be rejected.

For instance, I'm using Google's OAuth to handle authentication for sensitive web applications, such as the one which enables/disables the alarm in my house. It wouldn't be very practical if anyone with a Google account could disable the alarm, so the application has a list of hardcoded IDs (mine and the IDs for my family members). If the ID matches, you can see the web app. If it doesn't—sorry, HTTP 403.

Those IDs are what the application receives back from Google. In other words, Google tells, literally, “the person authenticated; his ID is 5900731...685, his email address is [email protected], and, BTW, here's his full name and avatar.” The person's full name and other elements are not interesting from the perspective of security: what interests you is the ID, or more precisely the pair (identity provider, ID), to avoid conflicting IDs if you use multiple providers. This pair becomes de facto the identifier of the user for your site, given that the same person can have naturally more than one ID (for instance if he logs in sometimes through Google, and other times through LinkedIn).

Based on this ID, you can take all sorts of decisions, like, for instance, showing the personal space of the user. Or, in a case of a system which, by design, is limited to a very narrow set of users, such as a home automation system, or a corporate build server, you can simply hardcode those IDs to allow only those specific users to access the application.

If somebody creates a Google account and logins to your site with it, his ID will not be among the whitelisted ones. Therefore, he won't be allowed to get in.

5
  • 1
    And what if you do not like or trust Google or Facebook? And also, what if only users that are authorized by you may login?
    – Frits
    Commented Jan 27, 2021 at 10:27
  • @Frits: I edited my answer to address your questions. Commented Jan 27, 2021 at 11:36
  • ...but why do you even use Google authentication at your home if you still need a token to authenticate/authorize? I mean everybody has (or at least could have) a Google account.
    – Fanbneyl
    Commented Jan 28, 2021 at 14:09
  • @Fanbneyl: I edited my answer. Is it clearer now? Commented Jan 28, 2021 at 16:07
  • yep, understood it now.
    – Fanbneyl
    Commented Jan 28, 2021 at 17:31
1

A simple authentication mechanism is not that scary to implement. I would recommend a session based approach instead of JWT because it is simpler and has fewer ways to screw it up.

The one part you don't want to do yourself is the hashing of the passwords. Just use a popular library for your ecosystem that is designed to hash passwords specifically and follow the instructions.

I dont know what you mean by matching the password with a regexp, but I'm quite sure you don't want to do that. Just hash the received password again and compare it to the stored hash.

When a user logs in via your login route, compare the password hashes and if they match generate a random session ID and store it in your database. Return that Session ID to your client. When a client now wants to post an article, check if they provided a valid session ID (in a header or cookie).

You should know what CSRF and XSS attacks are, but that is also the case if you don't do the authentication yourself.

There are plenty of ways to create security issues in your application, the core authentication code is just one of them. There are valid reasons to never implement your own cryptography, but I don't think creating your own authentication and authorization code is a bad thing. The advantage there is simplicity, you can also create security issues when integrating a third-party solution if you don't understand well enough how it works.

2
  • I used the regex to verify that the password contains at least 1 uppercase letter, 1 lowercase letter and 1 number when a new author is registered. Is this a bad approach?
    – Fanbneyl
    Commented Jan 31, 2021 at 13:49
  • 1
    @Fanbneyl that is fine. It just wasn't clear from your description and looked like you were using rgexps while checking the password Commented Jan 31, 2021 at 15:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.