I want to host a web app with node.js on a Linux virtual machine using the the HTTP module.
As the app will be visualising sensitive data I want to ensure it can only be accessed from PCs on the same LAN.
My understanding is that using the HTTP module a web server is created that's initially only accessible by other PCs on the same LAN. I've seen that either by tunnelling or portforwarding a node.js server can be exposed if desired.
Question
Are there any other important considerations/ways the server could be accessed externally?
Is there a particular way I can setup a node.js server to be confident that it's only accessible to local traffic?
It really depends what you are protecting against.
For example, somebody on your LAN could port forward your service using something like ngrok. There are a few things you can check for:
In this case the header x-forwarded-for is set. So, to protect against this you can check for this header on the incoming request, and if set you can reject the request.
The host header is also set and will indicate how the client referred to your service - if it is as you expect (maybe a direct local LAN address such as 192.168.0.xxx:3000) then all is OK, if not (I ran ngrok on a local service and got something of the form xxxxxxxx.ngrok.io) then reject it.
Of course a malicious somebody could create their own server to redirect requests. The only way there is to put in usernames and passwords or similar. At least you then known who is (allegedly) accessing your service and do something about it.
However, if you are not trying to pretect against a malicious internal actor, then you should be good as you are - I can't think of any way (unless there is a security hole in your LAN) for your service to be made public without somebody actively setting that up.
My last suggestion would be to use something like express rather than the http module by itself. It really does make life a lot simpler. I use it a lot for just this kind of simple internal server.
Thought I'd add a quick example. I've tested this with ngrok and it blocks access via the public address but works find via localhost. Change the host test to whatever local address (or addresses) you want to serve this service from.
const express=require('express');
const app=express();
app.use((req,res,next)=>{
if (req.headers.host!=='localhost:3000' || req.headers['x-forwarded-for']){
res.status(403).send('Invalid access!');
} else next();
});
app.get('/',(req,res)=>res.send('Hello World!'));
app.listen(3000,()=>{
console.log('Service started. Try it at http://localhost:3000/');
});
I would prefer using nginx as a proxy here and rely on nginx' configuration to accept traffic from local LAN to the node.js web server. If this is not possible, a local firewall would be the best tool for the job.
Related
I'm still new to Node, so what I'm asking may not work the way I'm wanting to, but, here is my dilemma.
I have a website which has an old data collector (which I did not write) collecting data. I wrote a Node app that mimics the old data collector so that it can be replaced. But now that it's ready for testing, how do I point the Node app towards the website and not localhost? The Node app is going to be hosted in a secure server.
When I would test in Postman I would test the functionality for, say, the 'id' endpoint by checking
localhost:3000/id
but now I want is when a user on the website goes to an address such as
www.myexample.com/id
The code in my Node app will run. And I may be wording this wrong, but basically if one of the endpoints is hit, I want Node to run the code for that endpoint.
The code for my endpoints is along these lines:
router.post('/id.json', function (req, res, next) {
//do the things
}
Is there a way to have Node work this way with an external website? I've checked, but haven't come across anything that would work for this particular issue. I'm using Express and I've tried changing my app.listen, to
app.listen('www.example.com')
but I'm getting errors from there, so I'm not sure if I'm not using proper syntax or if this simply isn't what app.listen was intended to do. Ultimately, what I'm wanting to do is have the Node app work the same way with the website as it would with localhost.
You can't take any site name by just "listening" to it with node app. When user in the Internet goes to www.myexample.com/id, the url is resolved into ip address and user's browser connects to a server (physical machine) that is running on that ip address. This server then accepts the connection and serves the website back to user. If you own www.myexample.com domain name and the server this domain name points to, you should go to the server, take down whatever is hosting your current website and run your node app there. Your node app doesn't even know which website address it's being hosted on, all it cares about is accepting incoming connections and returning data. Also mind the port - http and https work on ports 80 and 8080 respectively (which are omitted in the url) and your node app, based on your description, is running on 3000
I would like to create a secure internal route between two applications within the same space/organization. It should never be possible to reach the Node.js application from the outside. My Java application connects via HTTP to the Node application (running on express).
I have now tried to setup the desired configuration by creating a route called example-route.apps.internal and assigned it to the Node application. As a next step, I've opened the port (I've tried 443, 80, 8080) in the network configuration of the Java application (with the destination being the Node app). I restaged both applications.
Then, I opened a Java connection to the link http://example-route.apps.internal/test123. I've also tried to use https. The result was the same. Java refused to conncet to this URL.
Now, the following questions:
How can I properly set up this communication? Should I resolve this internal DNS somehow? Which port is the correct one if I just use the port of the env variable? How should I read this port from the other application?
How secure is the communication, if HTTP is used instead of HTTPS? (I assume HTTPS is not possible internally). Is it as safe as an HTTPS connection from the outside? Which devices are between, how far out does the connection go?
Thank you!
I think you're almost there.
Then, I opened a Java connection to the link http://example-route.apps.internal/test123. I've also tried to use https. The result was the same. Java refused to conncet to this URL.
You should use http://example-route.apps.internal:8080/test123. Your app is set to listen on $PORT, which is always 8080 in current versions of CF.
Normally you don't need to worry about this because your traffic goes in through Gorouter which translates for you (maps external port 80 -> internal 8080). With internal routes, traffic is direct so there is no transformation. That's why you need to use port 8080 in your URL.
Alternatively, you could use a service discovery mechanism like Eureka or Consul, but it's not a requirement. In this case, the service would know it's listening on 8080 and register that in the registry.
As far as HTTPS, that's tricky. Your app is only listening on 80/HTTP. You would have to change it to listen on 443/HTTPS, but then you need certs and different server configuration. It's technically possible, but it's a whole can of worms.
In some newer versions, Envoy is present and accepts HTTPS traffic into a container, can make HTTPS easier but it's still not a slam dunk (at the time of writing, at least). I expect this will get better in the future.
Should I resolve this internal DNS somehow?
Internal DNS helps with locating your other apps, not the port. Otherwise you'd need to manage IP addresses, which change often, and that would require something like Eureka or Consul.
Which port is the correct one if I just use the port of the env variable?
See above.
How should I read this port from the other application?
It's always 8080 at the moment, and has been for multiple years. It's unlikely to change, so you could probably hard code or set it in a config file safely.
How secure is the communication, if HTTP is used instead of HTTPS? (I assume HTTPS is not possible internally).
Is it as safe as an HTTPS connection from the outside? Which devices are between, how far out does the connection go?
Traffic would not be accessible externally as it wouldn't leave the Cell in some cases or worst case it goes between two Cells, but traffic would be visible internally since it's not encrypted. That means you need to have more trust on your CF provider, who would have access to internal traffic.
If it were HTTPS, only someone with the key would be able to decrypt it. You would still have to trust your provider though as they could likely get the key & use it to decrypt traffic. It would just be more work for them than if traffic is unencrypted.
Hope that helps!
I'm using node js trying to send my web-page to my network, I successfully call localhost:port in my computer using express as server, the webpage loads fine trigger my webcam which I used to streaming in the webpage, and then im working to make a simple app in my phone to directly access my server, so my questions:
1.How do I able to access my server from different devices in the same wireless-network? by calling ip + port ?192.168.1.104:9001 ? cause i've tried and it didnt work.
2.I've found https with .pem something like that, is that the answer ? is there also any other way ?
3.maybe any advice before i work to make my web-app to devices? using koa? i don't even really know what is that, but i'm happily take any advices.
EDIT: i've read How could others, on a local network, access my NodeJS app while it's running on my machine?
let's say I simply using random router, so i can't configure my router-port, my server in my pc and my phone join in the same network, trying to access the server in my phone
1.How do I able to access my server from different devices in the same wireless-network?
All you need to do is find your server's IP address in this same wireless-network, and find the Node.js application's port. Then access the following URL in other devices:
http://{server_IP}:{port}
However, there are some points need to check:
Need to check firewall and confirm the port is not blocked, server IP is not blocked by test device, and test device IP is not blocked by server.
Need to check whether there is any Proxy setting in server and test device. If there is any, disable the proxy.
A computer may have many IP addresses at the same time, you need to find the correct one in the same wireless-network. For example, If you install a virtual machine software such as VMware and run a virtual system inside, your real computer will get IP address as 192.168.*.* -- this IP address looks like an intranet IP in wireless-network, but it is not, and can never be accessed by test device.
2.I've found https with .pem something like that, is that the answer?
No, HTTPS has nothing to do with this problem. HTTPS just add security (based on HTTP layer), it does not impact any HTTP connectivity. Actually, to minify the problem, it is better to only use HTTP in your scenario.
There is only one very special case that may bring your problem by HTTPS -- the test machine is configured and will block any non-HTTPS connection for security.
3.maybe any advice before i work to make my web-app to devices? using koa?
My suggestion is: As there is an HTTP connectivity issue, the first step is trying to find the root cause of that issue. Thus, it is better to make a simplest HTTP server using native Node.js, no Koa, no Express. In this way, the complexity of server will be reduced, which makes root cause investigation easier.
After the HTTP connectivity issue is fixed, you can pick up Koa or Express or any other mature Node.js web framework to help the web-app work.
4.let's say I simply using random router, so i can't...
Do you mean your server get dynamic IP address by DHCP? As long as the IP is not blocked by test device, it does not matter.
If you have any ideas about the possibility of allow my friend to access my node.js web page by browser from her computer .. she lives out side my town i tried one method which is
var http = require('http'); http.createServer(function(req, res){ res.writeHead(200, {'content-type': 'text/plain'}); res.end('It works'); }).listen(3000, '0.0.0.0'); //listening all interfaces
it works correctly but with the computer which locate on the same LAN network
You could to configure your router to allow in route to your server port.
If you have a fix IP, you don't need more things. If your IP vary along the days, you can to configure your router to use a dynamic IP.
I use https://www.dtdns.com/, a free dynamic dns provider, to allow an external URL to access my home "server" (a Raspberry PI).
But, already, it starts at configure your router, or, also, using the tunnel listed after, by I believe configuring your modem it's more fast to access (more kb/s) than using tunnel.
Better to have Linux based operating system
Write NodeJS app (or download ready one somewhere)
Install Nginx - This app will reply and handle all incoming connections
Install Phusion Passenger (Free version) - This app will make sure your NodeJS application is up and running
Copy your application to /var/www/yourappname on Linux and ~/Sites on Mac
Configure Phusion Passenger
If you have fixed (static) IP-address - you're good to go. Just type your static address and port (if different from :80) into browser
If you have dynamic IP-address - You will need a service called Dynamic DNS, I can recommend this one but is is paid service. I'm sure after a bit of Googling you can find a free similar service
If you're doing this - first time, it may looks a bit tricky and can take a day or two. But after few server setups - you will be able to do same operations with closed eyes.
Is there any way to run Ghost on a subdomain using Node.JS? I am able to run it normally on Node.JS like:
App.Modules.Ghost = require('ghost'); /**< Ghost module. */
App.Apps.Ghost = App.Modules.Ghost({ config: '/Assets/Ghost/Config.js'.LocalFilePath }); /**< Create Ghost app. */
Then, I am then able to go to http://example.com/ghost/ and view my blog. Although this works for now, I want to be able to view my blog at http://blog.example.com/ using Node.JS.
Sadly, the way networking works prevents this in the context you desire. In order to achieve that sort of functionality, you would need a proxy server to go in front of the entire application. I would suggest NginX for this ability, due to its speed and wide-spread use.
Why is this not possible?
In this sense, networking is the system where you bind to an IP and a port. When you bind, nothing else can bind to that same IP/port. Since a domain (and subdomain) simply point to an IP address, there is no way that you can separate these connections at the networking level. This is why the Host HTTP header was added.
How does NginX do it?
NginX parses the Host header and can send the connection to your Ghost server as you wish it to be forwarded to. This also allows you to forward the main domain (http://example.com) to whatever website you like, therefor using different applications and such on the same IP and port.
This answer contains the best directions on how to achieve this functionality.