Autenticação do formulário em ASP.net

Saudações do dia! Eu estou usando autenticação de formulário, no registro está OK, mas enquanto login, ele está fazendo errado, ele está apenas fazendo o oposto. No registro, suponha que eu introduzi senha 123, agora ele vai converter essa senha usando a autenticação do formulário, e salvar em DB, agora, enquanto o login, se o usuário digitar 123, então ele será alterado, e tentar corresponder com o armazenado em DB. No meu caso, está a fazer o contrário, se ambas as senhas coincidirem, mostra, mensagem de erro personalizada..e se não for então aumentar a variável do contador para a conta de bloqueio

Por favor, reveja o meu código e ajuda-me....

Base de Dados:-

CREATE TABLE [dbo].[tblUsers](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [UserName] [nvarchar](15) NULL,
    [Password] [nvarchar](15) NULL,
    [Email] [nvarchar](200) NULL,
    [RetryAttempts] [int] NULL,
    [IsLocked] [bit] NULL,
    [LockedDateTime] [datetime] NULL,
PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]



CREATE proc [dbo].[sp_RegisterUser]
@UserName nvarchar(15),
@Password nvarchar(15),
@Email nvarchar(200)
As
Begin
Declare @Count int
Declare @ReturnCode int

Select @Count= COUNT(UserName) from tblUsers where UserName=@UserName
if(@Count=1)

Begin
Set @ReturnCode=-1
End

else
Begin
Set @ReturnCode=1
insert into tblUsers(UserName,Password,Email) values(@UserName,@Password,@Email)
End
Select @ReturnCode as ReturnValue
End


CREATE proc [dbo].[SP_AuthenticateUser]
@UserName nvarchar(15),
@Password nvarchar(15)
As
Begin
    Declare @Count int
    Declare @RetryCount int
    Declare @AccountLocked bit

    Select @AccountLocked= ISNULL(IsLocked,0)  from tblUsers where UserName=@UserName

    If(@AccountLocked=1)
    Begin
        Select 1 as AccountLocked,0 as Authenticate,0 as RetryAttempts
    End

    Else
    Begin
    Select @Count= COUNT(UserName) from tblUsers where UserName=@UserName and Password=@Password
    If(@Count=1)
    Begin
        Select 0 as AccountLocked,1 as Authenticate,0 as RetryAttempts
    End

    Else
    Begin
        Select @RetryCount=ISNULL(RetryAttempts,0) from tblUsers where UserName=@UserName
        Set @RetryCount=@RetryCount+1
    If(@RetryCount<=3)
    Begin
        Update tblUsers set RetryAttempts=@RetryCount where UserName=@UserName
        Select 0 as AccountLocked,0 as Authenticate,@RetryCount as RetryAttempts
    End
    Else
    Begin
        Update tblUsers set IsLocked=1,LockedDateTime=GETDATE() where UserName=@UserName
        Select 1 as AccountLocked,0 as Authenticate,0 as RetryAttempts
    End
    End
    End
End

concepção:-

