How can i secure my api endpoint when there is no users registration - node.js

I have front end page - contact us - where every user can fill up the form and contact us.After that the filled form is send to our email. Because on our web site, there will not be user registration, so possible client can contact us but he will not need to sign up to visit our web site because it is not "friendly".
I always secured my web api with json web token, so i see if the user is registered in our db so he can have access to some api routes or not. But because this time there will be no DB with users, how can i secure my api endpoints ?
For example: malicious user comes to my website, he can see in the network tab the post request that is made for sending the email.
He can go in postman, and he can make thousands of request if he wants to my api endpoint and it will make me a problems because he is not filling the form on the frontend page, but maybe he will ping my endpoint very often with pre-made body post maked object in postman.
How can i prevent this things without user authentication ?

So the only way that i found until now is to check the origin - from where the request is coming. We can write a middleware at the beggining of our .js file before all other routes and check that
const express = require('express');
const router = express.Router();
const helpers = require('../utils/helpers');
router.use(helpers.checkOrigin);
router.post("/sendemail", async (req, res) => {
...
})
helpers.js file
const checkOrigin = (req, res, next) => {
console.log("checkOrigin", req.headers.origin);
if(req.headers.origin == "www.yourdomain.com") {
next();
} else {
res.status(403).json({error: "Unauthorized"});
}
}
in the
console.log("checkOrigin", req.headers.origin);
when we send request from postman then it prints undefined so it goes to the else block
but if the request comes from www.yourdomain.com then it will go in the if block, execute next middleware and accept request from all routes below including - sendemail.
If anyone has other solutions and better please let me know !

Related

Single user is being logged in across all devices

I was building a project on node.js recently, I came across this bug of user authentication. The problem is that after I log in from one account, if at the same time I refresh the home page of the website from another device, it redirects to the dashboard of the first user account. In other words, a single user is getting logged in on all the devices over the network. If suppose I don't refresh the page, and I log in normally on the application, it works fine. This problem is happening, both on the localhost as well as after hosting it on Heroku. Technologies used- node.js for handling back-end views and URLs. HTML, CSS, JavaScript for the front-end. Firebase for the database and authentication. Here is the code for the login part-
const express = require("express");
const path = require("path");
//Create Router Object.
const router = express.Router();
//Main Login Page (GET)
router.get("/", (request, response) => {
response.sendFile(path.resolve("./views/html/login.html"));
});
//Main Login Page (POST)
router.post("/", (request, response) => {
let email = request.body.email;
let password = request.body.password;
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.NONE);
firebase.auth().signInWithEmailAndPassword(email, password)
.then(r => {
let user = firebase.auth().currentUser;
if (user.emailVerified)
response.redirect('/dashboard');
else
response.send("<h1>Please Verify your email address.</h1>");
})
.catch(error => {
console.log(error);
response.send("<h1>Invalid Credentials</h1>");
});
});
Please can someone help me by resolve this bug in my project?
Calling firebase.auth().signInWithEmailAndPassword(email, password) signs the user in on the location wherever you call this code. Since you run this in an express.js app in Node.js, the user is signed in to that Node.js process, until you sign them out again. This is why the Firebase Authentication SDK you are using is only meant to be used in client-side applications, where this behavior is working as intended.
When integrating Firebase Authentication in a server-side process, you should use the Firebase Admin SDK. This Admin SDK has no concept of a currently logged in user, and no signInWithEmailAndPassword. Instead, if you need to know the identity of the user accessing the server-side code, you'll:
Sign the user in in their client-side app with the Firebase Authentication SDK.
Get the ID token for that user on the client, and pass that with your call to the server.
On the server, verify that ID token, to ensure the user is who they claim they are.
Then use the information on the user's identity to determine if they're authorized to access the information.
For more on this, see the Firebase documentation on verifying ID tokens.

how to verify a firebase admin on backend

