Overview of Yomly security and performance

Yomly security

This section provides you with an overview of Yomly security.

Web Application Firewall

A Web Application Firewall (WAF) filters initial requests. This set of services reviews every part of the request to ensure that it is correct, not structured (like an attack), and complies with our auditing and compliance model. If the request fails any of these checks (some 1800 in total), the request is silently dropped, and the sender receives no response. (A response could indicate why the request was dropped and allow a potential attacker to modify their attack).

We do a number of different types of checks, including:

  • Is the request from an unapproved BOT?

    On the Yomly platform, we do not permit bots that scrape the Yomly interface or attempt to provide services by scripting at the UI level, due to their impact on performance and reliability.

  • Is this an anonymous request?

    We drop requests for which we cannot identify the sender as we cannot provide the appropriate auditing and logging of requests from anonymous senders. You might be providing an anonymous client if you, for example, use certain VPNs, the TOR browser, or have used a redirect system to obscure the return path. These types of requests are dropped.

  • Does your Request Look Malicious?

    We automatically detect attempts to use over 1500 different attack vectors (such as SQL insertion, spoofing, or cache poisoning) and drop such requests.

If your request gets by our firewall, it will come up against the internal defences of Yomly.

Data at rest 

In many multi-tenanted environments, particularly those based on a traditional LAMP infrastructure, tenants share the same database and are segregated logically using a specific key in each record that refers to a specific business. This method is often used to manage the use of database connections, which becomes an issue as the number of users increases.

It is, however, inherently insecure as every client will be sharing the same database. Poorly-constructed code or a security breach to a single database could possibly expose data that belongs to all tenants.

Yomly provides a separate database schema to each client. There is no shared database in which data belonging to different clients is mixed. This provides the following benefits:

  • Each database connection can access only a single business. Coding errors do not result in the exposure of information that belongs to other clients.

  • Malicious actors, if successful in breaching any database, would have access to a single business only, not everyone's data. This increases the effort/reward calculation for any criminal breach.

  • Each business can apply separate Personal Identifiable Information (PII) encryption to their database schema.

  • It is possible to recover a single client, without having to restore information of all clients.

We manage the use of database connections through a series of Database Proxies backed by multiple Database Replicas that enable Yomlu to maintain a high-performance database environment.

Data access

In a traditional LAMP stack, the database is often available to the internet. Although there are techniques to reduce this access, they are often implemented poorly or have maintenance utilities, which enable access to the database from outside the application itself.

The Yomly databases have no direct path to the internet. All access is only through the application itself, running within the same restricted subnet. A single data path exists from the front-end to the backend services through a secured ingress, which does not allow any port apart from HTTPS and SSH to pass through. Data is encrypted end to end from browser to backend service. This means:

  • No mechanism can be used to directly access the database and execute SQL code against the database itself. The support access is via a bastion server locked to a specific IP address, to which DBAs would need to establish an SSH connection before accessing the database.

  • The requests from the front-end are distributed to multiple GraphQL services, and each transaction requires an authentication token. This means that to make any changes to the database or retrieve data from the database, you must use the defined GraphQL queries and be an authenticated user.

  • Due to the numerous semantic translations occurring in this chain, common SQL insertion attacks are impossible from outside the cluster as we do not execute any SQL. Of course, we also have standard escapes for any detected SQL.

Authentication

Authentication means ensuring that any transactions that occur within the system are only executed by someone we know. Yomly has two public-facing transactions:

  • Get the business name of a client: This is a sort of reverse phonebook. This is publicly accessible information in any event and this transaction is required prior to login, so that we can assign the correct business.

  • Get the list of countries in the world: This is the same information that you can find on Wikipedia.

These public routes disclose none of the header structures that are used in other calls to the backend services, in fact we have employed signature obfuscation on them.

Identity Providers    

Yomly supplies an internal Identity Provider (IdP) based upon Amazon Cognito. This is primarily used for internal system users and smaller clients that do not have an IdP of their own. We also support and recommend the use of external IdPs, such as:

  • Any SAML2 provider, such as Active Directory, Azure, OneLogin, Okta, and more
  • If you are an Apple-only shop, we can set you up to authenticate with your AppleID.
  • If you are a Google-only shop, we can set you up to authenticate with your Google login credentials.
  • Any mixture of the above. You can allow some users to log in with our internal IdP and others with Azure Active Directory (AAD). This is important for companies that have different IdPs deployed in different locations.

