Block public access to expressjs app - javascript

Consider, the following expressjs app:
var express = require('express');
var http = require('http');
var httpApp = express();
httpApp.configure(function() {
httpApp.use(express.static(__dirname + '/static/'));
});
var server = http.createServer(httpApp).listen(4444);
now,
i want this server not to be available publically & ONLY to respond to requests from specific clients based on their IP address/domain. Everybody else should get 403 - Forbidden error.
I searched the API Doc & found way to do this to first enable trust proxy by app.enable('trust proxy') & then check req.ip.
However, I can't I access req object. so if anyone take this code & can show me how deny a req based on its IP/domain, that would be super-helpful

Simply add a piece of middleware that checks the IP and denies access if it doesn't match:
app.use(function(req, res, next) {
if (allowed(req.ip))
next();
else
res.status(403).end('forbidden');
});

Use express-ipfilter
Installation
npm install express-ipfilter
Usage with Express
var express = require('express')
, ipfilter = require('express-ipfilter')
, app = express.createServer()
;
// Whitelist the following IPs
var ips = ['127.0.0.1'];
// Create the server
app.use(ipfilter(ips, {mode: 'allow'}));
app.listen(3000);
https://www.npmjs.com/package/express-ipfilter#installation

Related

Server not receiving HTTP requests from Client

First a quick preface I think may be helpful: I am new to splitting my client and server into separate web apps. My previous apps have all had my server.js at the root level in my directory and the client (typically a create-react-app) in a /client folder.
What I wanted to do: Host a single express.js server on the web which multiple other web applications could make requests to.
I did the first part using an express server and aws elastic beanstalk.
server.js
require('dotenv').config()
const express = require('express');
const app = express();
const cors = require('cors');
const PORT = process.env.PORT || 5000;
const Mongoose = require('mongoose');
const { Sequelize } = require("sequelize");
//ROUTES
const APIUser = require('./routes/api/mongo/api-user');
more routes...
//INITIATE DATA MAPPING CONNECTIONS START
Mongoose.connect(
process.env.MONGO_URI,
{ useNewUrlParser: true, useUnifiedTopology: true },
console.log("connected to MongoDB")
);
const Postgres = new Sequelize(process.env.PG_CONN_STRING);
try {
Postgres.authenticate()
.then(console.log("connected to Postgres"));
} catch {
console.log("Postgres connection failed")
}
//INITIATE DATA MAPPING CONNECTIONS END
//middleware
app.use(cors())
more middleware...
//home route
app.get('/api', (req, res) => {
console.log('RECEIVED REQ to [production]/api/')
res.status(200).send('models api home').end();
})
//all other routes
app.use('/api/user', APIUser);
more route definitions...
//launch
app.listen(PORT, () => console.log(`listening on port ${PORT}`));
The log file for successful boot up on aws: https://imgur.com/vLgdaxK
At first glance it seemed to work as my postman requests were working. Status 200 with appropriate response: https://imgur.com/VH4eHzH
Next I tested this from one of my actual clients in localhost. Here is one of my react client's api util files where axios calls are made to the backend:
import { PROXY_URL } from '../../config';
import { axiosInstance } from '../util';
const axiosProxy = axios.create({baseURL: PROXY_URL}); //this was the most reliable way I found to proxy requests to the server
export const setAuthToken = () => {
const route = "/api/authorization/new-token";
console.log("SENDING REQ TO: " + PROXY_URL + route)
return axiosProxy.post(route)
}
export const authorize = clientsecret => {
const route = "/api/authorization/authorize-survey-analytics-client";
console.log("SENDING REQ TO: " + PROXY_URL + route)
return axiosProxy.post(route, { clientsecret })
}
Once again it worked... or rather I eventually got it to work: https://imgur.com/c2rPuoc
So I figured all was well now but when I tried using the live version of the client the request failed somewhere.
in summary the live api works when requests are made from postman or localhost but doesn't respond when requests are made from a live client https://imgur.com/kOk2RWf
I have confirmed that the requests made from the live client do not make it to the live server (by making requests from a live client and then checking the aws live server logs).
I am not receiving any Cors or Cross-Origin-Access errors and the requests from the live client to the live server don't throw any loud errors, I just eventually get a net::ERR_CONNECTION_TIMED_OUT. Any ideas where I can look for issues or is there more code I could share?
Thank you!
Add a console.log(PROXY_URL) in your client application and check your browser console if that's logged correctly.
If it works on your local client build, and through POSTMAN, then your backend api is probably good. I highly suspect that your env variables are not being set. If PROXY_URL is an emplty string, your axios requests will be routed back to the origin of your client. But I assume they have different origins since you mention that they're separate apps.
Remember environment variables need to prefixed with REACT_APP_ and in a production build they have to be available at build time (wherever you perform npm run build)