I'm trying to implement middleware in an express server that sets custom uid/admin headers on the incoming request. This modified request will then be used after the middleware to see if an authenticated user/admin is accessing that particular resource.
To do this for a client, I just grab the token on the Authorization header and feed it into the firebase admin api's verifyIdToken method. If a uid exists, I set the header. For example:
app.use((req, res, next) => {
/* get rid of headers sent in by malicious users. */
delete req.headers._uid;
try {
const token = req.headers.authorization.split(' ')[1];
_dps.fb_admin.auth().verifyIdToken(token).then(claims => {
if (claims.uid) { req.headers._uid = claims.uid; }
next();
}).catch(err => next());
} catch(err) { next(); }
});
Two questions:
1) As an admin with a service account on another server, how would I send a request to this server such that this server can determine an admin sent the request?
2) How would I identify the admin on this server?
You will need to create your own custom Firebase token to include custom fields such as isAdmin: true in the JWT. See https://firebase.google.com/docs/auth/admin/create-custom-tokens
See (1)
Use the setCustomUserClaims() API to add a special "admin" claim to all admin user accounts, and check for it when verifying ID tokens. You can find a discussion and a demo of this use case here (jump ahead to the 6:45 mark of the recording).
Perhaps a solution would be to simply generate an API key of decent length and set it as an environment variable on each of my servers. I could then send this in the Authorization header whenever i want to make an admin https request and verify it in the middleware of the receiver by doing a simple string compare. The only people that could see this API key are those that have access to my servers (AKA admins). Let me know if something is wrong with this approach. It sure seems simple.

Stripe webhook POST route does not have req.user

I am testing Stripe webhooks locally using ngrok, so that the webhooks can be sent to an endpoint on localhost.
I want to test saving customer and payment information to my database, however, it seems like the middleware isn't attaching req.user (set by Passport) like it is on any other route. This makes it a lot less convenient in terms of accessing the authenticated user.
I could do the database work on the routes where I receive a Stripe token, but the bulk of useful information is sent as a webhook. Another option is to save the charge id or customer id at that stage, and then to look up the user at a later stage, but again this seems like unnecessary work.
I'm a little confused as to why this is, unless I'm missing something super obvious.
router.post('/stripe/webhook', (req, res) => {
console.log(req.user); //undefined
res.sendStatus(200);
});
You can find the detail of Stripe webhook mechanism here
You need to parse the body of the request which is holding the payload JSON
Example receiving endpoint :
app.post("/my/webhook/url", function(request, response) {
// Retrieve the request's body and parse it as JSON
var event_json = JSON.parse(request.body);
// Do something with event_json
response.send(200);
});
You can test the your receiving endpoint by test JSON which you can found in Event API of Stripe! And you send test JSON using many app like POSTMAN
(having also a chrome app)

How to programmatically login to Facebook oauth2 api