Logging in with Facebook or LinkedIn account credentials

This mechanism is now deprecated as there are some concerns around potential exposures with the mechanism.

If you use an external IdP then all of your policies, such as password practices, multi-factor authentication, etc., are maintained. In some IdPs, for example, AAD, you might need assign access to Yomly within the IdP itself.

The front door

In many SaaS environments, once you are authenticated, you are in! To Yomly, this is only the first step in the access journey. We now know that you are who you say you, but it doesn’t mean we are going to let you do anything at this point.

Once you are authenticated, we provide you with a short-term ID token and an access token that has three abilities:

  • Ability to request authorization
  • Ability to find out the name of your business
  • Ability to list all the countries in the world.

So really, you aren’t able to do much at this point.

Authorization

The process of authorization provides you with a token that describes everything you are allowed to do within Yomly. On every call to the backend, for every piece of data you request and every action you take, this token must be passed to the backend. If what you are trying to do is not represented within the token, it will be denied and the attempt will be logged.

As a user of Yomly, this is mostly transparent to you. There are around 100 such calls on a single screen of the platform, and each call has a separate authorization check. While this doesn’t matter to real users, it is a huge problem for anyone trying to break in.

To break in, an attacker would successfully need to do all of the following:

  1. Get authenticated.
  2. Decrypt the format of the Yomly access token.
  3. Identify from the bitmap what each part of the access token means.
  4. Craft a header for each transaction that a page will execute.

Policies

Each backend call is protected by an access policy. There are approximately 3,000+ policies enforced at the backend. If you are assigned a specific policy, it will appear on your access token and you are allowed to perform the related authorized action. If you are not assigned the policy, the action is denied.

Policies are assigned to roles, and roles to each user. To make it easier to set up, we provide you with a basic set of roles (Employee, Manager, HR Admin, Payroll Admin, etc.) and the required policies. You can then tailor the policies to the level of authorization you require for each user.

Transaction lifecycle

Let’s put it all together. A transaction on the platform requires the following:

  1. Authenticating you

  2. Exchanging your ID token for an Yomly access token.

    We do this by creating a bitmap of every policy in the system and check to see if you are allowed to perform that action. If you are, we set the bit that corresponds to that policy to 1 (ON). Once we have all of your policies in the bitmap, we map your span of control for each policy and set this in an extension block. We take the complete access block, encrypt it, digitally sign it, and finally pass it back to you.

  3. A transaction, such as "get first name". (There are a lot of transactions.) The front-end passes your access token to the headers.

  4. Decrypting your token, verifying the digital signature, and comparing the bit associated with the required policies with the policies required for the transaction.

    If they match, we allow the action.

  5. Changing either the signature or encryption keys randomly so that you can’t just save an access key and get access forever

    All keys expire and require an authentication refresh under the covers. This again ensures that you can’t just reuse a token forever. This happens at random intervals, but never more than 60 minutes.

Data in transit 

All data transfers, both internally between services, and externally to and from your browser, use TLS 1.2 and if available, TLS 1.3. We do not support encryption below TLS 1.2, and therefore, certain older browsers are not compatible with Yomly. Data is encrypted end to end from browser to backend service.

System Users

Only authorized users can perform actions against client data on the Yomly platform. These actions include background workflows, external API calls, and more. In Yomly, we have two types of proxy users:

  1. Business proxy: This is a system user defined in the internal IdP. It is used inside workflows,  executes the automation, and orchestrates tasks. The business proxy user appears as a user inside your setup and you can control its activities by changing the permissions (policies) assigned to it.

  2. External API keys: Each application that uses the external APIs must have an API key. The API key must be associated with a real user. Optionally, you can limit an API key by time and IP address. All actions of the external API are logged against the user who created the key.

    Access logging means that:

    • User access is logged in both system logs and an access control table.
    • Changes to records are logged in both database logs and an internal changes table.

