Prevent users from accessing subdomain in Express - node.js

I am very new to web development and Node.js / Express. I have an Express server. In my client I send a GET request for some data in the DB. The GET request is handled by
app.get( '/pathname', controller.getsomedata );
The problem is, the user can now type in the URL domainname.com/pathname in the browser and get directed to that pathname. If they add in a certain queries domainname.com/pathname?query, they are able to retrieve data from the DB (this is supposed to happen), but I would prefer if GET requests to /pathname only occur from within the client code, not when the user enters it in the browser.
Is there a better way to do my GET request? Or is there a way to restrict users from accessing /pathname.
I apologize for the newbie question, but I don't know how to word it well enough to do a google search for the solution. Thank you!

It's impossible to do that. If your client-side code is able to access something, malicious user can do that as well.
You can mitigate the issue by using custom HTTP header or something like that, but it's better to validate all data on the server-side.

Allow whole client request as DB query may cause security issues. So be sure to validate query parameters and use them as DB query conditions.
If you want to query DB freely from HTTP query parameter, you should prepend authentication/authorization to the route.
app.get( '/pathname', function(req, res, next) {
if (confirmThisRequestIsFromMe(req)) {
next();
} else {
res.send(401);
}
}, controller.getsomedata );

Related

How to structure external API calls for Node.js, express, ejs routing?

//API Call one
function receiveLocation(){
axios({
"method":"GET",
"url":"https://ip-geo-location.p.rapidapi.com/ip/check",
...
})
.then((response)=>{
return response.data.country.name;
})
.catch((error)=>{
console.log(error)
})
}
//API Call two
//API Call three
console.log(receiveLocation());
app.get("/", function(req,res){
var location = receiveLocation();//
//Then render all the data from my API calls such as location, currency,
//etc. in my landing page. Also use that data on the backend.
res.render("landing",{location:location});
});
I am currently trying to make a website that uses multiple API calls to get information such as location, currency, and other things of a user who loads the website.
I am attempting to receive all the information from the different API calls as I go through the get request route that allows a user to see the landing page. Firstly, I am not even sure if this is allowed. If it is allowed/standard practice, what am I doing wrong in this example. I am attempting to call a function that in the get route to the root page that returns the country of a visiting user. But after doing some console.log() debugging I see that that information is never being received in the get route. Last note: I want to use the info from the API calls both to change what the user sees, and for some calculations that would need to be run on the backend.
If this is not allowed/not standard practice, may someone explain what I should do instead/point in the right direction as to what I should learn to get a better understanding of what I am trying to do
What you are trying at the moment to do is not standard practice, you should lookup MVC for Express,there you will learn how to structure your backend code so that the GET Routes will be used as Views ( these will be your server getting some public files like html,css,javascript that will be passed some information from the Controllers,this is done by using some server-side renders like EJS).
I recommend taking this Udemy course https://www.udemy.com/course/nodejs-the-complete-guide/ for a full understanding,but if you don't have the time,lookup node.js mvc with express, there is plently information about this.

Best way to handle API calls from frontend

Okay, so atm i have a frontend application built with Nuxt JS using Axios to do requests to my REST API(separate).
If a user does a search on the website the API URL is visible in XMLHttprequests so everyone could use the API if they want to.
What is the best way of making it so that only users that search through my website gets access to the API and people that just directly to the URL gets denied. I suppose using some sort of token system, but what is the best way to do it? JWT? (Users never log in so there is no "authentication")
Thanks!
IMO, you CANNOT block other illegal clients accessing your
backend as you describe that the official client and other illegal have the same knowledge about your backend.
But you can make it harder for illegal clients to accessing your backend through some approach such as POST all requests, special keys in header, 30-minutes-changed token in header and server-side API throttling by client IP.
If the security of the search API is really important, authenticate it by login; if not, just let it go since it is not in your critical path. Let's focus on other important things.
I'm in the same "boat" and my current setup is actually in VueJs but before even come to StackOverflow I developed a way to actually, the frontend calls the server and then the server calls the API, so in the browser, you will only see calls to the server layer that, the only constraint is that the call must come from the same hostname.
backend is handled with expressJs and frontend with VueJs
// protect /api calls to only be originated from 'process.env.API_ALLOW_HOST'
app.use(api.allowOnlySameDomainRequests());
...
const allowHostname = process.env.API_ALLOW_HOST ||'localhost';
exports.api = {
...
allowOnlySameDomainRequests: (req, res, next) => {
if(req.url.startsWith('/api') && req.hostname === allowHostname) {
// an /api call, only if request is the same
return next();
} else if (!req.url.startsWith('/api')) {
// not an /api call
return next();
}
return res.redirect('/error?code=401');
},
...
};
In our case, we use Oauth2 (Google sign through passportJs) to log in the user, I always have a user id that was given by the OAuth2 successful redirect and that user id is passed to the API in a header, together with the apikey... in the server I check for that userid permissions and I allow or not the action to be executed.
But even I was trying to find something better. I've seen several javascript frontend apps using calls to their backend but they use Bearer tokens.
As a curious user, you would see the paths to all the API and how they are composed, but in my case, you only see calls to the expressJs backend, and only there I forward to the real API... I don't know if that's just "more work", but seemed a bit more "secure" to approach the problem this way.