Background:
I have written a Node.JS script that successfully connects to the Facebook Graph API through my facebook app. I can read data when I give it an oauth access_token, I want this script to run on my server every night to store some data. I have done a lot of research of both the facebook api, oauth and similar questions on stack overflow. I am searching the /search/?type=event&q=query endpoint
Problem:
However, Facebook returns a 60 day access_token through the oauth2 login process that required me to create an express server that simply initiates the oauth2 process, allows the user to login, and receives the access_token code and I am storing it.
I want the script to save data so that my server can provide access to updated data every day. I don't want to have to remember to login to generate the key once every 60 days.
Question:
Is there anyway to receive a oauth2 access_token without setting up an http or express server?
More importantly, how do I get the access_token without manually having to running that server every ~60 days.
Code:
The Module I am using requires the access_token and client_secret
fs.readFile('./facebookAuthServer/oauth.txt', function read(err, data) {
if (err) {
throw err;
}
fbNode.setAuthorization({token: data, clientSecret: authSettings.clientSecret});
// Use the auth for next call
fbNode.fetchItems(displayItems);
});
Is there some way to spoof headers? or could I use a short lived access token and refresh it? Anyway to refresh a 60 day token? Has anyone created a server side implementation of Oauth2 that does not require visiting the FB login more than the first time?
Here is how you can refresh your own access token using Grant and request.
First you need an OAuth client server up and running:
var express = require('express')
var session = require('express-session')
var Grant = require('grant-express')
var grant = new Grant({
server:{host:'dummy.com:3000', protocol:'http'},
facebook:{
key:'[APP_ID]',
secret:'[APP_SECRET]',
scope:['user_about_me','user_birthday'],
callback:'/callback'
}
})
var app = express()
app.use(session({secret:'very secret'}))
app.use(grant)
app.get('/callback', function (req, res) {
res.end(JSON.stringify(req.query))
})
app.listen(3000, function () {
console.log('Oh Hi', 3000)
})
Next you need an HTTP client that will simulate the browser request:
var request = require('request')
request.get({
uri:'http://dummy.com:3000/connect/facebook',
headers:{
'user-agent':'Mozilla/5.0 ...',
cookie:'datr=...; lu=...; p=-2; c_user=...; fr=...; xs=...; ...'
},
jar:request.jar(),
json:true
}, function (err, res, body) {
if (err) console.log(err)
console.log(body)
})
How you use it:
Register OAuth app on Facebook and set your Site URL (I'm assuming http://dummy.com:3000)
Add 127.0.0.1 dummy.com to your hosts file
Configure and start the server from above
Navigate to dummy.com:3000 in your browser
Open up the Developer Tools and navigate to the Network tab, make sure Preserve log is checked
Navigate to http://dummy.com:3000/connect/facebook and authenticate as usual
Take a look at the authorize request in the Network tab and copy the relevant headers to the HTTP client example (the user-agent and the cookie)
Run the HTTP client code (that's the code you are going to execute from time to time, the server should be running as well)
Resources:
Introduction about how to use Grant
Grant documentation
Request documentation - see the options section
Module:
I wrapped the above code into a module https://github.com/simov/facebook-refresh-token
Start with reading the docs, it's all described there, instead of guessing:
https://developers.facebook.com/docs/facebook-login/access-tokens
https://developers.facebook.com/docs/facebook-login/access-tokens#refreshtokens
https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.4#login
It's somehow a pity that you don't write WHAT you want to query via the Graph API, because depending on that you could either use a non-expiring page access token or an app access token, which also doesn't have to be renewed, instead of an user access token.
There's no way to automatically extend the long-lived access token. The user must visit your app again.

Phonegap + Hello.js (server side authentication)

I have a Phonegap application that is communicating with Nodejs server.
Also for the Facebook\Twitter login I'm using Hello.js library (which is very easy to use by the way).
Unfortunately this library only makes client side login (authentication), so at server side I don't know if the user is valid or not (have been looged in with Facebook\Twitter).
Edit:
After the user is logged in (client side), Hello.js provides the user credentials, with a Facebook unique user ID, but I don't know how to pass it safely to the server, or generally if its a good idea to use it as a user id in my DB.
I'm looking for a simple example that will check the validity of the login at server side too.
Thanks.
If you are using https then sending the id to your server will be fine. What you can do is just check to see if that unique id already exists in your DB and return that users data (if needed) or create a new account.
I would also recommend creating a JWT (JSON Web Token) on the server side and sending that back to the app to be stored in local storage and used to validate all future requests to your node server. You can implement that method pretty easily if you use the jwt.verify method as middleware on all of your routes.
Here is a quick example:
var jwt = require('jsonwebtoken');
var jwtValidation = function(req, res, next) {
var token = req.body.jwt_token;
if (token) {
jwt.verify(token, 'yourSecretKeyHere', function(err, decoded) {
if (err) {
// Error when checking JWT - redirect to unauthorized
res.redirect('/unauthorized');
} else if (decoded.id) {
// Token that was passed in has been decoded
// Check your DB for the decoded.id
// Complete any other needed tasks then call next();
next();
} else {
// Something else went wrong - redirect to unauthorized
res.redirect('/unauthorized');
}
});
} else {
// No token present - redirect to unauthorized
res.redirect('/unauthorized');
}
};
module.exports = jwtValidation;
This is the main idea as I figured:
In the Phonegap application, after the user has logged in, this function will be called:
hello.on('auth.login', function(r){
var token = r.authResponse.access_token;
}
now, you can send only the token to the server, and the server will get the user credentials directly from Facebook.
For example, in Facebook, call this usr:
https://graph.facebook.com/me?access_token={token}

Resources