Penetration testing

We continuously scan our platform for potential security vulnerabilities. We perform the following scans daily:

  • Production portal penetration scan
  • Production GraphQL penetration scan
  • Production infrastructure scan
  • QA system penetration scan

We also use an external provider on a quarterly basis to perform a manual penetration scan.

Disaster recovery and service availability

This section provides you with an overview of our disaster recovery and service availability.

Cluster and service availability

Yomly runs as a series of services on a Kubernetes cluster. There is no single server to fail, and no single point of failure. A production cluster can consist of 8-15 nodes which scale horizontally based upon activity. These nodes are distributed across multiple data centre environments, so that if we lose power to one set, for example, the nodes will re-establish at the other availability zone.

Services run in increments of two instances. These operate in round robin mode; if one instance were to fail, another instance would take over the work. Instances automatically scale based upon the current load on the system.

If all the instances for a particular service were to somehow fail, then the system would continue to run with loss of only the specific service.

If we were to lose all availability zones for a cluster (such as a natural disaster in a city), we can recover a completely new cluster at another geographic location in approximately 45 minutes from bare metal.

Database recovery

Our database servers run in a cluster configuration, with a main server for update transactions and one or more replicas for read only queries. The main and replicas are distributed across multiple availability zones to provide real-time resiliency.

In the event that the main server becomes inoperable or communication to its data centre is lost, one of the replicas is promoted and steps in as the main server. This occurs in approximately 500 ms.

Point in time recovery

We have implemented a regime for database recovery that includes:

  • Daily database snapshots: These snapshots are retained for 35 days and enable restoration of the server to the time of the snapshot.
  • Transaction logging: We log each database transaction (both before and after images) and can restore the database to a specific point of time within the last 35 days.
  • Single schema restore: A single database schema can be restored to a specific point in time for the past 35 days. This involves restoring a copy of the complete database and copying the specific schema to the current operating database server. This takes approximately 90 minutes.
  • Main/replica failover: Separate synchronized copies of the database server are maintained in different availability zones. In the event of a failure in one, the database server can be switched to the replica in approximately 15 seconds.

Performance

We use a variety of techniques to ensure that platform performance exceeds your expectations.

The requirement to transfer information across the network limits the services that many SaaS products can provide. Yomly distributes workloads in a way that minimizes any performance dependencies from the transaction chain.

Front-end

Many web applications struggle with providing desktop-level performance in the browser. This is largely due to latency when loading up JavaScript and other assets across the network when  required. In Yomly, we have over 200MB of JavaScript code. If we were to use a traditional web hosting model, it would result in 20-30 seconds of delay in simply loading the front-screen. On the contrary, Yomly loads in most cases in 1-2 seconds.

The reason we are able to maintain front-end speeds is that we have structured the front-end application as a Progressive Web Application (PWA). On first load, we install the application and all JavaScript to the hard disk of your local machine. Then, instead of fetching from a cache or across networks, we can execute the JavaScript from your hard disk, providing significant performance boosts.

A PWA can be used to create a real desktop application, which is added to your start menu, or occupy an icon on your desktop, or even your mobile phone.

Backend

Instead of a single backend server, Yomly provides around 30 different micro-services. Each  service runs independently and provides its own mechanism for horizontal scaling. Therefore, for example, if the Leave feature starts getting heavy use, it spins up an additional instance to take over the additional load. When the load decreases, an instance is shutdown.

Data access

Data access is provided by a federated GraphQL schema. Unlike accessing data through a REST API or through SQL calls, GraphQL only returns the specifically-requested data, thereby reducing the amount of data transferred through the network. We also utilize the following techniques:

  • GraphQL uses local cache for non-volatile information so that the request is delivered from your local hard disk instead of proceeding from the front-end. These caches are invalidated through a background worker if the data on the server is changed.

  • Query segregation: In the world of SQL (which is where our data ultimately resides), Update and Insert transactions lock a table, while Select statements do not. We utilize this dichotomy by sending Updates, Inserts and Deletes to the primary server, and redirect Select calls to the read replicas.

Was this article helpful?
0 out of 0 found this helpful

Comments

0 comments

Please sign in to leave a comment.