Registration_Page-

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Registration.aspx.cs" Inherits="Registration" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div style="font-family:Arial">
<table style="border: 1px solid black">
    <tr>
        <td colspan="2">
            <b>User Registration</b>
        </td>
    </tr>
    <tr>
        <td>
            User Name
        </td>    
        <td>
            :<asp:TextBox ID="txtUserName" runat="server">
            </asp:TextBox>
            <asp:RequiredFieldValidator ID="RequiredFieldValidatorusername" 
            runat="server" ErrorMessage="User Name required" Text="*"
            ControlToValidate="txtUserName" ForeColor="Red">
            </asp:RequiredFieldValidator>
        </td>    
    </tr>
    <tr>
        <td>
            Password
        </td>    
        <td>
            :<asp:TextBox ID="txtPassword" TextMode="Password" runat="server">
            </asp:TextBox>
            <asp:RequiredFieldValidator ID="RequiredFieldValidatorPassword" 
            runat="server" ErrorMessage="Password required" Text="*"
            ControlToValidate="txtPassword" ForeColor="Red">
            </asp:RequiredFieldValidator>
        </td>    
    </tr>
    <tr>
        <td>
            Confirm Password
        </td>    
        <td>
            :<asp:TextBox ID="txtConfirmPassword" TextMode="Password" runat="server">
            </asp:TextBox>
            <asp:RequiredFieldValidator ID="RequiredFieldValidatorConfirmPassword" 
            runat="server" ErrorMessage="Confirm Password required" Text="*"
            ControlToValidate="txtConfirmPassword" ForeColor="Red" 
            Display="Dynamic"></asp:RequiredFieldValidator>
            <asp:CompareValidator ID="CompareValidatorPassword" runat="server" 
            ErrorMessage="Password and Confirm Password must match"
            ControlToValidate="txtConfirmPassword" ForeColor="Red" 
            ControlToCompare="txtPassword" Display="Dynamic"
            Type="String" Operator="Equal" Text="*">
            </asp:CompareValidator>
        </td>    
    </tr>
    <tr>
        <td>
            Email
        </td>    
        <td>
            :<asp:TextBox ID="txtEmail" runat="server">
            </asp:TextBox>
            <asp:RequiredFieldValidator ID="RequiredFieldValidatorEmail" 
            runat="server" ErrorMessage="Email required" Text="*"
            ControlToValidate="txtEmail" ForeColor="Red"
            Display="Dynamic"></asp:RequiredFieldValidator>
            <asp:RegularExpressionValidator ID="RegularExpressionValidatorEmail" 
            runat="server" ErrorMessage="Invalid Email" ControlToValidate="txtEmail"
            ForeColor="Red" Display="Dynamic" Text="*"
            ValidationExpression="\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*">
            </asp:RegularExpressionValidator>
        </td>    
    </tr>
    <tr>
        <td>

        </td>    
        <td>
            <asp:Button ID="btnRegister" runat="server" Text="Register" 
            onclick="btnRegister_Click"/>
        </td>    
    </tr>
    <tr>
        <td colspan="2">
            <asp:Label ID="lblMessage" runat="server" ForeColor="Red">
            </asp:Label>
        </td>    
    </tr>
    <tr>
        <td colspan="2">
            <asp:ValidationSummary ID="ValidationSummary1" ForeColor="Red" runat="server" />
        </td>    
    </tr>
</table>
</div>
    </form>
</body>
</html>

Página De Autenticação:_

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Login.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div style="font-family:Arial">
<table style="border: 1px solid black">
    <tr>
        <td colspan="2">
            <b>Login</b>
        </td>
    </tr>
    <tr>
        <td>
            User Name
        </td>    
        <td>
            :<asp:TextBox ID="txtUserName" runat="server">
            </asp:TextBox>
        </td>    
    </tr>
    <tr>
        <td>
            Password
        </td>    
        <td>
            :<asp:TextBox ID="txtPassword" TextMode="Password" runat="server">
            </asp:TextBox>
        </td>    
    </tr>
    <tr>
        <td>
           <asp:CheckBox ID="chk_boxRememberMe" runat="server" Text="Remember Me" />         
        </td>    
        <td>
            <asp:Button ID="btnLogin" runat="server" Text="Login" OnClick="btnLogin_Click" />
        </td>    
    </tr>
    <tr>
        <td>
            <asp:Label ID="lblMessage" runat="server" ForeColor="Red"></asp:Label>
        </td>
    </tr>
</table>
<br />
<a href="Registration/Registration.aspx">Click here to register</a> 
if you do not have a user name and password.
</div>

    </form>
</body>
</html>

Código Atrás:-

Página De Registo:-

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Web.Security;
public partial class Registration : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }

    protected void btnRegister_Click(object sender, EventArgs e)

    {
        if (Page.IsValid)
        {
            string CS = ConfigurationManager.ConnectionStrings["con"].ConnectionString;

            using (SqlConnection Conn=new SqlConnection(CS))
            {
                SqlCommand cmd = new SqlCommand("sp_RegisterUser",Conn);
                cmd.CommandType = CommandType.StoredProcedure;

                SqlParameter UserName = new SqlParameter("@UserName",txtUserName.Text);
                string EncryptPassword = FormsAuthentication.HashPasswordForStoringInConfigFile(txtPassword.Text, "SHA1");
                SqlParameter Password = new SqlParameter("@Password", EncryptPassword);

                SqlParameter Email = new SqlParameter("@Email", txtEmail.Text);

                cmd.Parameters.Add(UserName);
                cmd.Parameters.Add(Password);
                cmd.Parameters.Add(Email);

                Conn.Open();

                int ReturnCode=(int) cmd.ExecuteScalar();

                if (ReturnCode==-1)
                {
                    lblMessage.Text = "User Name alredy exists";
                }
                else
                {
                    Response.Redirect("~/Login.aspx");
                }
            }
        }
    }
}

Página De Autenticação:-

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Web.Security;


