Backend security - adamk90/PictoGraphy GitHub Wiki

Security aspects of the backend

Authentication with JWT

During login (/api/login), a JWT token is generated, which has a 40 minutes expire. The token contains the user's username and whether the user is an admin or not:

{
  'username': '...' //<- string
  'isAdmin': '...' //<- bool
}

Except of login (/api/login) and register (/api/register), all endpoints should contain valid JWT token in the Authentication header to authenticate the call. If it's expired or contains a user that is not exists in the database (e.g. a user is deleted from the database for some reason, but at the same time still has a valid JWT token), then the call is rejected with 400 error.

JWT generation can be seen here. JWT authentication can be seen here.

Password storing and requirements

Generally all passwords have to be at least 8 characters long, should contain one lowercase letter, one uppercase letter, one special character and one number.

In the database, the password is not stored in plain text, but hashed with sha512 and with a random 16 hex characters (8 bytes) long salt. The salt is concatenated after the password hash, so password is basically stored as 'sha512(password, salt) + salt'.

Password hashing can be seen here

For the hashing, express's crypto library is used.

Endpoint user inputs

There are cases when user inputs are sent to the backend like:

  • body of the payload in POST requests
  • parameters in URLs (mongoose ObjectIds)
  • query parameters

To be able to safely use these in the mongodb queries, after JWT authentication, the next middleware in the chain of all endpoints is sanitizing these parameters. The sanitizing middleware can be seen here.

For sanitizing, the mongo-sanitize npm package is used.

Also, the mongoose ObjectIds in URL parameters should be valid parameters. For these, they are checked with mongoose.schema.Types.ObjectId.isValid. It is part of the mongoose package.

Caff encryption

The caffs are stored encrypted on the filesystem. For encryption, AES-256 is used in CBC mode (for this express's crypto library is used). The key is a fix key for all caffs (stored securely discussed in following section), and a random 16 bytes IV is generated and concatenated to the front of the encrypted caff.

The encryption can be seen here.

Caff decryption

When caff is downloaded, first it has to be decrypted. The decryption process creates a temporary file in the /backend/tmp/ folder and after successful streaming of the tmp file it is removed from the filesystem.

The decryption process can be seen here.

An improvement could be to use AES in CTR mode, this way the decryption could be done during streaming.

Storing of secrets

There are several points in the backend, where secrets are used:

  • the AES key
  • the builtin admin's password
  • JWT secret
  • the certificates for SSL

For the AES key, admin's password and JWT secret, the dotenv npm package is used, so they are stored in the .env file. Note that, now it is included in GIT, but in production, these should not (.env should be listed in the .gitignore file).

For the SSL certificate, the corresponding files are in the /backend/ssl folder. Note that this library should also be included in .gitignore with the real certificates.

SSL

To be able to securely communicate with the backend, it uses https. This way, sensitive information can't be retrieved for man-in-the-middle. Currently, the certificate is self-signed, so it should be enforced in the client interface (like chrome) to use the not so reliable certificate. The corresponding files are in the /backend/ssl folder. Note that this library should also be included in .gitignore with the real certificates.

Errors

In case of any errors, 400 BAD response is send. This way it is ensured that no information is leaked about the type of error happened.

Logging

For each caff upload, caff download, send comment, delete caff and delete comment activities the actor of the activity and the subject of the activity is logged with a timestamp in the database.