Best Practices: Secure Frontend Code by Moving to Serverless Cloud

Best Practices: Secure Frontend Code by Moving to Serverless Cloud

January 29, 2019 0 Comments
How to Secure Your Frontend Code by Moving it to the Cloud_870x450

We look at a modern approach to securely moving frontend code to the cloud using a serverless approach, walking step-by-step through two examples.

Frontend code is inherently insecure. Yes, you can mangle your code with something like UglifyJS, or use more a more advanced obfuscation tool like Jscrambler, but at the end of the day, the public nature of frontend code means it’s accessible to nefarious users.

The tried-and-true solution to this problem has been moving sensitive code to the server, which works, but can be time consuming—especially in organizations where the server-side infrastructure is a hot mess of Java, .NET, and SAP code that has evolved over many decades.

In this article we’ll look at a modern approach to moving frontend code to the cloud using a serverless approach. We’ll look at two examples: one where you’ll hide a third-party API key in a serverless function, and another where you’ll move a JavaScript algorithm to the cloud.

Let’s get started.

Scenario 1: Hiding a Third-Party API Key Using Serverless Cloud

For our first scenario, suppose you’re working on an app that has a screen that shows the current weather in the user’s location.

Weather App

To get this data you use an API provided by OpenWeatherMap, a service which allows you to get weather data after signing up for an API key. Because OpenWeatherMap charges based off the number of calls you make to their backend, you don’t want your API key to fall into the wrong hands—and you therefore don’t want to ship that key in your client-side code.

This is a scenario where a serverless approach works really well. By leveraging the cloud, you can quickly and easily move this functionality out of your client-side code. Not only do you get to move your key to a safe location, you also get a cloud function on a server you don’t have to maintain, and you get a function you can use across multiple applications.

There are a number of different serverless cloud providers, but for this article's examples we’ll use Progress Kinvey. Kinvey is a high productivity serverless platform that makes it easy to build everything from quick serverless functions for hiding API keys, to more advanced serverless scenarios we’ll look at later in this article.

NOTE: New to Kinvey? Sign up for a free account to follow along with the steps in this article.

Creating Your First Serverless Function

After you set up a Kinvey account and create an app, you’ll see a dashboard that looks like the image below. Start by clicking “Custom Endpoints,” which is the easiest place to get started with serverless in Kinvey.

Kinvey Dashboard

TIP: Kinvey does a lot more than just serverless. You can store files and data, connect to existing data and authentication providers, and even send push notifications. Learn more on the Kinvey Dev Center.

At the next screen, click the ADD AN ENDPOINT button, give the endpoint a name of “WeatherWrapper,” select Code editor, and finally click the CREATE AN ENDPOINT button.

Kinvey Dashboard 2

NOTE: A Kinvey custom endpoint is a HTTP POST endpoint. You’ll try this out momentarily.

After you finish those steps you’ll see the Kinvey business logic editor, which is where you’ll write the serverless function that you’ll consume in your apps.

Business Logic Editor

The default serverless function is a bit of boilerplate code that returns an empty response. For our example scenario you want to include an OpenWeatherMap API key in your response, so to do that, copy the code below, paste it in the Kinvey business logic editor, and then hit the Save button. (Feel free to use a placeholder for the API key for now.)

function onRequest(request, response, modules) {
  response.body = "YOUR_API_KEY_HERE";
  response.complete();
}

With this code in place all you need to do is send an HTTP POST request to your new endpoint with the correct headers. The easiest place to do that is in the Kinvey API Console, which you can access using the link shown below.

Kinvey API Console

Once you’re in the console, change the first dropdown to POST, and the second dropdown to the “WeatherWrapper” endpoint you just created.

API Console

After that, click the blue SEND button and scroll down to see your result. If all went well, you should see your placeholder API key.

API Key Result

And it’s really that easy! With just a small handful of steps, you’ve created a serverless function that can return a third-party API key that you can reuse across several apps.