How do i allow 'Access-Control-Allow-Origin' in Node.JS Http Server?

Im trying to send a POST from a client connected to this server to a external URL. I get a lot of 'CORS' errors. Im pretty sure that it's because i haven't allowed 'Access-Control-Allow-Origin' and etc on my Node.JS server. But i don't know how to do it. I have found another answers on the web, but none of them solved my problem.
Here is my server:
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
const { instrument } = require('#socket.io/admin-ui')
var bodyParser = require('body-parser')
var clientesConectados = [];
app.use( bodyParser.json() ); // to support JSON-encoded bodies
app.use(bodyParser.urlencoded({ // to support URL-encoded bodies
extended: true
}));
app.get('/', function(req, res){
//send the index.html file for all requests
res.sendFile(__dirname + '/index.html');
});
app.post('/', (request, res) => {
console.log("********************");
console.log(" >POST RECEBIDO!!");
console.log(res);
postData = request.body;
io.emit('message',postData);
console.log(postData);
});
http.listen(3000, function(){
console.log('listening on *:3000');
});
Express has a middleware for CORS. Link here
Install npm package called cors
After installing, on your file add this line app.use(cors()) will solve your issue of cors error I hope.
Install cors package in your application
npm install cors
And then add these two lines in there
var cors = require("cors");
app.use(cors())
Else there are ways that set through header or you could use a proxy in your frontend but using cors package is simpler

How to secure a simple GET request using Express js

I have build a simple web server using Express js. There I have one GET request to send any json response. Now this request can be accessed from anywhere by anyone.
How can I restrict this GET request from having public access and what approach should I follow to restrict this public access?
Please note, I don't have the login or logout feature, only simple GET request.
Below is my code ---
const express = require('express');
const app = express();
app.get('/', (req, res) => { res.send('Test response'); });
app.listen(3000, () => console.log('Listening on port 3000!'));
There are multiple ways to secure a route. One way can be IP whitelisting.
So basically, you can give particular IPs access to the route. For that you can use express-ipfilter
// Init dependencies
const express = require('express')
const ipfilter = require('express-ipfilter').IpFilter
// Whitelist the following IPs
const ips = ['127.0.0.1']//add the IPs here
// Create the server
app.use(ipfilter(ips, { mode: 'allow' }))
app.get('/', (req, res) => { res.send('Test response'); });
app.listen(3000, () => console.log('Listening on port 3000!'));
There are countless ways to give access to certain person your route:
Private key encryption, sharing a secret key with someone you want access. Whenever your route is called you check the secret key
Public key, You can share your certificate with them, they need to pin the certificate in their request module and hit the route etc.

What protocol should I use and what are the docs for it?

