Hash Encode Password

Discussion in 'ASP .Net Security' started by Jason, Jun 26, 2010.

  1. Jason

    Jason Guest

    Hi,
    I'm using the standard ASP Membership provider, and I want to create users
    from VBA.
    Does this sound OK? I can append all the user data into the database, but I
    need to hash encode the password before I store it. My VBA application then
    sends the clear password to an ASP.Net web service that does all the hashing
    and sends it back.

    My web service uses the code I found at
    http://msdn.microsoft.com/en-us/library/6tc47t75.aspx. It gets stuck
    because...... If machineKey.ValidationKey.Contains("AutoGenerate") Then _
    Throw New ProviderException("Hashed or Encrypted passwords " & _
    "are not supported with auto-generated keys.").
    I'm using a 3rd party web host, so I guess they've locked the machine key
    section. There must be another way. - How does the website administration
    tool do it? How does the New User Wizard do it?

    Thanks for your help you clever clever people.
     
    Jason, Jun 26, 2010
    #1
    1. Advertisements

  2. Jason

    Steven Cheng Guest

    Hi TMF,

    The membership link you provides is a custom membership provider
    implementation. Are you wantting to use a custom membership provider?

    http://msdn.microsoft.com/en-us/library/6tc47t75.aspx

    Also, the code you quoted is to detect whether the PasswordFormat is set to
    Clear mode and if not, it throw an exception. For ASP.NET membership
    provider, you can let it store password as hash encoded format without
    implementing your own provider. You can just configure the provider's
    "PasswordFormat" to "Hashed" e.g.,

    <membership defaultProvider="SqlProvider" userIsOnlineTimeWindow="15">
    <providers>
    <clear />
    <add
    name="SqlProvider"
    type="System.Web.Security.SqlMembershipProvider"
    connectionStringName="MySqlConnection"
    applicationName="MyApplication"
    enablePasswordRetrieval="false"
    enablePasswordReset="true"
    requiresQuestionAndAnswer="true"
    requiresUniqueEmail="true"
    passwordFormat="Hashed" />
    </providers>


    #How To: Use Membership in ASP.NET 2.0
    http://msdn.microsoft.com/en-us/library/ff648345.aspx

    Thus, whenever, you call Membership API to create a new user(and supply
    password), the actual password will be stored in membership database in
    hashed format instead of clear text one.

    As for the calling membership API from VBA code, do you mean office VBA
    code? If so, since VBA code cannot directly use .NET managed
    class/components, I think it is reasonable that you develope a XML
    webservice (http based) to expose the membership operations(such as create
    user, validate ...). And your VBA client can use script component such as
    XMLhttp or some service Monikor to consume the webservice.

    Sincerely,

    Steven Cheng

    Microsoft MSDN Online Support Lead


    --------------------
     
    Steven Cheng, Jun 28, 2010
    #2
    1. Advertisements

  3. Jason

    Jason Guest

    Thanks Steven. It works now.

    In my Web Service I used the Membership.CreateUser function.

    However, this creates a big security hole, becasue anyone can hook up to my
    web service and create a user for themselves.

    I really wanted the webservice to be just a Password Hasher, and let my
    MSAccess application manage the creation of the user.

    How's this for a solution? MSAccess sends the password to the web service,
    and the the webserice creates a dummy user. It looks up the hashed password
    in the ASP_Membership table and returns it to Access, then it deletes the
    dummy user.

    Does this sound secure?
     
    Jason, Jun 28, 2010
    #3
  4. Jason

    Steven Cheng Guest

    Thanks for your reply TMF,

    If you do want to send hashed value as password when creating user(due to
    security consideration). I think you can adopt the following approach:

    *Configure the membership provider to accept clear text password (set
    PasswordFormat to "Clear") so that the membership provider will not
    automatically hashed the password.

    * In your webservice API, you manually hash the password (accept from
    webservice client) and pass it to the membership API

    Thus, ASP.NET membershp provider doesn't take care of the password hash and
    just store and return whatever password value you pass to it

    In addition, for ASP.NET webservice deployed in IIS, you can also consider
    using HTTPS/SSL to secure it at transport layer:

    #HTTP Security and ASP.NET Web Services
    http://msdn.microsoft.com/en-us/library/ms996415.aspx#httpsecurity_topic3

    #Consuming Webservices over HTTPS (SSL)
    http://weblogs.asp.net/jan/archive/2003/12/04/41154.aspx

    Sincerely,

    Steven Cheng

    Microsoft MSDN Online Support Lead


    Delighting our customers is our #1 priority. We welcome your comments and
    suggestions about how we can improve the support we provide to you. Please
    feel free to let my manager know what you think of the level of service
    provided. You can send feedback directly to my manager at:
    .
    --------------------
     
    Steven Cheng, Jun 29, 2010
    #4
  5. Jason

    Jason Guest

    Thanks for your reply Steven,

    By 'manually' I suppose you mean 'not using the machine key' because, as I
    said, the machine key is set to AutoGenerate/IsolateApps.

    If I set the password format to 'Clear', the ASP.net application will also
    expect clear passwords because it uses the same Web.config. Should I have a
    seperate Web.config for my web service?

    I think I'm going to use the CreateDummyUser>FindPassword>DeleteDummyUser
    approach, if you can't see any risk with that.

    *********************************************************
    <WebMethod()> _
    Public Function GetHashedPwdAndSalt(ByVal strClearPWD As String) As
    String()
    Dim Usr As MembershipUser
    Dim strArray As String()

    Usr = Membership.CreateUser("dummy", strPWD, "")

    'Get the Password and PasswordSalt
    strArray = basGetDummyPWDAndSalt()

    'Now delete the dummy user
    basDeleteDummyUser()

    Return strArray

    End Functio
    ---------------------------------------------------------------------------------------
    Private Function basGetDummyPWDAndSalt() As String()
    Dim DR As SqlDataReader
    Dim Cnn As New SqlConnection()
    Dim Rtn As String()

    Cnn.ConnectionString =
    ConfigurationManager.ConnectionStrings("PADSConnectionString").ToString
    Dim myCommand As New SqlCommand

    If Cnn.State = ConnectionState.Closed Then Cnn.Open()

    myCommand.Connection = Cnn
    myCommand.CommandType = CommandType.Text
    myCommand.CommandText = _
    "SELECT Password, PasswordSalt FROM aspnet_Membership WHERE (Email =
    N'')"
    DR = myCommand.ExecuteReader()
    DR.Read()
    ReDim Rtn(2)
    Rtn(0) = DR("Password")
    Rtn(1) = DR("PasswordSalt")
    myCommand.Dispose()
    Cnn.Close()

    Return Rtn

    End Functio
    --------------------------------------------------------------------------------------------
    Private Function basDeleteDummyUser() As String
    Dim DR As SqlDataReader
    Dim Cnn As New SqlConnection()
    Dim Rtn As String
    Dim strSQL As String
    Cnn.ConnectionString =
    ConfigurationManager.ConnectionStrings("PADSConnectionString").ToString
    Dim myCommand As New SqlCommand

    If Cnn.State = ConnectionState.Closed Then Cnn.Open()

    myCommand.Connection = Cnn
    myCommand.CommandType = CommandType.Text
    strSQL = "DELETE FROM aspnet_Membership "
    strSQL = strSQL & "FROM aspnet_Membership INNER JOIN "
    strSQL = strSQL & "aspnet_Users ON aspnet_Membership.UserId =
    aspnet_Users.UserId "
    strSQL = strSQL & "WHERE (aspnet_Users.LoweredUserName = N'dummy')"

    myCommand.CommandText = strSQL
    DR = myCommand.ExecuteReader()

    myCommand.Dispose()
    Cnn.Close()

    If Cnn.State = ConnectionState.Closed Then Cnn.Open()

    strSQL = "DELETE FROM aspnet_Users "
    strSQL = strSQL & "WHERE (LoweredUserName = N'dummy')"

    myCommand.CommandText = strSQL
    DR = myCommand.ExecuteReader()

    myCommand.Dispose()
    Cnn.Close()

    Rtn = "User: dummy has been deleted"
    Return Rtn

    End Function
    **********************************************************
    This could go wrong if 2 people ran it at the same time, but it's not a
    problem to me


    ------------------------------------------------------------------------------------------------
     
    Jason, Jun 29, 2010
    #5
  6. Jason

    Steven Cheng Guest

    Thanks for reply TMF,

    If the webservice and the asp.net web application is deployed together
    (within the same IIS application virtual directory), there is no need to
    use separate web.config file, they just share the same web.config.

    As for the worry about "2 people ran the membership management api" at the
    same time, I think you can just add some concurrency protection code(such
    as lock) around the user creation/editing webservice method to as to ensure
    only a single request can access it at the same time thought that might
    impact the performance a bit.

    Sincerely,

    Steven Cheng

    Microsoft MSDN Online Support Lead

    --------------------
     
    Steven Cheng, Jul 7, 2010
    #6
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.