public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }

    protected void btnLogin_Click(object sender, EventArgs e)
    {
        //Login_WebConfig();
        // Login_DataBase();

        if (AuthenticateUser(txtUserName.Text, txtPassword.Text))
        {
            FormsAuthentication.RedirectFromLoginPage(txtUserName.Text, chk_boxRememberMe.Checked);
        }
        else
        {
            lblMessage.Text = "Invalid username/password";
        }
    }

    //protected void Login_WebConfig()
    //{
    //    if (FormsAuthentication.Authenticate(txtUserName.Text, txtPassword.Text))
    //    {
    //        FormsAuthentication.RedirectFromLoginPage(txtUserName.Text, chk_boxRememberMe.Checked);
    //    }
    //    else
    //    {
    //        lblMessage.Text = "Invalid user name/password";
    //    }
    //}

    protected void Login_DataBase()
    {

    }

    private bool AuthenticateUser(string username, string password)
    {
        string CS = ConfigurationManager.ConnectionStrings["con"].ConnectionString;
        using (SqlConnection Conn = new SqlConnection(CS))
        {
            SqlCommand cmd = new SqlCommand("SP_AuthenticateUser", Conn);
            cmd.CommandType = CommandType.StoredProcedure;

            string EncryptPassword = FormsAuthentication.HashPasswordForStoringInConfigFile(password, "SHA1");

            SqlParameter paramUserName = new SqlParameter("@UserName", username);
            SqlParameter paramPassword = new SqlParameter("@Password", EncryptPassword);

            cmd.Parameters.Add(paramUserName);
            cmd.Parameters.Add(paramPassword);
            Conn.Open();

            int ReturnCode = (int)cmd.ExecuteScalar();
            return ReturnCode == 1;


        }
    }
}

Configuração Web:-

<?xml version="1.0"?>

<!--
  For more information on how to configure your ASP.NET application, please visit
  http://go.microsoft.com/fwlink/?LinkId=169433
  -->

<configuration>

    <system.web>
      <compilation debug="true" targetFramework="4.5" />
      <httpRuntime targetFramework="4.5" />
      <authentication mode="Forms">
        <forms loginUrl="Login.aspx" defaultUrl="Welcome.aspx" timeout="2" protection="All">
          <!--<credentials passwordFormat="Clear">
            <user name="rkbisht" password="1234"/>
          </credentials>-->
        </forms>
      </authentication>
      <authorization>
        <deny users="?"/>
      </authorization>
  </system.web>

    <appSettings>
      <add key="ValidationSettings:UnobtrusiveValidationMode" value="None" />
    </appSettings>

  <connectionStrings>
    <add name="con" connectionString="Data Source=.;Initial Catalog=Security_Learning;Integrated Security=true"/>
  </connectionStrings>

</configuration>
Author: Ravindra Bisht, 2017-11-02

2 answers

Basicamente, não estás a usar a ferramenta certa para o trabalho.

Não está a usar acutualmente FormsAuthentication e também não está a gravar a faixa num ficheiro de configuração, por isso FormsAuthentication.HashPasswordForStoringInConfig não é o que deveria estar a usar.

Vale a pena ter tempo para acertar as coisas. Eis um ponto de partida:

Https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/consumer-apis/password-hashing

Nota, deve estar a usar um haxixe e um sal, o sal deve ser exclusivo para cada usuário.

Pessoalmente eu uso o Microsoft.AspNetCore.Criptografia.KeyDerivation pacote nuget com uma implementação semelhante à seguinte:

Classe Auxiliar

using Microsoft.AspNetCore.Cryptography.KeyDerivation;
using Resources;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web;

public static class SecurityHelper
{
     public static int DefaultIterations = 10000

     //KeyDerivation.Pbkdf2
     /// <summary>
     /// Generates a random salt
     /// </summary>
     /// <returns>A byte array containing a random salt</returns>
     public static byte[] GetRandomSalt()
     {
         byte[] saltBytes = new byte[32];
         RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
         rng.GetNonZeroBytes(saltBytes);            
         return saltBytes;
     }

     public static string GeneratePasswordHash(string plainPassword, int iterations, out string generatedRandomSalt)
     {
         generatedRandomSalt = Convert.ToBase64String(GetRandomSalt());
         return Convert.ToBase64String(ComputeHash(plainPassword, generatedRandomSalt, iterations));
     }

     public static string GetPasswordHash(string plainPassword, string existingSalt, int iterations)
     {
         return Convert.ToBase64String(ComputeHash(plainPassword, existingSalt, iterations));
     }



