I would like to know what can I do to have properly running my code.
I want to validate the oldPassword enter by the user in the form against the password that is stored in the db. Is they are the same is good to go if are different raise an error.
So far I have this but I have errors and don't pretty sure how to fix it.
I have the function IsSameAsOldPassword but i dont know how to send the parameters.
RuleSet(() => RuleFor(x => x.OldPassword)
.Must((x) => IsSameAsOldPassword(x.Id, x.OldPassword))
.WithMessage("Old password incorrect"), RuleSets.Update);
private bool IsSameAsOldPassword(Guid id, string oldPassword)
{
var user = _userManager.FindByIdAsync(id.ToString());
return _userManager.CheckPasswordAsync(user.Result, oldPassword).Result;
}
Any improvement to the code will be welcome.
I just found a solution, hope this help someone else, we just need to remove the field. the final solution will be like this:
RuleSet(() =>
{
RuleFor(x => x)
.MustAsync((x, cancellation) => IsSameAsOldPassword(x))
.WithMessage("Old password incorrect");
}, RuleSets.Update);
private async Task<bool> IsSameAsOldPassword(UserSetInputModel userInputModel)
{
userInputModel.fieldToUse
}
Related
So I'm currently setting up a small database for testing purposes and I'm trying to follow some general safety guidelines such as trying to prevent a SQL attack by using parameterized queries. When using EF Core to register a user I would usually do something along the lines of.
public IActionResult Register(UserModel userModel)
{
using (var ctx = new APIDbContext())
{
if (!ctx.Users.Any(x => x.Username.ToLower() == userModel.Username.ToLower()))
{
ctx.Users.Add(new UserModel
{
Username = userModel.Username,
Password = userModel.Password,
});
return Ok();
}
}
return NotFound("Username already taken.");
}
Besides storing the password in plain text, is there anything super bad going on here? Can you SQL inject something like this and is there anything I should think of?
[HttpPost] // Use the right http verb.
// You dont want to submit credentials in the url, but the body.
// Put validations on the Model properties.
1. You should have your own password policy.
2. Whitelist the username characters to prevent any malicious
characters that can be compile somehow into scripts
3. Have an limit of length on every request input that will go
to the database.
// Performance Tip: Make your action async.
// async Task<IActionResult> and await on user creation function
public IActionResult Register(UserModel userModel)
{
// Add captcha to guard the application from malicious automation tools.
// It would be better to take the users email,
// for example in order to reset the password.
// If the username is his password, then ignore this point.
// Optional: Add a central or localized logging capability for security reasons.
using (var ctx = new APIDbContext())
{
if (!ctx.Users.Any(x => x.Username.ToLower() == userModel.Username.ToLower()))
{
ctx.Users.Add(new UserModel
{
Username = userModel.Username,
Password = userModel.Password, // This needs to be hashed
});
// await ctx.SaveChangesAsync()
return Ok();
}
}
return NotFound("Username already taken.");
}
I have provided you with guidelines in the comments at your code.
As long as you use linq queries, they are not vulnerable to traditional SQL injection attacks.In this way Entity Framework passes the data via SQL parameters. Also When passwords are stored in plain text, anyone who knows the database password, can get them and log into any user profile. So they needed to be hashed in the database.
I am working on a side project(student, not homework, just holiday curiosity), which would be my simple personal password manager/vault. It will be a windows app. I want it to support more than just one user. Now that i have my login screen and other functionalities, i struggle to find a simple and effective way to check if login and password of the user are correct. I store the information in a simple SQL table called Users(picture below). Now, i want to get the bool result, whether are these two strings (username,password) in database. i will include some code and screenshots below. Any help appreciated!
P.S.: I am pretty familiar with mySQL(Oracle), i just canĀ“t fin a good way to do this without being ridiculous. :)
namespace KeyLocker.Database {
[Serializable]
public class UserDatabase {
public void AddUser(string username,string password,string question,string answer) {
using(var db = new KeyLockerContext()) {
db.Add(new User { Username = username,Password = password,SecurityQuestion = question,SecurityAnswer = answer });
db.SaveChanges();
}
}
public bool CheckUser(string username,string password) {
using(var db = new KeyLockerContext()) {
/*here i need to find out if username is present in database
and if it is, i need to find out if the password is correct*/
}
}
}
}
Table Users ScreenShot
Table SQL detail
At first glance, it seems like the easiest code to execute your idea would be:
public bool CheckUser(string username,string password) {
using(var db = new KeyLockerContext()) {
// Check if that combination already exists in DB.
var result = db.Users.Where(x => x.Username == username && x.Password == password).SingleOrDefault();
// See if result has a value, SingleOrDefault() returns null if no match
return (result == null);
}
}
EDIT/Disclaimer: Since there seems to be some confusion, this is an idea for how to quickly check if an object w/ certain values already exists in the DB - not a complete authentication library. You should never store cleartext passwords.
I have an API that I've created. I've (finally) managed to both GET and POST with it. Now I want to check the POST before it gets submitted.
I have a class with properties (is that the right word? I'm still learning the lingo) of id, name, city, state, and country.
I have a form with a button, and the button has a click event method that looks like this:
protected void submitButton_Click(object sender, EventArgs e)
{
void Add_Site(string n, string ci, string s, string co)
{
using (var client = new HttpClient())
{
site a = new site
{
name = n,
city = ci,
state = s,
country = co
};
var response = client.PostAsJsonAsync("api/site", a).Result;
if (response.IsSuccessStatusCode)
{
Console.Write("Success");
}
else
Console.Write("Error");
}
}
Add_Site(nameText.Text, cityText.Text, stateText.Text, countryText.Text);
}
Now, at this point, it's working as expected. However, I'd like to limit it.
What I want to do is to have it look at the nameText.Text value. Before it runs the POST statement, I want it to look at the other values in the GET of the API and make sure that name doesn't already exist.
While I know that I could probably update the database to make the name field unique, I'd rather do it programatically in C#.
Is this something that's possible within my C# code? If so, what function would I use and how would I get it to return the Site.Name attribute to compare my nameText.Text value?
EDIT:
Here is the code for the POST as requested in one of the comments. Note: This was auto-generated by Visual Studio when I added the controller.
// POST: api/site
[ResponseType(typeof(site))]
public IHttpActionResult Postsite(site site)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.site.Add(site);
db.SaveChanges();
return CreatedAtRoute("DefaultApi", new { id = site.id }, site);
}
I wouldn't have any idea where to even start with adding an "If the name already exists, throw an error," so some kind of walkthrough is plenty.
Here's code for looking in the database if any sites have the provided name (site.Name):
if (db.site.Any(o => o.Name == site.Name))
return BadRequest("Name already exists.");
I eventually determined that I should modify the POST as said in the comments. The solution I used ended up in this question: How to limit POST in web API
Users of my site have experienced some strange behaviour yesterday (first time I've seen this issue), and unfortunately I don't have much in the way of error logs to try to figure out what's going on. The site had a higher-than-normal number of people online at once, albeit not a large number in the grand scheme of things (maybe 50 to 100 users all trying to perform similar functions). I can't recreate the issue in my development environment, haven't seen it before, and don't really know why it is happening.
The crux of the problem is that users can register or log on successfully, but a small number of them could see other users' data.
The site is ASP.NET MVC 3.
Users are logging on and I set an authentication cookie - here's the LogOn action:
[HttpPost]
public ActionResult LogOn(AccountLogOnViewModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (!Membership.ValidateUser(model.UserName, model.Password))
{
ModelState.AddModelError("login-message", "Incorrect username or password");
}
}
if (ModelState.IsValid)
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
Session.Remove("MenuItems");
return Redirect(returnUrl ?? Url.Action("Index", "Home"));
}
else
{
model.ReturnUrl = returnUrl;
return View(model);
}
}
AccountLogOnViewModel is a simple object with two string properties, UserName and Password.
From what I can gather, this is fine - if you log in as NickW then doing something like User.Identity.Name correctly gives you "NickW" (when users were seeing other users' data, they reported that that "Welcome, NickW" text on screen was showing them the correct value - this is written out using User.Identity.Name)
The site also uses a custom membership provider. It overrides the ValidateLogin method, and the GetUser method. ValidateLogin appears to be working just fine so I'm not concerned about it.
The overridden GetUser method is as follows:
public override MembershipUser GetUser(string username, bool userIsOnline)
{
User user = _userRepository.Users.FirstOrDefault(u => u.UserName == username);
MembershipUser membershipUser = null;
if (user == null)
return membershipUser;
membershipUser = new MembershipUser(this.Name,
user.UserName,
user.Id,
user.Email,
null,
user.Comments,
user.IsActivated,
user.IsLockedOut,
user.CreatedDate,
user.LastLoginDate,
user.LastLoginDate,
user.LastModifiedDate,
Convert.ToDateTime(user.LastLockedOutDate));
return membershipUser;
}
So I'm attempting to retrieve a User object from my database, and using that to create a new MembershipUser object. My database User table has additional columns on top of those required by the membership provider - e.g. name, address, phone number etc.
At various points in the rest of the website (for example if you go to the Profile page), I retrieve a user object from the database and use it to populate the screen. The line I use to retrieve the User object is:
User user = userRepository.Users.FirstOrDefault(u => u.UserName == Membership.GetUser().UserName);
Here is a cut down version of the userRepository (i.e. just removing unrelated code).
public class SqlUserRepository : IUserRepository
{
private Table<User> usersTable;
private string _connectionString;
public SqlUserRepository(string connectionString)
{
_connectionString = connectionString;
usersTable = (new DataContext(connectionString)).GetTable<User>();
}
public IQueryable<User> Users
{
get { return usersTable; }
}
public void CreateUser(AccountRegisterViewModel user)
{
User newUser = new User();
newUser.UserName = user.UserName;
newUser.Salutation = user.Salutation;
newUser.PhoneNumber = user.PhoneNumber;
newUser.SecondaryPhoneNumber = user.SecondaryPhoneNumber;
newUser.FirstName = user.FirstName;
newUser.LastName = user.LastName;
newUser.PasswordSalt = CreateSalt();
newUser.Password = CreatePasswordHash(user.Password, newUser.PasswordSalt);
newUser.Email = user.Email;
newUser.CreatedDate = DateTime.UtcNow;
newUser.Comments = "Created from web registration";
newUser.LastModifiedDate = DateTime.UtcNow;
newUser.LastLoginDate = DateTime.UtcNow;
newUser.IsActivated = true;
newUser.IsLockedOut = false;
newUser.MayContact = user.MayContact;
usersTable.InsertOnSubmit(newUser);
usersTable.Context.SubmitChanges();
}
}
So it appears to me as if the auth cookie I'm setting is fine, but either:
When I first go in to the membership provider's GetUser() method, it retrieves the wrong record from the database and therefore sets up a MembershipUser object with the wrong username; subsequently when I look in the database for "this" user I'm actually looking for the wrong username.
Or: Intermittently when I do userRepository.FirstOrDefault(x => x.UserName == Membership.GetUser().Name) it retrieves the wrong record.
Or: something else is going wrong that I haven't thought of.
As I say, this seems to be a problem when the site was under load, so I'm wondering if it's some sort of caching issue somewhere? But I really don't know.
One thought I had was to change the way I retrieve the user in case the problem lies with the membership provider, and use this instead:
userRepository.FirstOrDefault(x => x.UserName == User.Identity.Name)
// or HttpContext.Current.User.Identity.Name if not within a controller
But really I'm not even sure what's going on so have no idea whether this will resolve the issue. Could it be a caching problem somewhere? It appears (but I can't be 100% certain) that when user A could see user B's details, it was always the case that user B was also active in the system (or had been within the previous 20 minutes).
I know it's a long shot, but does anyone have any idea how this could happen? Obviously it's a major concern and needs to be fixed urgently, but without knowing why it's happening I can't fix it!
Thanks in advance for any help,
Nick
Some things to consider:
Instead of using FirstOrDefault, use SingleOrDefault. FirstOrDefault assumes there will be more than 1 record of data matching your query. Since you are querying by username, there should only be 1 matching row, correct? In that case, use SingleOrDefault instead. When there are multiple rows that match the query, SingleOrDefault will throw an exception.
To get the username, instead of invoking Membership.GetUser().UserName, use User.Identity.Name. The User property on an MVC controller references an IPrincipal that should match the user's forms authentication cookie value. Since you have a custom membership provider, this should help eliminate its methods as a source of the problem.
There could be a caching issue if you have caching set up for the MVC project. Do you use the OutputCacheAttribute ([OutputCache]) on any controllers or action methods? Do you have it set up as a global filter in the global.asax file? Or do you think there may be some kind of SQL-based caching going on?
Looking at your overridden GetUser method, I see it should take 2 parameters: string username and bool isOnline. However, when you invoke it with Membership.GetUser().UserName, you are passing no parameters. Do you have another overridden overload of this method that also takes no parameters? What does it look like? Does it use System.Threading.CurrentPrincipal.Identity.Name to sniff out the current username when none is passed?
I've been brooding over a design issue (smelly code kinda thing) for a couple days now. Maybe you can help.
I have a "Login" Method in my RegistrationService, and currently it looks simplified like this:
public Boolean Login(String username, String password,
out String successRedirectUrl,
out IValidationDictionary validationResults)
{
successRedirectUrl = "";
if (!Validator.IsValid(username) || !Validator.IsValid(password)) return false;
// Other logic
// Distributed login requests etc.
// Build Redirect Url if login was successful etc.
}
Okay, let me explain above code. The method's main return value (Boolean) is supposed to tell the caller whether or not the login request was successful. Now, IF it was successful, I need to redirect the user to a different Url (thus, the "out" parameter successRedirectUrl). If it was NOT successful, I need to tell the user in the view what was wrong - thus the ValidationDictionary (Modelstate).
This code is really ugly and hard to maintain though. I thought of getting rid of the Boolean return type (returning the successRedirectUrl directly and checking on the caller side if it is empty) but I felt things became even more unclear.
Any idea how to do this better?
Thank you!
Make a custom class to hold all three values, and return it. Get rid of the "out" parameters.
How about this??
public class LoginOutput{
private bool _isLoginSuccess=false;
public bool IsLoginSuccess{/*Usual get set block*/}
private string _successRedirectUrl = String.Empty();
public string SuccessRedirectUrl{/*Usual get set block*/}
public IValidationDictionary ValidationResultDict{/*Usual get set block*/}
}
//your method now could be
public LoginOutput Login(string username, string password){
// your logic goes here
}
Questions:
Is the redirect URL different for different users? - I would say it shouldn't be, but if it is different, the decision shouldn't be in your business layer. This is UI logic and should be there.
What's your IValidationDictionary interface? You can probably just use it directly in your UI logic:
public IValidationDictionary Login(string user, string password);
var user = "bob";
var validator = Login(user, "password");
if (validator.IsValid)
Response.Redirect(GetUserPage(user));
else
HandleLoginError();
Note that GetUserPage() should not be a database lookup or anything else complicated. Again, this should be simple UI logic, something like:
public string GetUserPage(string user)
{
return "/MyPage/" + user;
}