Node.js and mongoose - prevent salt and password to return to client - node.js

I have a node.js app with mongoose. my problem is that when returning entities with populated user, the user data includes secure data like salt, tokens and password. I used the following method to prevent private data from going back to client:
User.methods.toJSON = function() { // Do not change to lambda expression
const SERVER_ONLY_PROPERTIES = ['tokens', 'salt', 'password'];
var user = this.toObject();
SERVER_ONLY_PROPERTIES.forEach(propKey => {delete user[propKey]});
return user;
}
Everything worked great, until I used the lean() function in my code.
when using lean the toJson method isn't being called and the private data returns to client. what are my options?

Instead of taking out the stuff that you don't want to return, you should instead have a process that builds a new object to return that explicitly includes only the necessary pieces of data. That's the best practice as far as security, if I'm not mistaken.

Related

How to verify a hashed secret without knowing the salt?

I store the API-Keys as hashes in a database.
...
async function createToken(userId:number) {
...
const salt=await bcrypt.genSalt(15)
const hash=await bcrypt.hash(token, salt)
await db.store({userId,hash})
}
async function verifyToken(token:string){
const userId= //I don't know the UserID since only the token is sent as HTTP header
const hashes= db.get(userId)
for(const hash of hashes) {
if(await bcrypt.compare(token, hash)) {
return true
}
}
return false
}
How do I verify the token validity without knowing the userID?
The only option I see is to loop through all DB records, and try if the produced hash for that record matches. But this results potentially in thousands of hashes checked before I find the right one.
I may reduce this to only the tokens belonging to a specific UserID. However, this would require my users to also send there userID which I don't want them to do.
Seems like you are using bcrypt hashes as token to authenticate the users, but that's not the actual purpose of such hashes. If you need to use a token, why not use something like JWT. It can hold the user information, and can be verified without a single db call.

createParamDecorator VS CanActivate in Nestjs for authorization