When it comes to integrating this functionality into your apps you have a few options. You can send a POST request manually, using your HTTP client or APIs of choice, or, you can utilize one of the many Kinvey SDKs to make your life easier. For example, this is the Kinvey SDK code you need hit the endpoint you just built.

const Kinvey = require("kinvey-nativescript-sdk");

Kinvey.CustomEndpoint.execute("WeatherWrapper", {})
  .then((data) => {
    console.log(data); // This logs your API key
  })

Now that you have your first first serverless function in place, let’s take things one step further to give you an idea of just what’s possible in these serverless functions.

Making HTTP Calls in Serverless Functions

With your current function your apps have to make an HTTP POST request to get your OpenWeatherMap API key, and then make a second HTTP request to actually hit OpenWeatherMap for weather data. While this works, you could simplify things for your apps if you just put the entire call to OpenWeatherMap inside your serverless function.

To do that, all you have to do is go back to the Custom Endpoint editor in Kinvey, select your “WeatherWrapper” endpoint, and swap out the current code to use the following.

function onRequest(request, response, modules) {
  // To test this, you can sign up for a free OpenWeatherMap
  // API key at https://openweathermap.org.
  var appId = "OPEN_WEATHER_MAP_KEY";
  var url = "https://api.openweathermap.org/data/2.5/weather?APPID=" + appId +
      "&units=imperial&lat=" + request.body.lat +
      "&lon=" + request.body.long;

  modules.request.get(url, function(err, result) {
    response.body = result;
    response.complete();
  });
}

This code expects there to be lat and long parameters in the request body, formats the data as necessary, calls the OpenWeatherMap API directly, and then returns the result in the response body.

To test your updated function, head back to Kinvey’s API console, then select “POST” and the “WeatherWrapper” endpoint from the two dropdowns (exactly like you did the last time you tested this endpoint). This time though, include a request body that includes both lat and long parameters as shown in the image below.

Testing API Console Weather

When you send this request, you should see data coming back from OpenWeatherMap that looks like the data below.

OpenWeatherMap Data

To integrate this new functionality in your apps, all you need to do change your existing Kinvey SDK call to pass in the lat and long you want to retrieve weather data for. For example, here’s how I can get weather data for my hometown.

return Kinvey.CustomEndpoint.execute("WeatherWrapper", {
  lat: "42.733",
  long: "-84.555"
}).then(data => {
  var weatherData = JSON.parse(data);
  console.log(weatherData);
});

Pretty cool huh? You can try this code out for yourself in this complete weather app sample that utilizes the cloud function you just wrote.

Hopefully this gives you an idea of just what a serverless approach makes possible. In this example you were first able to hide a third-party API key behind a serverless function. Next, you extended that function to hit a third-party API HTTP directly, giving you a secure utility function you can use across several apps.

And we’re just getting started. Let’s move on to a more advanced way of making serverless calls.

Scenario 2: Moving a JavaScript Algorithm

For our second scenario, suppose you’re working for a large financial company, and you’re getting ready to unveil a new budgeting app called BudgetScore.

BudgetScore

The most important feature of BudgetScore is an algorithm that grades how well a user is budgeting based on their spending habits. The code that determines this grade is something your company doesn’t want anyone to get their hands on, and is therefore something you want to move to a server.

In the real world, the algorithm that determines this score would likely be very complex, but to keep things simple for the sake of explanation, let’s assume the code to determine the score looks like this.

// Assumes transactions is an array of transaction
// data with a numeric amount and a string category.
function determineScore(transactions) {
  var score = 100;
  transactions.forEach((transaction) => {
    if (transaction.amount < 0) {
      score -= 5;
    }
    if (transaction.amount > 5) {
      score += 10;
    }
    if (transaction.category === 'restaurant') {
      score -= 5;
    }
  });
  return score.toString();
}