    private static byte[] ComputeHash(string plainText, string salt, int iterations)
    {
         return KeyDerivation.Pbkdf2(
         password: plainText,
            salt: Convert.FromBase64String(salt),
            prf: KeyDerivationPrf.HMACSHA256,
            iterationCount: iterations,
            numBytesRequested: 32);
    }       

 }

O teu fluxo de trabalho agora muda:

  • quando você guarda a senha, você precisa salvar o sal também
  • ao autenticar o utilizador, obter o Utilizador pelo nome de Utilizador da base de dados, calcular o hash para a senha introduzida, usando o sal gravado, comparando o resultado com o hash salvo.

Aproximadamente

//Registration
using (SqlConnection Conn=new SqlConnection(CS))
{
    SqlCommand cmd = new SqlCommand("sp_RegisterUser",Conn);
    cmd.CommandType = CommandType.StoredProcedure;

    SqlParameter UserName = new SqlParameter("@UserName",txtUserName.Text);
    string Salt = string.Empty;
    string Password = SecurityHelper.GeneratePasswordHash(txtPassword.Text, SecurityHelper.DefaultIterations, out salt);
    ;
    SqlParameter Password = new SqlParameter("@Password", Password);
    SqlParameter Email = new SqlParameter("@Email", txtEmail.Text);
    SqlParameter Salt = new SqlParameter("@Salt", Salt);
    cmd.Parameters.Add(UserName);
    cmd.Parameters.Add(Password);
    cmd.Parameters.Add(Email);

    Conn.Open();

    int ReturnCode=(int) cmd.ExecuteScalar();

    if (ReturnCode==-1)
    {
        lblMessage.Text = "User Name alredy exists";
    }
    else
    {
         Response.Redirect("~/Login.aspx");
    }
}

//Log In
private bool AuthenticateUser(string username, string password)
{
    //Get the following from your database based on username
    string savedHash = //fromDB;
    string savedSalt = //fromDb;

    return (SecurityHelper.GetPasswordHash(password, savedSalt, SecurityHelper.DefaultIterations) == tempUser.Password)                
}
Simplifiquei um pouco isto. Eu também guardo a iteração contra o usuário no banco de dados, caso precisemos aumentar as iterações padrão. A minha última dose de adivce, por isso, uma leitura sobre o porquê de "salgar" é uma coisa boa.
 0
Author: Jon P, 2017-11-02 05:49:38

O seu procedimento de autenticação armazenado (SP_AuthenticateUser) devolve 3 colunas, mas está a chamá-lo usando ExecuteScalar. Você precisa pegar o conjunto de dados e verificar a segunda coluna.

private bool AuthenticateUser(string username, string password)
{
    string CS = ConfigurationManager.ConnectionStrings["con"].ConnectionString;
    using (SqlConnection Conn = new SqlConnection(CS))
    {
        SqlCommand cmd = new SqlCommand("SP_AuthenticateUser", Conn);
        cmd.CommandType = CommandType.StoredProcedure;

        string EncryptPassword = FormsAuthentication.HashPasswordForStoringInConfigFile(password, "SHA1");

        SqlParameter paramUserName = new SqlParameter("@UserName", username);
        SqlParameter paramPassword = new SqlParameter("@Password", EncryptPassword);

        cmd.Parameters.Add(paramUserName);
        cmd.Parameters.Add(paramPassword);
        Conn.Open();

        var reader = cmd.ExecuteReader();
        reader.Read();
        return reader["Authenticate"] as bool;
    }
}

Também, certifique-se que repõe o contador após uma autenticação bem sucedida.

Select @Count= COUNT(UserName) from tblUsers where UserName=@UserName and Password=@Password
If(@Count=1)
Begin
    Update tblUsers set RetryAttempts = 0 where UserName = @UserName
    Select 0 as AccountLocked,1 as Authenticate,0 as RetryAttempts
End

O seu código também tem alguns outros problemas, mas estes dois estão provavelmente a causar o comportamento indicado na sua pergunta.

Aqui está uma maneira melhor de alterar a sua senha.

O utilizador terá de continue a assinar, a menos que configure um cookie auth. Clique aqui para obter ideias sobre como .

Provavelmente não precisa de credenciais na sua web.configuracao. Você só precisa colocá-los lá se você pretende usar FormsAuthentication.Autenticar . Parece estar a usar uma base de dados.
 0
Author: John Wu, 2017-11-02 10:08:42