How to apply Atlassian’s Security Requirements for addons

Around November 2019 Atlassian has published new security requirements for cloud applications. The requirements come into force on January 1, 2020. However Atlassian has not published guidance on how to apply these security requirements in their officially supported javascript framework ACE (Atlassian Connect Express).

In this post I share my interpretation of the security requirements in the form of javascript code for ACE. I’ll only cover the requirements which need to be handled in a typical ACE installation on e.g. Heroku. Heroku already provides TLS, and things like not exposing secrets in source repositories fall outside the scope of this article. The code uses two npm packages: helmet and express-sslify. You normally need to add the code below to your app.js.

// security configuration https://developer.atlassian.com/platform/marketplace/security-requirements/
import helmet from 'helmet';
import enforce from 'express-sslify';
import nocache from 'nocache';

After importing these, you need to configure the libraries:

...
// define helmet middleware early
// use helmet only in poduction/prodtest
let prodEnv = false;
if ( app.get('env') == 'production' || app.get('env') == 'prodtest') {
    prodEnv = true;
}
console.log('prodEnv is: '+prodEnv+' env is: '+app.get('env'));

// Sets "Strict-Transport-Security: max-age=34560000; includeSubDomains".
// HSTS minimum is one year, use 400 days
// fourhundredDaysInSeconds := 400 * 24 * 60 * 60 = 34560000
const fourhundredDaysInSeconds = 34560000;
if (prodEnv) {
    // for Heroku: trustProtoHeader: true, otherwise not necessarily
    app.use(enforce.HTTPS({ trustProtoHeader: true }));
    app.use(helmet.hsts({
        maxAge: fourhundredDaysInSeconds,
        includeSubDomains: false
    }));
    app.use(helmet.referrerPolicy({
        policy: ['no-referrer']
    }));
    app.disable('x-powered-by');
    console.log('started security policy');
}

...

// Mount the static files directory
const staticDir = path.join(__dirname, 'public');
app.use(express.static(staticDir));

// use the nocache after mounting the staticDir
app.use(nocache());

A short note on using nocache after mounting the staticDir: the static files usually are resource files like css and javascript and don’t contain changing data, so caching is allowed. I think this use cases falls under the exemption in article 5. of the security requirements. Using noCache after staticDir does not set the Cache-Control header for these resources.

The requirement that the application must authenticate and authorize all requests can be easily handled by ACE:

app.get('/configure', addon.authenticate(), function(req, res) {
     ...
    });

I.e. use addon.authenticate() in your route definitions. However make sure you don’t require authentication for atlassian-connect.json.

One further hint: Don’t use helmet.frameguard. ACE apps run as an iframe in the Atlassian application, and must be embeddable in an iframe.

Photo by REVOLT on Unsplash