Although this function is simple, it does expect a collection of transaction data, which already makes it more complex than our previous example. And in the real world, there’s a good chance an algorithm like this might need to pull information from various data sources, and perhaps from various technologies.

For handing more advanced serverless tasks Kinvey has a feature called Flex Services, which are essentially small Node.js libraries that live and run in Kinvey’s cloud infrastructure. Let’s look at how to set one up for your BudgetScore app.

Creating Your First Flex Service

In Kinvey the way you create and deploy Flex Services is through the Kinvey CLI. Therefore, your first step is to install the Kinvey CLI from npm.

npm install -g kinvey-cli

NOTE: You need to have Node.js installed on your development machine for the above command to work. If you don’t, go ahead and install it from the Node.js site.

From there, create a new folder that will contain the code for your new service.

mkdir BudgetScore
cd BudgetScore

Next, use the npm init command to create a package.json configuration file for your service. The command will ask you a number of questions, but for now feel free to accept the defaults.

npm init

After that, use the command below to install the Kinvey Flex SDK, which contains the code you’ll need to register this service with Kinvey’s backend console.

npm install --save kinvey-flex-sdk

Finally, create an index.js file and give it the following code, which returns a hardcoded number as a string for now.

const sdk = require('kinvey-flex-sdk');

sdk.service((err, flex) => {
  function getBudgetScore(context, complete, modules) {
    complete().setBody({
      score: '80'
    }).done();
  }

  flex.functions.register('getBudgetScore', getBudgetScore);
});

Most of the code you see here is the boilerplate for any Flex Service you write with Kinvey. The key thing to note here is the flex.functions.register('getBudgetScore') call, as that’s what registers the service with the Kinvey backend.

TIP: You can read more about the Kinvey Flex Service APIs on the Kinvey DevCenter.

Deploying Your Service

Now that you have the boilerplate code in place, you next have to register the Flex Service in the Kinvey Console backend.

To do so, in your Kinvey Console, choose the Service Catalog tab at the top of the page and then click the Add A SERVICE button.

Add A Service

Next, select Flex and then Flex Services Runtime.

flex-runtime

After that, give your service a name (like “BudgetScore”), and scope the service to an existing app. Hit the SAVE button twice (once in the dialog, once on the following screen) to finish creating your service.

Name Service

With the service created in the web console, head back to your terminal or command prompt, and use the kinvey flex init command.

kinvey flex init

The command will prompt you with a few questions to connect the service you’re developing locally to the one you created in the Kinvey web console. For the prompt answers, select APP, the app you associated the service with in the web console, and BudgetScore.

Prompts

With the connection made, next run kinvey flex deploy to deploy the current version of your local flex service.

Flex Deploy

TIP: See Brian Rinaldi’s article on Testing Kinvey Flex Services the Easy Way for help on creating a local testing environment. This will become more necessary as you start developing more advanced serverless functions.

The deployment will take around a minute, and you can check its status using the kinvey flex status command (look for a deploymentStatus of COMPLETE).

When it’s done, let’s look at how you can use this new Flex Service in an app.

Using Your Service

The steps to using a Flex Service in Kinvey are almost exactly those for the business logic scenarios you used in this article’s first scenario.

In the Kinvey web console, you’ll want to return to the Custom Endpoints menu and again click the ADD AN ENDPOINT button.

Endpoints 2

Give the endpoint a name of “BudgetScore,” select Microservice, and click the CREATE AN ENDPOINT button.

BudgetScore Dialog

Next, select your BudgetScore service, the Development environment, and the getBudgetScore() handler. (This is the name of the function you passed to the flex.functions.register in your service’s code.)

BudgetScore Next

And with that you’re ready to go! To test this out, head back to the Kinvey API Console, select POST, select your new “BudgetScore” endpoint, and click the SEND button. If all went well, you should see your hardcoded value of "80" in the response body.

API Console Budget