I'm trying to authorize users based on their permissions. Is there any difference in functionality between using createParamDecorator and CanActivate method?
export const GetUser = createParamDecorator((data: string, ctx: ExecutionContext) : User => {
const request = ctx.switchToHttp().getRequest();
const user = request.user;
const permissions = user.permissions
for(var i = 0; i < permissions.length; i++){
if(permissions[i].name === data)
return user;
}
throw new NotFoundException()})
These are absolutely not equivalent approaches, and should not be considered as such. The createParamDecorator is supposed to be an easy way to tell Nest how to inject a custom value (e.g. req.user instead of having to do #Req() { user }). It was never meant to be used for authorization, and while you can, it will most likely lead to very weird stack traces.
Guards, on the other hands, were made for authentication and authorization of the request. You can set metadata on a handler (e.g. what roles are allowed), read them with the Reflector, and then apply the conditional logic of if the request is valid or not. You're also able to use dependency injection on guards to add things like your database connection and get a full user from the database from an ID, which isn't possible in the createParamDecorator.
Lastly, in guards you can throw any error you want, or you can return false and get back a 403 by Nest's design.
Is there any difference in functionality...?
As mentioned, the dependency injection. It's also easier to test guards, in my opinion. But that's me.

Convert NodeJS asynchronous code to Spring Project Reactor

I have below NodeJS code:
// req and resp are http request, response objects
var uri = req.getURI()
var pageView = new PageView(uri)
var token = req.token
if (token) {
UserRepository.findByToken(token, function(notFound, user){
if(notFound) { // means user not found by specified token
var newUser = new User('John Doe')
user.foo = 'some value'
processUser(newUser, pageView)
} else { // user found by token
user.foo = 'some value'
processUser(user, pageView)
}
})
} else { // token does not exist
token = new Token('some value')
resp.setToken(token)
var newUser = new User('John Doe')
user.foo = 'some value'
processUser(newUser, pageView)
}
processUser(user, pageView) {
PageViewRepositiry.save(pageView, function(error, savedPageView){
if(error) {
throw 'error'
}
user.pageViews.push(savedPageView)
// save the modified savedUser
UserRepository.save(user , function(error, savedUser){
})
})
}
It uses Repository pattern as abstraction over database layer (same as the Repository pattern in Spring applications).
Basically it finds user by incoming token (from http req object). If user is found then updates user entity and adds the saved pageView entity and saves the modified user. If user is not found by token then it creates a new User, updates the user with saved pageView, saves the user.
How the same code will be written in Spring Project Reactor (Flux) ?
Is it possible to solve this problem without using block()? Ideally I would like a solution that does not use block().
First of all, you have some logic to generate a token if a token isn't present. For example:
private Mono<String> getToken(String token) {
return Mono
.just(token)
.switchIfEmpty(Mono.just("some token"));
}
In this case, it's a bit overkill to use switchIfEmpty for this, but I assume your process to generate a token is a bit more complex, otherwise you could have worked with Optional<String> in stead (eg. token.orElse("some token")).
Additionally, we also have some logic to either find the user by its token, or create a new user if there is no user by the given token:
private Mono<User> findUserByToken(String token) {
return userRepository
.findByToken(token)
.switchIfEmpty(userRepository.save(new User("John Doe", token)));
}
Now that we have these methods, we can create a PageView and use these methods along the way. The reason I start with creating a PageView is because that's the first "constant" in the entire token, regardless of whether there is a token/user found:
return Mono
.just(new PageView(uri))
.flatMap(pageViewRepository::save)
.flatMap(pageView -> getToken(token)
.flatMap(this::findUserByToken)
.doOnNext(user -> user.setFoo("foo"))
.doOnNext(user -> user.getPageView().add(pageView)))
.flatMap(userRepository::save)
.map(User::getToken);
Now, since you need the token to add to the response, and I figured out that the token is part of the User object somehow (otherwise UserRepository.findByToken() wouldn't work?), it would be easier to just use User::getToken at the end to retrieve the token to pass to the response.
Be aware though, the repository pattern does work properly with Spring, but there is only reactive support for MongoDB, Cassandra, Couchbase and Redis. Other than that there's also reactive support for PostgreSQL through rdbc, but I don't think Spring data has support for that.

How to set push key when pushing to firebase database?

When I write data to firebase database from both frontend(Angular 4) and backend(firebase functions), there is a push key generated by firebase. With this key, I cannot access data in the future because the key is unique. I am wondering is any way I can set the key myself or I can access the data without knowing the key?
Here is my code from frontend:
this.db.list(`${this.basePath}/`).push(upload);
Here is my code from backend:
admin.database().ref('/messages').push({original: original}).then(function (snapshot) {
res.redirect(303, snapshot.ref);});
All data I pushed will be under path/pushID/data
I cannot access data without knowing the pushID.
The best case I want is path/my own pushID/data
Thanks so much for help!!
If you want to loop through all messages:
var ref = firebase.database().ref("messages");
ref.once("value", function(snapshot) {
snapshot.forEach(function(message) {
console.log(message.key+": "+message.val().original);
});
});
If you want to find specific messages, use a query:
var ref = firebase.database().ref("messages");
var query = ref.orderByChild("original").equalTo("aaaa");
query.once("value", function(snapshot) {
snapshot.forEach(function(message) {
console.log(message.key+": "+message.val().original);
});
});
For much more on this, read the Firebase documentation on reading lists of data, sorting and filtering data, and take the Firebase codelab.
The keys should be unique in any way. You can set your own key like this instead of push
admin.database().ref('/messages/'+ yourUniqueId).set({original: original}).then(function (snapshot) {
res.redirect(303, snapshot.ref);});
yourUniqueId can be auth uid or email of user, like something unique.

Express.js how to use security on login and afterwards

I have a web app being built in express.js with a postgresql db.
I was wondering about how to implement the security, but everyone uses something different ( i guess thats a good thing? ).
Different modules different authentication sequences etc.
What I have at the moment:
1) User form post to for example /login
2) app routes to specific route
3) in route I try the following
var localconstring = "postgres://" + usr + ":" + pass + "#ip:port/db";
var client = new pg.Client(localconstring);
client.on('drain', client.end.bind(client));
client.connect(function (err, client, done) {
The database uses md5 so the pass is already protected by the db.
What should really happen?
Should I salt and hash the username and password and then save the salted/hashed credentials alongside the salt and then use the md5 of the db also?
If so which module?
Should I be logging in like that or try to do a select * from pg_roles/users ??
Thanks a lot!
(regarding the salt and hash if possible some detailed examples as I am pretty knew with authentication security)
Forgot to mention. cookies..
After the authentication I set the following cookies:
res.cookie('user', req.body.lguser.username, { signed: true })
res.cookie('watcher', o, { signed: true })
And look em up afterwards
req.signedCookies.user !== undefined
Is the signed attribute secure?
You should generate a key. This key should be saved on a cookie and on the database. Then when the user makes a petition, you can get the key on the cookie and search the user on the database.
There are libraries that help you on this, take a look at Passportjs:
http://passportjs.org/
First of all md5 is NOT seure anymore, so I would recommend you using 'sha512'.
A snippet would be something like this:
var crypto = require('crypto');
var salt = crypto.pseudoRandomBytes(32);
crypto.pbkdf2(userPassword,salt,1024,32,function(err,finalPassword){
//on the db you save the salt as a field and the SALTEDPASSWORD !!
//in this case the finalPassword
}
So when the user logs-in you get the user from the db by username and do the following:
//after getting the user from DB recalculate the hash
crypto.pbkdf2(passw,user.salt,1024,32,function(err,corrPass){
if(corrPass.toString() == user.password.toString()) // log in the user
//where user.password is the result from the db query
}
And I do recommend using passport like the other dude said, it simplifies all of the cookie stuff.
Hope it helped !

Resources