lavamoat-browserify

    14.1.0 • Public • Published

    LavaMoat Browserify - a Browserify Plugin for creating LavaMoat-protected builds

    NOTE: under rapid develop, not ready for production use, has not been audited, etc

    lavamoat-browserify is a browserify plugin for generating app bundles protected by LavaMoat, where modules are defined in SES containers. It aims to reduce the risk of malicious code in the app dependency graph, known as "software supplychain attacks".

    Anatomy of a LavaMoat bundle

    The lavamoat-browserify plugin replaces the last internal build step of the browserify compiler pipeline. This step takes all the modules and their metadata and outputs the final bundle content, including the kernel and LavaMoat policy file.

    LavaMoat builds differ from standard browserify builds in that they:

    1. Include the app-specified LavaMoat policy

    This tells the kernel what execution environment each module should be instantiated with, and what other modules may be brought in as dependencies.

    1. Use a custom LavaMoat kernel

    This kernel enforces the LavaMoat policy. When requested, a module is initialized, usually by evaluation inside a SES container.

    1. Bundle the module sources as strings

    Modules are SES eval'd with access only to the platform APIs specificied in the policy.

    The result is a bundle that should work just as before, but provides some protection against supplychain attacks.

    Example

    Create a file, index.js with some requires.

    const foo = require('./foo.js');
    const gamma = require('gamma');
    
    const elem = document.getElementById('result');
    const x = foo(100);
    elem.textContent = x;
    

    Now use the browserify command with lavamoat as a plugin to build a lavamoat-protected bundle starting at index.js:

    $ browserify index.js --plugin [ lavamoat-browserify --autopolicy ]
    

    All of the modules that index.js needs are included in the bundle.js as strings to be evaluated inside SES containers. A lavamoat policy object is generated from a recursive walk of the require() graph and injected into the bundle (via --autopolicy), which is also written to disk at ./lavamoat/node/policy.json. Commit this policy file and regenerate it when your dependencies change.

    **WARNING: Do not edit the autogenerated policy.json directly. It will be overwritten if a new bundle is created using LavaMoat. Instead, edit the policy-override.json.

    To use this bundle, just toss a <script src="bundle.js"></script> into your html, as per the official browserify documentation.

    **Be sure to use the same Browserify configuration (eg. plugins and transforms like babelify) that you normally use, so that it can parse the code as it will appear in your final bundle.

    Install

    With npm do:

    npm i -g browserify lavamoat-browserify
    

    Usage

    Usage: browserify [entry files] {BROWSERIFY OPTIONS} --plugin [ lavamoat-browserify {OPTIONS} ]
    
    Options:
    
     --autopolicy, -a  Generate a `policy.json` and `policy-override.json` in the current
                       working directory. Overwrites any existing policy files. The override policy is for making manual policy changes and always takes precedence over the automatically generated policy.
    
         --policy, -p  Pass in policy. Accepts a policy object {} or a filepath string to the existing
                       policy. When used in conjunction with --autopolicy, specifies where to write the policy. Default: ./lavamoat/browserify/policy.json
    
       --override, -o  Pass in override policy. Accepts a policy object {} or a filepath string to the
                       existing override policy. Default: ./lavamoat/browserify/policy-override.json
    
    Advanced Options:
    
        --prelude, -pr  Omit the lavamoat prelude from the bundle.
    
    --prunepolicy, -pp Remove redundant package entries from the policy.
    
    --debugpolicy, -dp Generate a `policy-debug.json` in the current working directory. Used for the
                       lavamoat visualisation tool.
    
          --debug, -d  Turn on extra logging for debugging.
    
           --help, -h  Show this message
    

    More Examples

    Run with Policy

    This uses the existing policy files to generate a bundle.

    $ browserify index.js --plugin [ lavamoat-browserify ]

    Automatically searches for policy files inside ./lavamoat/browserify/.

    Policy Override with Relative Path

    This uses the override policy specified at ./policies/policy-override.json to generate a new bundle.

    $ browserify index.js --plugin [ lavamoat-browserify --override './policies/policy-override.json' ]
    

    browserify API

    Create a browserify bundle with LavaMoat directly from the API and write it to bundle.js.

    const browserify = require('browserify')
    const fs = require('fs')
    
    const lavamoatOpts = {
      policy: '../../policy.json',
      override: '../../policy-override.json',
      writeAutoPolicyDebug: true,
      prunePolicy: true
    }
    
    const bundler = browserify(['./index.js'], {
      plugin: [
        ['lavamoat-browserify', lavamoatOpts]
      ]
    })
    
    bundler.bundle().pipe(fs.createWriteStream('./bundle.js'))

    Policy Formats

    Policy as an object

    const lavamoatOpts = {
        policy: {
            resources: {
                 <root>: {
                     packages: {
                         react: true
                    }
                }
            }
        }
    }

    Policy as a function, must return a filepath or an object:

    const lavamoatOpts = {
        policy: () => "./lavamoat/policy.json"
    }

    OR

    const policyObject = {
        resources: {
            <root>: {
                packages: {
                    react: true
                }
            }
        }
    }
    const lavamoatOpts = {
        policy: () => policyObject
    }

    See lavamoat-browserify examples for more usage examples.

    Policy file explained

    Here is an example of the policy file with each field explained:

    {
        “resources": {
            “<root>”: {
                "packages": {
                    “react”: true,
                },
            },
            “react”: {
                "globals": {
                    “console”: true,
                    "window.postMessage": write
                }
            }
        }
    }
    
    • "resources": All packages in your dependency graph accessible via require().
    • "<root>": Entry point for the project's code, the "application package", such as index.js.
    • "packages": All packages accessible by the parent resource. In this example, "<root>" has access to "react".This means that "<root>" can require('react').
    • "globals": All platform APIs and global variables accessible by parent resource. In this example,"react" has access to console. Global access is read-only, unless defined by the write value. React can therefore read from AND mutate window.postMessage(!!).

    Lavamoat Viz

    The lavamoat viz is a tool to visualize an application's dependency graph and assess package dangerousness.

    Introduction to LavaMoat Video

    introduction to LavaMoat

    Keywords

    none

    Install

    npm i lavamoat-browserify

    DownloadsWeekly Downloads

    624

    Version

    14.1.0

    License

    MIT

    Unpacked Size

    941 kB

    Total Files

    59

    Last publish

    Collaborators

    • tmpfs
    • kumavis