To use your new flex service in an app you once more have a couple of options. As with the previous example, you could again manually send HTTP post requests in your app, using the endpoints and headers specified in the Kinvey API console. Or, you could again use one of the Kinvey SDKs to make your life easier. For example, the following code uses the Kinvey SDK to hit your new endpoint.

CustomEndpoint.execute("BudgetScore", {}, {})
  .then((data) => {
      console.log(data);
  })

Let’s take a step back and look at the big picture here though. In just a few minutes, you created a secure Node library that lives in the cloud, which gives you all sorts of potential. For one, you’ve met the requirement of moving your sensitive code to the cloud—without having to rewrite your code to a more traditional server-side language like .NET or Java.

But that’s just the beginning. With Kinvey Flex Services you have a fully functional Node environment, meaning, you can install npm modules, reuse JavaScript code, and architect your services any way you’d like. When you’re done, you can deploy and manage your service outside of your applications—meaning, you can update your production services without having to redeploy your applications.

And there’s more! With a Kinvey Flex Service you can access a number of Kinvey’s other features, such as its ability to access data in a number of different systems. For example, after you connect to your existing data, here’s a Flex Service that reads transaction data and utilizes the algorithm we discussed earlier in this article.

const sdk = require('kinvey-flex-sdk');

function getTransactions(modules) {
  return new Promise((resolve, reject) => {
    const store = modules.dataStore({ useUserContext: false });
    const collection = store.collection('Transactions');
    const query = new modules.Query();

    collection.find(query, (err, result) => {
      if (err) {
        reject(err);
      } else {
        resolve(result);
      }
    });
  });
}

function determineScore(transactions) {
  var score = 100;
  transactions.forEach((transaction) => {
    if (transaction.amount < 0) {
      score -= 5;
    }
    if (transaction.amount > 5) {
      score += 10;
    }
    if (transaction.category === "restaurant") {
      score -= 5;
    }
  });
  return score.toString();
}

sdk.service((err, flex) => {
  function getBudgetScore(context, complete, modules) {
    getTransactions(modules).then((transactions) => {
      complete().setBody({
        score: determineScore(transactions)
      }).done();
    }).catch((err) => {
      complete().setBody(new Error(err)).runtimeError().done();
    });
  }

  flex.functions.register('getBudgetScore', getBudgetScore);
});

Overall, Kinvey Flex Services makes it possible to secure your source code in the cloud, while giving you the potential to do a whole lot more. To see the above Flex Service in action, check out this complete BudgetScore application.

TIP: To get an idea of what else is possible, see Brian Rinaldi’s intro to Flex Services, as well as his collection of Flex Service examples on GitHub. You can also read more about security in Kinvey with this security overview of the Kinvey platform.

Wrapping Up

It’s never been easier to secure your frontend code by moving it to the cloud. Serverless providers make it trivial to not only move your code, but to also leverage powerful backend functionality, such as the ability to hit third-party APIs.

Moving to a serverless approach gives you a number of auxillary benefits, such as not having to worry about server maintenance, giving you the ability to access your code across applications and platforms, and giving you the ability to deploy your code independent of application deployments.

Kinvey is a high productivity serverless platform, designed to accelerate your development in a number of ways. To try serverless with Kinvey, get started today at progress.com/kinvey.

tj-vantoll

TJ VanToll

TJ VanToll is a front-end developer, author, and a Principal Developer Advocate for Progress. TJ has over a decade of web development experience, including a few years working on the jQuery team. Nowadays, he spends his time helping web developers build mobile apps through projects like NativeScript.

Comments
Comments are disabled in preview mode.
Topics
Latest Stories
in Your Inbox

Subscribe to get all the news, info and tutorials you need to build better business apps and sites

More From Progress
progress-next-logo
ProgressNEXT: Premier Event for Modern Application Development
Read More
 
kinvey-console-thumbnail
Getting Started with Kinvey
Read More
 
whatdevsthink
Low-Code Platforms: What Developers Think and Why
Read More