Home > other >  How do I protect an express / gun.js server?
How do I protect an express / gun.js server?

Time:01-15

How do I protect this gun server? I only want traffic from one domain with many sub-domains.

In my use-case, I made a game for my kids on iPad. When they played for the first time - I realized it would be better if some of the game controls could be moved to their phone. So they use the ipad and the phone simultaneously to control the game. It works great. Data is sync'd between devices via gun. However, there's this problem of security. Anyone could use my gun server to share state between devices in real-time. I'd like to restrict it to my app

const ARGS = process.argv.slice(2);

var fs = require('fs');
var protocol = ARGS[0];
var port = ARGS[1];

var express = require('express');
var cors = require('cors')

var Gun = require('gun');
require('gun/axe');

var app = express();
var allowedOrigins = [
    'localhost:8080',
];

app.use(cors({
    origin: function (origin, callback) {
        // allow requests with no origin
        // (like mobile apps or curl requests)
        // if (!origin) return callback(null, true);

        if (allowedOrigins.indexOf(origin) === -1) {
            var msg = 'The CORS policy for this site does not '  
                'allow access from the specified Origin.';
            return callback(new Error(msg), false);
        }

        return callback(null, true);
    }
}));


app.use(Gun.serve);
app.use(express.static('/gun'));

server = require(protocol);

if (protocol == 'https') {
    var privateKey = fs.readFileSync('../json-data.ssl/key.pem', 'utf8');
    var certificate = fs.readFileSync('../json-data.ssl/cert.pem', 'utf8');
    var credentials = {key: privateKey, cert: certificate};
    var server = server.createServer(credentials, app);
} else {
    var server = server.createServer(app);
}

server.listen(port, () => {
    console.log('listening on *:'.concat(port));
});

var gunDev = Gun({web: server, file: 'testingDB'});

CodePudding user response:

A web server on the internet is, by default, open to anyone who has any sort of programming skills.

CORs protection is something that only applies to Javascript running in a web page. CORs protection itself is implemented in the browser and when any sort of code is running outside a browser (any simple script), there is no CORs protection at all. So, CORs really doesn't apply from any other type of client besides a browser.

So, to protect your server from access by the general public, you have these various options:

  1. Keep your server off the internet. Make it only accessible on some local network where the clients reside. For example, I have a raspberry Pi server used for some home automation tasks running at my house and it's behind my home firewall and only accessible from my home network (e.g. not on the internet). Any access to this server (such as changing its configuration) is done from on the home network. Thus, it doesn't have to be secured against random internet access.

  2. Restrict access to only certain client IP addresses. In general, this is usually not very practical as any sort of mobile device may very well change its IP address regularly and also not entirely secure.

  3. Require some sort of credential upon connection to your server. This is the main mechanism used. Depending upon how the client will acquire and enter the credential, this may be either a typical end-user account credential such as username and password or if everything is programmatic, it can be a cryptographically secure key. In either case, a client gets issued (by your server) a credential that can then be used to authenticate on future connections to your server. This will deny access to any clients or any type that you haven't issued a credential to. Your server would require the credential upon connection and reject any requests that don't pass the auth check. It goes without saying that credentials should only be sent over https to prevent theft of the credentials by network snoopers (like public WiFi).

For your particular game use, #1 would be possible only if you restrict use to the home network and require both devices to be on home WiFi, not on the cellular network.

For your used, #2 is probably not feasible.

So, that means that #3 is probably what makes the most sense. If this is a one-off deployment, then you could manually configure each client with a security token and manually add those tokens to some configuration storage (like a JSON file) on the server. If you're attempting to make a more scalable system that lots of other gaming users can use, then you would have to develop some sort of system for registering legit clients, issuing them credentials and storing those credentials in the clients. Since your clients may come in pairs that need to be "connected", you will have to bake that into your credential issuing process too.

CodePudding user response:

Step 1 - Create cors.js file

const cors = require('cors');
const whitelist = ['localhost:8080'];

const corsOptions = (req, callback) => {
  let options = {
    origin: whitelist.includes(req.header('Origin') ? true : false;
  }
  callback(null, options);
};

exports.corsWithOptions = cors(corsOptions);

Step 2- Import and apply corsWithOptions

const { corsWithOptions } = require('./cors');
...
app.use('/*', corsWithOptions, (req, res) => { res.sendStatus(200); })
app.use(Gun.serve);
app.use(express.static('/gun'));
  •  Tags:  
  • Related