How to secure a web app with login and database in 2022?

Viewed 293

My security knowledge is very old and I want to refresh my full stack development tools. I'm learning about Oauth2, JWT, Next.JS, Auth0 and stuff, but I don't know how to bring all of that together. Please be patient with me, I put efforts in that question :)

Let's say I want to build a web app, where a user can register to a building. He is entering his personal data and receives a human friendly checkin number (e.g. A00001 - Z99999).

o/    ___              
/▌   |App| --POST---> API --> Add User to MySQL, create number-|
/\    ———  <---------------------Send number back--------------|            
  1. How can I secure this /user POST path, to avoid getting spammed by a hacker?

Now there is a security man at the door of the building with the admin app. He get's all users and and clicks "ok" when the user enters the building.

 O/    _________  ---PUT---> API --> Modify User                       
/▌    |Admin App| ---GET---> API --> All Users -|
/\     —————————  <-------send all users--------|
  1. How can I secure this /user GET path, so that only authenticated admins can get all users?
  2. How can I secure this /user PUT path, so that only authenticated admins can update users?
  3. The user should be able to login, but not register. There is only one admin account.

There is no registration for the admin. Only one admin with username and password login. User's don't need a GET /user/[id]. But optionally, is it secure, when I send them a link with a 32bit hash and then I open a GET /user/[hash]?

For those, how would love to help me with code, I'll bring a little with the question:

// pages/checkin.js
export default function Checkin() {

    const checkin = async (e) => {
        e.preventDefault();
        try {
            await fetch('https://myapi.com/user', {method: "POST", data});
        } catch (err) {
            console.log(err);
        }
    }

    return (
        <div>
            <form onSubmit={checkin}>
                {/* ... */}
            </form>        
        </div>
    )
}
// pages/_app.js
import { UserProvider } from "@auth0/nextjs-auth0";

function MyApp({ Component, pageProps }) {
  return (
    <UserProvider>
      <Component {...pageProps} />
    </UserProvider>
  );
}
export default MyApp;
// pages/api/auth/[...auth0].js
import { handleAuth } from '@auth0/nextjs-auth0';

export default handleAuth();
// pages/userList.js
import { useUser } from '@auth0/nextjs-auth0';

export default function UserList() {
  const { user, error, isLoading } = useUser();

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>{error.message}</div>;

  {/*
    * How and where do I fetch the secured users?
    */}

  const ok = async (id) => {
      try {
          /*
           * How to secure the PUT?
           */
        await fetch('https://myapi.com', {method: 'PUT', data: {id, ok: true}})
      } catch (err) {
          console.log(err);
      }
  }

  return (
    user && (
      <div>
        {users.map((user) => (
            <div key={user.id}>
                {user.human_numer} - <button onClick={() => ok(user.id)}>OK</button>
            </div>
        ))}
      </div>
    )
  );
}
1 Answers

So, some security tips from me (beware that I am not an security expert, just code web apps a lot):

  • Use bcrypt (https://www.npmjs.com/package/bcrypt). It is the best simple & secure module I have seen until now.
  • If you are using nodejs (which you are probably) and if you setted up your app with express, you can use express-ratelimit middleware to avoid spam.
  • To be honest, securing GET was a headache for me. Because internet is open by design, it is hard to disallow content sometimes. You can either:
    • Whitelist only your ip (if it is static) or match it with your user-agent etc. and disallow all other IPs. Note that this might be a trouble if you want to work on travel.
    • Use temporary bearer tokens that is for one time use. Note that if your db holding these or the token generator gets hacked, your whole app may fall, so be cautious.
  • The only login no register is easy. Just enter the credentials in your database manually.
  • Personally, I think you don't need to connect everything to a single domain. Set up a local (or not) dashboard and directly PUT users from there. Again, only whitelist your ip and disallow others.
Related