Submitting a Form Action Post for API, do I need a post route?

I am using the npm "twit" and it is ultimately posting Twitter Status Updates. I have the user fill out a form and the action of the form is a post request to a path like home/tweet/.
In my express router I have a route home/tweet/. The Form data isn't really being posted there though, the reason I am doing this is because I am extracting the form fields qith req.body and then inside the router I am making the post request to Twitter to create a new tweet. Here is what it looks like:
router.post("/tweet/", function(req,res){
var tweet = req.body.tweet;
Twitter.post('statuses/update', { status: myFuncs.encode(myFuncs.key, tweet) }, function(err, data, response) {
});
res.redirect('/');
})
Even though this works, it feels a little hacky to me. Is there a better way to design this? Is there a better way to extract the Form Fields without using a post request using req.body, or a get request using req.query?
Although, I agree that it seems "hacky"---as you put it---but unfortunately, since Twitter has not enabled CORS on its API, you have no choice but to use an intermediary, such as your server. Alternatively, you may use a third-party service, but that still is an intermediary just like your server.

NodeJS - Not being able to access the route I want

I'm having some troubles getting to a route I got. The route works on http://localhost:3000/me and shows info but on http://localhost:3000/!#/me it doenst show anything. The purpose of said route is to show the logged persons' profile.
On my server routes I got:
app.get('/me', users.me);
The users.me function is as follows:
exports.me = function(req, res) {
res.jsonp(req.user);
};
The console states it expected a object and got an array, I can understand that since I'm getting a json, but how can I send the own user back to the front-end so it shows his/her profile?
Edit: I managed to solve my problem, since I use passportjs I can get the user id from the session. Since I already had a route for a user by id, I simply had to redirect to said route. Like this: req.redirect('users/'+ req.session.passport.user);. Since I already had a /users/:userId route working it completely solved my issue.
Edit2: Apparently there are several ways to get the user id. Try to console.log the request and you will see what I mean :)
/me and /!#/me are not the same route . The later won't match get('
/me',..)
the hash fragment #/me will not send to the server, you cannot capture that by server side routers(without force the page refresh by client code). But you can manage that by client-code.

How to avoid sessions until logged in within Express

I cannot seem to figure a way to prevent Express/Connect to create sessions until I have a valid log in from the user.
The problem especially arises when using a DB-Backed Session Storage and calling the REST Services from non-browsers as in such cases, the Connect Session Object will create a new Session for each request which I do of course want to prevent.
However, I do need sessions whenever the user is authenticated as I am using Passport.js for authentication which requires sessions as well as I do require it to load session data from sent cookie information.
Looking at the source of the Connect Session Code, it seems it is always creating a new Session if none got sent from client without any option to prevent it..?
thanks
Alex
If you can easily identify calls to your API at query time you could do something like this:
app.use(function(req, res, next){
if ( req.path.indexOf("/api") == 0 ) return next();
else return express.session()( req, res, next );
});
This way the session middleware is only included if the request URL doesn't match some condition. I haven't tried this in anger though, so you might want to consider initialising express.session() outside the function, and make sure there aren't any other repercussions.

Resources