I'm using Firebase 2.x. If I enable email/password security, how do I prevent a malicious pre-existing user from writing their own javascript code that would do authenticate with my Firebase and then launch a createUser attack? Hypothetically, it might look like this:
var ref = new Firebase(my_fire_base);
ref.authWithPassword({ email : 'pre#existing.com', password: 'validpassword' },
function(error, authData) {
if (!error) {
ref.createUser( ... ); // do this a bunch of times
}
});
Since this question was cross-posted to Google Groups, I'll quote the answer that was given there:
You do not need to be authenticated to call createUser(). This is by design and how all registration systems work. It is possible for a malicious client to call createUser() a gazillion times, but this is where we build rate limiting into the service we provide and prevent people from doing this. You cannot restrict by specific origins, and even if you could, as you mentioned, this can be easily spoofed.
Related
In express app where users login using their web identities (google, facebook, amazon, etc) using passport.js for this. I have created a route. but only want that a single user should have access to it.
I have it working with extensive testing, but not entirely sure if its in fact secure enough?
Here is my code for the route:
app.get("/superSecretPage", function(req, res){
console.log(req.user);
if (req.isAuthenticated()){
if (req.user.userId === "XXXXXXXXXXXXXXXX") {
User.find({}, function(err, users){
res.render("userlist", {
users: users,
});
});
} else {
res.render("invalid")
}
} else {
res.redirect("login")
}
});
XXXXXXXXXXXXXXXX = being the users uniqueID from Google/Amazon/Facebook or another ID provider
Like i said this work, and only allows the user that equals req.user.userId, but is this secure enough?
This is not a proper way to do that. What will you do If you want to allow another user later? Will you open code and edit the user Id?
Do not hard code the user ID.
You need to implement Role Base Access Control. You need to create a super power user role and assign it to the users, Who you want to allow to access your super secret page. And use middlewares to check the role permissions.
This will help you : Role based auth | NodeJS
Like i said this work, and only allows the user that equals req.user.userId, but is this secure enough?
You haven't really shown enough to know about the overall security of this. The security depends upon at least the following:
Implementation of req.isAuthenticated()
How the user session was established and protected. Most sessions use a browser cookie to identify the session and it must be run over https to offer any protection. Then, you must also have proper auto-logout to make it less likely the session is just left active where someone else can use it on that computer.
How the req.user.userId got set in the first place. You don't show this so we really have no idea what is behind that and whether it's following good security practices or not.
If there is any persistent storage of the user session, then the security of that storage mechanism is relevant.
Presuming there's a login mechanism, are secure (hard to guess) credentials required? Are there anti-hacking protections in place to attempt to thwart credential guessing.
If you are 100% sure that req.user.userId is valid and that this connection belongs to the appropriate user for the userId, then this bit of code works fine. But, the devil is in the details of making sure that req.user.userId is appropriately connected to an authorized user and that's where the hard work is of making security work.
Add a field in the db schema and set it to an array which contains all the route that the user has access to. When authenticating loop through the array to see if he/she can access the route he/she is trying to.
I have a form on a website that needs to check my calendar to see what times are available, and then later when it's submitted it's going to send an email.
I created a service account in the API console but I have no idea how to grant it access to my account.
Here's what I have so far, trying to list labels of my Gmail account as a test.
var google = require( 'googleapis' );
var gmail = google.gmail('v1');
var key = require('../client_secret.json');
var authClient = new google.auth.JWT(
key.client_email,
null,
key.private_key,
['https://mail.google.com/'],
'****#gmail.com');
authClient.authorize(function (err, tokens) {
if (err) {
return console.log(err);
}
gmail.users.labels.list({
auth: authClient,
userId: '****#gmail.com'
}, function (err, resp) {
if (err) {
return console.log(err);
}
console.log(resp);
});
});
And when I run the script I get:
[Error: unauthorized_client]
Edit:
I've also tried another auth flow using oauth, where it takes you to the typical permission screen asking you to Allow access for "project name" to "whatever scopes you put". Then I can use the access token to make requests and everything is good... but this doesn't feel right because I don't ever want any other user to authorize. I could use a route to authorize the "app" 1 time and then disable that page so it can't be accessed again... It feels kind of hack-y.
I have partially solved my problem; at least, I have gotten the example in my question to work.
In the Developer Console I had to edit my service account and check a box to enable "Domain-wide delegation".
You go to your Service Accounts, click the little 3 dot menu icon to the right of your service account, click edit and in the popup dialog there is a checkbox that you need to check.
I had previously seen something about Domain-wide Delegation but in that example they were saying to go to your Google Apps account, which I don't have, so I thought it didn't pertain to me, but after tinkering around in the Developer Console I found that checkbox and the Gmail example above works, as well as other parts of the Gmail API including reading messages from my inbox.
However, I tried doing a request to the Calendar API and I am getting an error, but I think that calls for a different question.
I'm working on an application where only the admin should be able to create users for the system; meaning the user is restricted from creating an account but can login if login credentials were made for him/her.
I'm thinking about using houston:admin to manually create users, but how can I restrict users from creating an account using accounts-ui?
Should I use different packages to achieve this altogether?
You have several ways to prevent users from creating accounts:
throwing an error in the Accounts.onCreateUser() callback (server only):
Accounts.onCreateUser(function(options, user) {
if (/* some logic to figure out if current user is an admin */) {
return user;
}
throw new Meteor.Error("user creation disabled.");
});
This will prevent the account from being created if the current user is not an admin.
configuring Accounts to forbid account creation (both client and server):
Accounts.config({
forbidClientAccountCreation: true
});
which rejects calls to createUser() from the client (but will not prevent user creation using oAuth services).
A combination of both is a likely course of action.
Take a look at the linked documentation for more details.
I am building an application that has two types of users. Professional users and their clients. The account types are completely distinct with no overlap. So, emails registered as Pro could still be used to register as a Client, and if a Pro user tried to log in using the client form, their account would not exist.
The problem:
Meteor automatically prevents duplicate emails from being used when creating user accounts. My thought was to use a custom validation to allow the behavior and essentially create two different sets of users. Here is an example of the validation I tried for a 'Pro' user.
Accounts.onCreateUser(function(options, user) {
var email = user.email;
if (Meteor.users.find({emails: email, isPro : true}).count() > 0) {
throw new Meteor.Error(403, "This email address is already registered");
}
user.isPro = true;
return user;
});
But meteor still uses its default duplicate email rejection instead. Any ideas on how I can override this behavior, or is there a better way to create two distinct sets of users?
You can do this in a mongo shell
db.users.dropIndex('emails.address_1');
Doing this is probably not the best idea and may have unintended consequences. I too think the solution discussed in the comments would be better.
I'm building a Meteor app for contracts. A signed in user can create a contract. But I'd like for them to be able to send a contract to another party, who can view the contract without signing up or creating an account. The problem is that, even if the URL is long and random, www.example.com/docs/bM7GjrRq1wABYdxws3 -- I'm not sure it is private enough -- because maybe all these contracts could be easily crawled or end up in search like this.
I'd like the creator of the contract to set a password that can be emailed to the other party along with the link to the contract. Before the party can view the contract, they need to enter the password.
My solution is to allow a user to password protect the page (but without a username/email). But I'm not sure how to do it. How can I password protect a page with a password set by a user?
You could save password within the page object on mongodb.
Then when he creates or edit the page, he might choose to share publicly or with password.
The publish method could look somewhat like this.
Meteor.publish("page", function (){
if (!this.userId) {
return Pages.find({
_id: Session.get("pageId"),
private: true,
password: Session.get("pagePassword")
});
} else {
// code for logged in users
}
});
Of course it's a good idea to store a hash for the password and compare to the hash the user entered, instead of storing the raw password.