Velo How-To: Security Checklist

Written by velo | Published 2021/06/04
Tech Story Tags: wix | velo | backend | security | software-development | beginners | coding-with-velo | website-development

TLDR You should always set the permissions of your database collections to be as restrictive as possible. Each permission should only be granted to the Admin role unless there is a specific reason to grant the permission to additional roles. Sometimes, you may need to grant access to collection data only in a specific situation or only to a specific user. Changing permissions of the collections will not work in such cases because doing so exposes the data to all users of with the permitted role all the time. When you need a user with a different role to access the collection, you can perform that operation in Backend code.via the TL;DR App

In general, your site is secure without you having to do anything. Wix takes care of that for you. However, there are certain situations where you have to take some precautions so that you don't expose your sensitive data to your site's visitors.

Collection Permissions

You should always set the permissions of your database collections to be as restrictive as possible. Each permission should only be granted to the Admin role unless there is a specific reason to grant the permission to
additional roles. Even when there is a reason to grant a permission to more roles, you should only grant it to the roles that need it.
Here are some examples to illustrate this point:
1. Form Submission - Suppose you have an input form that you want anyone to be able to use. On the collection that the form is connected to, you need to set the create permissions to the Anyone role. But you should still keep all the other permissions restricted to only the Admin role.
  • Read - Admin
  • Create - Anyone
  • Update - Admin
  • Delete - Admin
2. Site Content - Suppose you have a page that displays content from a collection to anyone. You need to set the read permission of that collection to the Anyone role. But you should still keep all the other permissions restricted to only the Admin role.
  • Read - Anyone
  • Create - Admin
  • Update - Admin
  • Delete - Admin
3. Member-Generated Content - Suppose you have a member-generated comments section where members can post comments that anyone can see, but only the poster can update or delete the comment. You should to set the permissions as follows.
  • Read - Anyone
  • Create - Site member
  • Update - Site member author
  • Delete - Site member author
The collection permissions model contains a number of presets that automatically set the permissions for common scenarios, such as the ones mentioned above. For more information on the roles and presets, see Roles and Collection Type Presets in About Database Collection Permissions.
You should be careful when granting a permission to your collections even
if you don't expose that collection functionality in your site.
Here are some examples to illustrate this point:
  • If your site does not contain a form for users to create content for a specific collection, you may think you can safely grant the create permission for that collection to be Anyone. That is not the case. Even though there is no form for a user to create content in the collection, a malicious user can still inject data into your collection. However, your collection will be protected if you restrict the create permission to only the Admin role.
  • If you have a collection for internal use that you don't use on any of your site's pages, you may think you can safely grant the read permission for that collection to be Anyone. That is not the case. Even though there is no page that uses the collection, a malicious user can still read data from your collection. However, your collection will be protected if you restrict the read permission to only the Admin role.
Special Situations
Sometimes, you may need to grant access to collection data only in a specific situation or only to a specific user. Changing the permissions of the
collection will not work in such cases because doing so exposes the
collection data to all users of with the permitted role all the time. Instead, you can set the collection permissions as appropriate for most situations. When you need a user with a different role to access the collection in some manner, you can perform that operation in Backend code.
When calling certain
wix-data
functions from the backend, you can use a
WixDataOptions
object to suppress the permissions check when running the operation. So, even though your collection permissions are restricted to the Admin role, you can perform whatever operation you need, even though the current user's role hasn't been granted permissions for that operation. However, keep in mind that exported backend code can be called by anyone, as described below.
Therefore, a backend function that suppresses permissions checks must perform its own appropriate checks before accessing the collection. Also, only suppress permissions checks when absolutely necessary. When not needed, the permissions checks will ensure that even backend operations run only for users who have been granted permission to that operation.

Code Visibility

All Page, Site, and Public code is visible to any user who visits your site. Even Page code on a password-protected page or members-only page can be viewed and manipulated by any site visitor, even those who don't have the password and are not members.
Therefore, it is extremely important that you don't expose any sensitive information in Page, Site, or Public code.
Backend code is not visible to site visitors. So it's safe to use sensitive
information there. However, keep in mind that even though malicious
visitors can't see what exported backend functions do, they can still see they exist, call them with any arguments they want, and examine their return values.
Therefore, any exported backend code should contain some sort of validation mechanism before performing potentially harmful operations or returning sensitive information. Also, backend functions that are not called from public code should not be exported. 
API Keys
If you access a 3rd party service that requires an API key or other sensitive information, you should always store that information in the Secrets Manager. Never use API keys in Page, Site, or Public code.
Instead, create a function in a backend web module that uses the Secrets API to extract the key and calls a 3rd party service.  Then call that function from your Page, Site, or Public code.
Validations and Checks
If you want to perform a security check or validation in your code, you should always do so using Backend code. Any check or validation in your Page, Site, or Public code can be easily read, manipulated, and circumvented by a malicious site visitor.
For example, consider the following Page code intended to reveal a secret key to a specific user:
export function validateButton_click(event) {
  wixUsers.currentUser.getEmail()
    .then(userEmail => {
      if (userEmail === "[email protected]") {
        // show secret key 
        $w("#secretText").text = "43ne5gfou94tfe";
      } else {
        // show denial message
        $w("#secretText").text = "Access denied!";
      }
    } );
}
There are two major problems with this code:
  1. The security check is revealed to all site visitors. Anyone can see that the correct email address is [email protected].
  2. Sensitive information is revealed to all site visitors. Anyone can see that the secret code is 43ne5gfou94tfe.
The correct way to do this is to move both the security check and the secret code to a backend web module as follows:
// In backend file: secureModule.jsw
import wixUsers from 'wix-users-backend';
import {getSecret} from 'wix-secrets-backend';

export async function secureCheck() {
  try {
    const currentUser = wixUsers.currentUser;
    const currentUserEmail = await currentUser.getEmail();
    const secretEmail = await getSecret("secretEmail"); // "[email protected]"
    
    if(currentUserEmail === secretEmail) {
      const secretValue = await getSecret("secretValue"); // "43ne5gfou94tfe"
      return secretValue;
    }
    else {
      return "Access denied!";
    }
  } 
  catch(err) {
    console.error(err);
    return "An error occured";
  }
}
Although malicious users can call the backend function, they can't gain any
information by doing so since no sensitive information has been revealed. You can call this function safely from Page code as follows:
import {secureCheck} from 'backend/secureModule';

export function secretButton_click(event) {
  secureCheck()
    .then( (message) => {
      $w("#secretText").text = message;
    } );
}
This page code is visible to any site visitor. However, since all the logic was moved to backend code, seeing the code doesn't reveal any sensitive
information to malicious users.
Web Module Permissions
You can also set permissions that define who can call each individual exported function in a web module. To learn more, see About Web Module Permissions.

Storing Personal Information in a Collection

You can store your site visitor's personal information in a collection,
provided that you set the collection permissions so that only the Site member author can read, update, or delete content.
You may also want to store visitor's information using the built-in Contact List. This will allow you to use this information with all the other functionality that Wix provides for use with your contact list.
You can then also use Velo APIs for performing operations that involve site members or contact data.
The following APIs are available:

Written by velo | Velo is a full-stack development platform that empowers you to rapidly build, manage and deploy professional web apps.
Published by HackerNoon on 2021/06/04