So I'm trying to build a Discord bot. These types of threads tend to get downvoted a lot on stackoverflow, so I'm hoping this doesn't happen to me.
This particular feature is acting as a temporary solution to my dashboard problem. Due to the nature of glitch.com's hosting, it's supposed to fall asleep after 5 minutes of http inactivity. I solved that already by adding a script that pings the URL every 4 minutes, but that caused another issue. I think what's happening is that because that script and the bot script are constantly running, and never technically 'finish', it never lets any incoming connection actually load the webpage. So my solution to that problem was to create another glitch project that would act as the dashboard website, and transfer information from the bot project. Of course then I'd need to create more scripts that communicate with each other via some internet protocol. The info recorded by the bot is all recorded in a private JSON database using the node-json-db npm library.
My problem is: I don't know what protocol would be best for this kind of thing. Even if I did know, then I'd have to go digging through the docs for the info I'm looking for.
My question is: What protocol should I use, and what docs do I need to read for this?
I've included some snippets of the code here:
The bot's server code (where I would add the script for communicating with the dashboard):
// server.js
// where your node app starts
// init project
const express = require('express');
const app = express();
const JsonDB = require('node-json-db');
const db = new JsonDB("myDataBase", true, true);
// we've started you off with Express,
// but feel free to use whatever libs or frameworks you'd like through `package.json`.
// http://expressjs.com/en/starter/static-files.html
app.use(express.static('public'));
// http://expressjs.com/en/starter/basic-routing.html
app.get('/', function(request, response) {
response.sendFile(__dirname + '/views/index.html');
});
app.post('/login/c3RvcCBoYWNrZXIh', function(request, response) {
var servername = request.param('servername');
var password = request.param('password');
if (db.getData("/" + servername + "/password") === password) {
response.json(db.getData("/" + servername));
} else {
response.json(null);
}
});
// listen for requests :)
const listener = app.listen(process.env.PORT, function() {
console.log('Your app is listening on port ' + listener.address().port);
});
// to keep the bot alive, since glitch puts projects to sleep after 5 mins of inactivity.
const http = require('http');
setInterval(() => {
http.get(`http://${process.env.PROJECT_DOMAIN}.glitch.me/`);
}, 270000);
The server.js on the dashboard website:
// server.js
// where your node app starts
// init project
const express = require('express');
const app = express();
const request = require('request');
// we've started you off with Express,
// but feel free to use whatever libs or frameworks you'd like through `package.json`.
// http://expressjs.com/en/starter/static-files.html
app.use(express.static('public'));
// http://expressjs.com/en/starter/basic-routing.html
app.get('/', function(request, response) {
response.sendFile(__dirname + '/views/index.html');
});
app.post('/login', function(request, response) {
var servername = request.param('servername');
var password = request.param('password');
if ("thereisnopassword" === password) {
response.sendFile(__dirname + '/dashboard/index.html');
} else {
response.sendFile(__dirname + '/views/wronginfo.html');
}
});
// listen for requests :)
const listener = app.listen(process.env.PORT, function() {
console.log('Your app is listening on port ' + listener.address().port);
});
I had this too, but solved it by simply putting the code to start the express server before the http loop.
// Require packages
const http = require('http');
const express = require('express');
const app = express();
// Express
app.get("/", (request, response) => {
response.sendStatus(200);
});
app.listen(process.env.PORT);
// Interval
setInterval(() => {
http.get(`http://${process.env.PROJECT_DOMAIN}.glitch.me/`);
}, 240000);
// Bot code
const Discord = require('discord.js');
const client = new Discord.Client();

Make a cookie when a user connects with socket. io - node js

have a server that uses socket.io. When a user connects it will assign them the user id thats made on the server then increment it by 1 so the next user with have a different id.
I want to use cookies for this, to check if they have previously logged in, if so, use that id, if not, use the one on the server.
the way to create a cookie is by using
res.cookie('cookie', 'monster')
but im not where i would put it, i tried putting it in the connect function but res wouldnt exist. and if i put it outside the function, how would i call it? Here is my code. This is the start of my server:
//Require npm modules
var express = require('express');
var http = require('http');
var events = require('events');
var io = require('socket.io');
var ejs = require('ejs');
var app = express();
//Set the default user Id to 1 and the default username to Guest
exports.Server = Server = function()
{
this.userId = 1;
this.userName = "Guest";
};
app.set('view engine', 'ejs');
app.get('/game/:id', function (req, res)
{
res.render('game', {game: req.params.id});
});
Server.prototype.initialise = function(port)
{
//Create the server using the express module
this.server = http.createServer(app);
//Declare the 'public' folder and its contents public
app.use(express.static('public'));
//Listen to any incoming connections on the declared port and start using websockets
this.server.listen(port);
this.startSockets();
this.em = new events();
consoleLog('SERVER', 'Running on port: ' + port);
};
Server.prototype.startSockets = function()
{
//When a user connects to the server on the 'game' socket
this.socket = io.listen(this.server);
this.socket.of('game').on('connection', function(user)
{
res.cookie('cookie', 'monster')
//Set their usedId and username
user.userId = this.userId;
user.userName = this.userName + " " + this.userId;
//Increment the user id by 1 so each user with get a unique id
this.userId++;
//Send a response back to the client with the assigned username and user id and initialise them
user.emit('connected', user.userId, user.userName);
this.em.emit('initialiseUser', user.userId, user.userName);
So where i have the res.cookie is where i want to be able to read and write cookies, any help is appriciated
I think what you are looking for is the middleware pattern employed by express. You can define as many of these middleware calls as you wish, and they are the perfect scope for calling any other functions which may need the res instance (or the req instance for that matter).
app.use(function (req, res, next) {
// call function, passing in res here
next();
})
Reference: https://expressjs.com/en/guide/using-middleware.html
EDIT:
This answer is not correct for your situation. In a node/express server not using socket connections, then yes, you could easily use the above pattern anywhere you need the request and response objects in scope.
However, once you setup the socket io server, the game changes. During the socket communications, there are no express request and response objects in scope anymore, everything is handled directly between your socket handling code and the client. So the answer is you need to handle the situation in a socket io way, not in an express way.
Please see: Adding a cookie value on Socket.IO

Categories

Resources