I'm making a webgame, and if I have a route that looks like:
app.post('/create_account', (req, res) => {
var email = req.body.email
var pass = req.body.pass
res.json({response: "created"})
})
Anyone can post data to mywebsite.com/create_account using postman, or curl or something, and my website will start creating account for them even though they are not even on my webpage.
I found an interesting workaround, and I wanted to know if this is safe, or even a good idea. Basically I wrap my app routes within a socket.io connection:
io.on('connection', function(socket) {
app.post('/create_account', (req, res) => {
//code goes here
})
})
I tested it, and it seems that this way you can only post to /create_account if you are actually connected to the webpage.
What (if any) are the disadvantages to doing this? If this is a bad idea, whats's a better way to prevent people from posting data if they aren't on my site.
#Ruslan's suggestion about CSRF tokens is sound and probably your best option, wrapping everything in socket.io seems like too much complexity. Here's a library that does that: https://github.com/expressjs/csurf
Related
Using Express with React on the front end, and want to hide the request payload, but couldn't figured it out how to do it.
it looks like the below image
backend code sample:
router.post('/fit_spend', (req, res) => {
const {avg_unit_price,
brand,
budget,
isDev,
path,
period,
showEnv}= req.body;
...
})
any help please?
I can't make comments yet, but I think the best way to handle this is to make sure a user is logged in and make your call a protected route. As other users have said, you can't control the client side of things.
I have a challenge I'm running into and cannot seem to find an answer for it anywhere on the web. I'm working on a personal project; it's a Node.js application that uses the request and cheerio packages to hit an end-point and scrape some data... However, the endpoint is a Facebook page... and the display of its content is dependent upon whether the user is logged in or not.
In short, the app seeks to scrape the user's saved links, you know, all that stuff you add to your "save for later" but never actually go back to (at least in my case). The end-point, then, is htpps://www.facebook.com/saved. If, in your browser, you are logged into Facebook, clicking that link will take you where the application needs to go. However, since the application isn't technically going through the browser that has your credentials and your session saved, I'm running into a bit of an issue...
Yes, using the request module I'm able to successfully reach "a" part of Facebook, but not the one I need... My question really is: how should I begin to handle this challenge?
This is all the code I have for the app so far:
var express = require('express');
var fs = require('fs');
var request = require('request');
var cheerio = require('cheerio');
var app = express();
app.get('/scrape', (req, res) => {
// Workspace
var url = 'https://www.facebook.com/saved';
request(url, (err, response, html) => {
if (err) console.log(err);
res.send(JSON.stringify(html));
})
})
app.listen('8081', () => {
console.log('App listening on port 8081');
})
Any input will be greatly appreciated... Currently, I'm on hold...! How could I possibly hit this end-point with credentials (safely) provided by the user so that the application could get legitimately get past authentication and reach the desired end-point?
I don't think you can accomplish that using request-cheerio module since you need to make a post request with your login information.
A headless browser is more appropriate for this kind of project if you want it to be a scraper. Try using casperJs or PhantomJs. It will give you more flexibility but it's not a node.js module so you need to make a step further if you want to incorporate it with express.
One nodeJs module I know that can let you post is Osmosis. If you can make .login(user, pw) to work then that'll be great but I don't think it can successfully login to facebook though.
API if possible would be a much nicer solution but I'm assuming you already looked it up and find nothing in there for what you are looking for.
My personal choice would be to use an RobotProcessAutomation. WinAutomation, for example, is a great tool for manipulating web and scraping. It's a whole new different approach but it can do the job well and can be implemented faster compared to programmatically coding it.
For example, I have a REST api endpoint written in Node.js. It can be accessed from a webpage for non-technical users, and it can also be accessed through command line using the curl command. It doesn't require any credentials to access it because it is intended to be open for anyone to access it. The problem I am trying to solve is how can I prevent someone maliciously access this REST API endpoint, for example pinging this api endpoint over and over again, or how to prevent ddos attacks.
Not necessary a programming question, let me know if there is a better place to ask this.
Setup Rate Limiting if you cant have an auth on it.
You can use this if you are using express https://www.npmjs.com/package/express-rate-limit
Preventing DDOS is not that easy without using solutions like CloudFlare.
To secure your REST api, you can use middleware if you use express
const checkAuth = (req, res, next) => {
// logic for checking auth
if (authorized) {
return next();
}
res.status(401).send('NEED AUTH');
};
router.post('/login', checkAuth, (req, res, next) => {
// actual logic for login
});
Update: regarding #Akarsh's answer,
you can use multiple middleware before actual logic. For example, one for auth check, and one for rate limit
router.post('/logic', checkAuth, rateLimit, (req, res, next) => {});
You say you want it to be open, but then you say you want it to be sort of open!
Throttling / auth tokens. Choose at least one, pref both.
Pinging and DOS attacks are different and have nothing to do with your API as such. Unless your info is valueable / highly competitive, something as simple as IP banning will go a long way.
I'm working on my first project and would like to know if socket.io is the only or the best solution to connect my UI to node.
Is there anything else you could recommend me? Real-time is not important, I just want to access my data. Simple keywords would already help me a lot.
Thank you!
GT
It is pretty straightforward:
Make sure your node.js server returns (JSON) data on certain calls, e.g.
//this is your API endpoint
app.use('/api/endpoint', (req, res, next) => {
res.send({
key: 'value'
});
});
//this sends your html file with react bundle included
//has to be placed after the api handling
app.use('*', (req, res, next) => {
res.sendFile(path.join(__dirname, 'public', 'index.html'));
});
You don't have to serve your html with the same server, but it normally makes sense.
Now, you can make API calls inside your React app to fetch the data. I like to use axios (https://github.com/mzabriskie/axios), but you can make the calls however you want.
You should make the call and save it somehow, either in state or in your store if you use redux.
E.g.:
...
componentDidMount() {
axios.get('http://yourserver.com/api/endpoint')
.then(function (response) {
this.setState({
data: response.data
});
})
.catch(function (error) {
console.log(error);
});
}
...
Sending Data to your node server to store it in a DB is pretty similar.
Please note, that this is just a basic example, you will encounter some issues along the way, especially when you go to production, such as CSRF protection or JWT for securing your API. However, this should get you started!
So what I'm trying to do is when someone loads my site, and gets authenticated by passport, their userId is stored in req.user.id in my app.get('/home', funciton(req, res). Now what I am trying to do in a way is this:
app.get('/home'. function(req, res){
io.on('connection', function(socket){
socket.emit('userId', req.user.id);
});
}
Thats essentially what I'm trying to do, but I know it is very wrong. Now my question is how can I get the req.user.id to the client so I can use it in future interactions with the server.
Looks like you're receiving a GET request and using Express right? You're probably passing the userid in the querystring, so you'll want to use:
req.query.userid
This basically pulls the value assigned to a key in the querystring.
Source: http://expressjs.com/en/api.html#req.query
I would also recommend sending something like ?userid=12345 in the querystring, rather than an object (user.id) in the querystring, as encoding an object will unnecessarily add more complications and not needed.
You can use express session with socket.io
There's a npm module called express-socket.io-session