I have a controller form application and the security team they said there is a vulnerability you can put any user_id fom postman inside the controller like this
ForgotPassword/user_id
how I can remove this vulnerability check the code below:
[HttpPost]
[ValidateAntiForgeryToken]
public JsonResult ForgotPassword(string emailId)
{
var helper = new Helper.Helper();
List<SqlParameter> args = new List<SqlParameter>();
args.Add(new SqlParameter("#Pin_email_id", emailId));
var req_resp = new Dictionary<string, object>();
try
{
using (DataSet dataset = helper.ExecuteSqlQuery("Web_Forgot_Password", args))
{
if (dataset != null && dataset.Tables.Count > 0 && dataset.Tables[0].Rows.Count > 0)
{
if (dataset.Tables[0].Rows[0]["Status"].ToString() == "Success")
{
req_resp["status"] = true;
req_resp["message"] = dataset.Tables[0].Rows[0]["Description"].ToString();
req_resp["code"] = dataset.Tables[0].Rows[0]["Code"].ToString();
string password = dataset.Tables[0].Rows[0]["user_password"].ToString();
SendForgotMail(emailId, dataset.Tables[0].Rows[0]["user_name"].ToString(), helper.Decrypt(password), dataset.Tables[0].Rows[0]["employee"].ToString());
return Json(req_resp);
}
else
{
req_resp["status"] = false;
req_resp["message"] = dataset.Tables[0].Rows[0]["Description"].ToString();
req_resp["code"] = dataset.Tables[0].Rows[0]["Code"].ToString();
return Json(req_resp);
}
}
else
{
req_resp["status"] = false;
req_resp["message"] = "Request Failed";
req_resp["code"] = "1005";
return Json(req_resp);
}
}
}
catch
{
var response = new
{
status = false,
message = "Request failed",
code = "1005"
};
return Json(response);
}
}
Well normally you store only password hashes in your database, which are not decryptable. Watching helper.Decrypt(password) in your code and sending the original password as a plain text in email is something painful. Normally I would just send a password reset link which can be used only once.
I checked the SqlParemater docs, it is added as a String value the way you use it, so it is not SQL injectable. Without the exact SQL I cannot tell much. I think they meant that it is SQL injectable, but then they should send evidence at least.
I'm working on a social network with ASP.NET and signalr. I have a simple login page, if it finds the user in the database it creates an Application variable and redirect the user to the profile page and in this page i invoke my Connect method declared in my hub class, this method takes the userid in the session and it give the friend list of this user. That works great when two or many users logged in at different time. The thing is, when two or several users logged in at the same time, the connect method declared in my hub takes the last user id stored in the Application variable and it give the friend list of this last user id and it send it to all user connected.
I can't find the correct approach.
Loggin Page code:
protected void btn_login_Click(object sender, EventArgs e)
{
Tbl_User user = new Tbl_User();
user = FonctionCommun.Login(txt_UserName.Text , txt_PassWord.Text);
if (user != null)
{
Application["UserID"] = user.UserID.ToString();
Response.Redirect("Profile.aspx");
}
else {
Label1.Visible = true;
}
}
My connect method code:
public void connect()
{
UserID = Guid.Parse(HttpContext.Current.Application["UserID"].ToString());
string OutPut = "";
if (ListOnlineUser.Count(x => x.UserID == UserID) == 0)
{
ListOnlineUser.Add(new OnlineUsers { UserID = UserID, ConnetionID = Guid.Parse(Context.ConnectionId) });
objchat.SetOnline(UserID);
ListFriends = objchat.GetFriendLoginStatus(UserID);
}
foreach (Tbl_User item in ListFriends)
{
if (item.Status == "1")
{
OnlineUsers onlineFriend = ListOnlineUser.FirstOrDefault(x => x.UserID == Guid.Parse(item.UserID.ToString()));
if (onlineFriend != null)
{
using (FIESTA_ADVISOREntities BD = new FIESTA_ADVISOREntities())
{
Tbl_User Obj_User = BD.Tbl_User.Where(o => o.UserID == UserID).FirstOrDefault();
if (Obj_User.ProfileImage != null)
{
string ext = BD.Assets.Where(o => o.url == Obj_User.ProfileImage).Select(o => o.MimeType).FirstOrDefault();
UserDetaille res = new UserDetaille() { UserID = Guid.Parse(Obj_User.UserID.ToString()), Username = Obj_User.UserName, ProfileImage = Obj_User.ProfileImage.ToString(), Ext = ext };
OutPut = JsonConvert.SerializeObject(res);
}
else {
UserDetaille res = new UserDetaille() { UserID = Guid.Parse(Obj_User.UserID.ToString()), Username = Obj_User.UserName, ProfileImage = "111", Ext = "png" };
OutPut = JsonConvert.SerializeObject(res); }
Clients.Client(onlineFriend.ConnetionID.ToString()).OnNewUserConnect(OutPut);
}
}
}
}
Clients.Caller.ShowFriends(ListFriends);
}
Try session variable instead of application variable. Application variable shared through out application working. So Whenever new user this is override. But if you use session variable that will never override by any other user
Also you can use query string in signalr in which you can pass userid as query string so in each request userid will be in query string
$.connection.hub.qs = 'userid=' + "UserId";
I have two websites A and B. On A I have the login option and if the user is authenticated I need to send it to B with same credentials. I have access to the code of both websites. My first approach was trying to log the user on A and figure out how could I make a Post to a action method on a controller on B(this is a recurrent question here in stackoverflow) I found this website and I don't know if it is useful: http://www.codeproject.com/Articles/833007/Redirect-and-POST-in-ASP-NET-MVC. My second approach is putting all the data that I wanted to submit to B in Browser Session, call a Redirect to B and then in a method("GET") try to read all that data and check if I can proceed with the logic on B.
I want to know which is the best approach to make this happen, and also if the later is wrong or not.
I have this code on my website A:
[HttpPost]
public ActionResult Login(LoginModel user)
{
//hardcoding InternalUser
user.AccountType = ((int)AccountTypeEnum.Internal).ToString();
var validator = new LoginModelValidator();
var result = validator.Validate(user);
if (!result.IsValid)
{
return View((LoginModelDecorator) user);
}
var service = new AuthenticationServiceAgent(user.Username, user.Password);
var securityService = new SecurityServiceAgent(service.GeToken());
var state = securityService.ProcessAccount(service.GeToken() != null, user.Username);
if (state == (int)UserAccessEnum.Processed)
{
var type = securityService.GetAccountTypeByUser(user.Username);
//CHeck user type
var accountType = Enum.GetName(typeof(AccountTypeEnum), int.Parse(user.AccountType));
var types = type.Split(',').Select(n => n.Split(':')[0]).ToList();
var containsTheUserType = user.AccountType == "1"
? types.Contains("XXX") || types.Contains(accountType)
: types.Contains(accountType);
if (containsTheUserType)
{
//var cPrincipal = service.GetClaims();
var claims = securityService.GetIdentity().Select(claim => new Claim(claim.ClaimType, claim.Value)).ToList();
if (claims.Count != 0)
{
var cPrincipal = new ClaimsPrincipal(new ClaimsIdentity(claims, "Custom"));
type.Split(',')
.ToList()
.ForEach(
ty =>
cPrincipal.Identities.First()
.AddClaim(new Claim("http://claims/custom/accounttype", ty)));
var token = new SessionSecurityToken(cPrincipal)
{
IsReferenceMode = true
};
FederatedAuthentication.WSFederationAuthenticationModule.SetPrincipalAndWriteSessionToken(
token, true);
Session["SEC_TOKEN"] = service.GeToken();
//Do I need to post?: SecurityToken, types and claims
//here is where I am redirecting the user
return Redirect("http://localhost:12345/Account/Login");
}
ModelState.AddModelError("LoginError", "Invalid Username or Password!");
}
ModelState.AddModelError("AccountTypeError", "You don't have access");
}
switch (state)
{
case (int)UserAccessEnum.BlockedAccount:
ModelState.AddModelError("StateError", "Your account is Blocked");
break;
case (int)UserAccessEnum.ChangePassword:
ModelState.AddModelError("StateError", "You need to change your password");
break;
case (int)UserAccessEnum.NoProcessed:
ModelState.AddModelError("StateError", "Error, please contact the system administrator");
break;
}
return View((LoginModelDecorator) user);
}
In my website B:
public ActionResult Login()
{
List<Claim> claims = //I need to get the claims from somewhere SESSION?
var type = //type used in the other Loging method
var securityToken = //securityToken used on the other Login method
if (claims.Count != 0)
{
var cPrincipal = new ClaimsPrincipal(new ClaimsIdentity(claims, "Custom"));
type.Split(',')
.ToList()
.ForEach(
ty =>
cPrincipal.Identities.First()
.AddClaim(new Claim("http://claims/custom/accounttype", ty)));
var token = new SessionSecurityToken(cPrincipal)
{
IsReferenceMode = true
};
FederatedAuthentication.WSFederationAuthenticationModule.SetPrincipalAndWriteSessionToken(
token, true);
Session["SEC_TOKEN"] = securityToken;
return RedirectToAction("Index", "Home");
}
return null;
}
Any idea of how to complete the gaps that I have?
I would like to obtain Birth Date from DotNetOpenAuth OpenID provider.
I have set up openID server as google right now and executing code like this:
Request
IAuthenticationRequest authenticationRequest = openid.CreateRequest(Request.Form["openid_identifier"]);
var fields = new ClaimsRequest();
fields.Email = DemandLevel.Require;
fields.FullName = DemandLevel.Require;
fields.BirthDate = DemandLevel.Require;
authenticationRequest.AddExtension(fields);
return authenticationRequest.RedirectingResponse.AsActionResultMvc5();
Response:
switch (response.Status) {
case AuthenticationStatus.Authenticated:
Session["FriendlyIdentifier"] = response.FriendlyIdentifierForDisplay;
FormsAuthentication.SetAuthCookie(response.ClaimedIdentifier, false);
ClaimsResponse untrustedExtension = response.GetUntrustedExtension<ClaimsResponse>();
ClaimsRequest claimsRequest = response.GetExtension<ClaimsRequest>();
if (!string.IsNullOrEmpty(returnUrl)) {
return Redirect(returnUrl);
} else {
return RedirectToAction("Index", "Site");
}
}
Problem is that with this Claims Request I get only email address, and I would like to obtall all of specified information.
Is it possible to obtain that informations?
In my mvc 4 application, i'm creating auth cookie with some other information. It works fine i f the data is less than 1KB, but when it exceeds 1Kb, cookie never creates.
As per my knowledge, max cookie size is apx 4KB. My code is below.
if (result.Status == ActionStatus.Success)
{
AuctionSiteApplication = result.Data;
CreateCustomAuthorisationCookie(AuctionSiteApplication.User.Email, obj.RememberMe, new JavaScriptSerializer().Serialize(AuctionSiteApplication));
if ((AuctionSiteApplication.User.UserType == UserType.SUAdmin) || (AuctionSiteApplication.User.UserType == UserType.Admin))
{
return RedirectToAction("Index", "Dashboard", new { area = "Admin" });
}
else
{
return RedirectToAction("Index", "Home", new { area = "" });
}
}
protected void CreateCustomAuthorisationCookie(String user_name, Boolean is_persistent, String custom_data)
{
FormsAuthenticationTicket auth_ticket =
new FormsAuthenticationTicket(
1, user_name,
DateTime.Now,
DateTime.Now.AddMinutes(30),
is_persistent, custom_data, ""
);
String encrypted_ticket_ud = FormsAuthentication.Encrypt(auth_ticket);
HttpCookie auth_cookie_ud = new HttpCookie(Cookies.UserCookie, encrypted_ticket_ud);
if (is_persistent) auth_cookie_ud.Expires = auth_ticket.Expiration;
System.Web.HttpContext.Current.Response.Cookies.Add(auth_cookie_ud);
}
protected override void OnAuthorization(AuthorizationContext filter_context)
{
if (Request.RawUrl.ToLower().Contains("www.")) filter_context.Result = RedirectPermanent(Request.RawUrl.ToLower().Replace("www.", ""));
HttpCookie auth_cookie = Request.Cookies[Cookies.UserCookie];
#region If auth cookie is present
if (auth_cookie != null)
{
FormsAuthenticationTicket auth_ticket = FormsAuthentication.Decrypt(auth_cookie.Value);
AuctionSiteApplication = new JavaScriptSerializer().Deserialize<AuctionSiteApplication>(auth_ticket.UserData);
System.Web.HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(new FormsIdentity(auth_ticket), null);
ViewBag.AuctionSiteApplication = AuctionSiteApplication;
base.OnAuthorization(filter_context);
}
#endregion
// Rest Code
...
}
Below is the data which i am trying to store in cookie which is not saving
{"User":{"UserID":1,"Email":"abctest#pqr.com","FirstName":"abc","LastName":"Arora","UserType":2,"UserCompanies":[{"CompanyId":35,"CompanyName":"New Company","CompanyRoleId":96,"IsAdmin":true},{"CompanyId":36,"CompanyName":"tryrtyr","CompanyRoleId":103,"IsAdmin":true},{"CompanyId":37,"CompanyName":"abc","CompanyRoleId":109,"IsAdmin":false},{"CompanyId":35,"CompanyName":"New Company","CompanyRoleId":98,"IsAdmin":false},{"CompanyId":37,"CompanyName":"abc","CompanyRoleId":109,"IsAdmin":false},{"CompanyId":37,"CompanyName":"abc","CompanyRoleId":109,"IsAdmin":false},{"CompanyId":37,"CompanyName":"abc","CompanyRoleId":109,"IsAdmin":false},{"CompanyId":37,"CompanyName":"abc","CompanyRoleId":109,"IsAdmin":false},{"CompanyId":37,"CompanyName":"abc","CompanyRoleId":109,"IsAdmin":false},{"CompanyId":36,"CompanyName":"tryrtyr","CompanyRoleId":105,"IsAdmin":false}],"IsAuthenticated":true},"Company":{"CompanyId":0,"CompanyName":null,"CompanyRoleId":96,"IsAdmin":true}}
Below is the data which i am trying to store in cookie which is saving properly
{"User":{"UserID":2,"Email":"abc#pqr.com","FirstName":"abc","LastName":"Arora","UserType":1,"UserCompanies":[{"CompanyId":35,"CompanyName":"New Company","CompanyRoleId":0,"IsAdmin":false},{"CompanyId":36,"CompanyName":"tryrtyr","CompanyRoleId":0,"IsAdmin":false},{"CompanyId":37,"CompanyName":"abc","CompanyRoleId":0,"IsAdmin":false}],"IsAuthenticated":true},"Company":{"CompanyId":0,"CompanyName":"SUAdmin","CompanyRoleId":2,"IsAdmin":false}}
I still think there is no reason to store these datas in the cookie. You have to verify them against your database every time so you gain nothing.
However the problem is that your data is 968 (1KB) character and after the encription it's larger than 4KB.
UPDATE:
I try and my test result that the encrypted string generated by Enrypt method is 4032 byte. I think it's too close to the limit. With the other data of the cookie I'm sure it's exceeds the limit.