Authenticating DotNetNuke Users in ColdFusion

后端 未结 3 669
深忆病人
深忆病人 2020-12-19 18:20

Is there any way to authenticate users from other web apps using the DNN logins?

We have a main site that is using DNN and user logins are stored in the asp net mem

相关标签:
3条回答
  • 2020-12-19 18:49

    Most likely the password is not encrypted, it is hashed. Hashing is different from encrypting, because it is not reversible.

    You would not use ColdFusion's encrypt() function for this, you would use its hash() function.

    So the questions you'll need to answer to figure out how to hash the passwords in CF to be able to auth against the DNN users are:

    1. What algorithm is DNN using to hash the passwords?
    2. How is the salt being used with the password prior to hashing?
    3. Is DNN iterating over the hash X number of times to improve security?

    All of those questions must be answered to determine how CF must use the hash() function in combination with the salt and user-submitted passwords.

    I'll make some assumptions to provide an answer.

    If we assume that noiteration is being done and that the salt is simply being appended to the password prior to using SHA1 to hash the password, then you'd be able to reproduce the hash digest like this:

    <cfset hashDigest = hash(FORM.usersubmittedPassword & saltFromDB, "SHA1") />
    
    0 讨论(0)
  • 2020-12-19 18:51

    (Edit: Original answer did not work in all cases. Substantially revised ...)

    From what I have read, DNN uses an "SHA1" hash by default. The thread @barnyr posted shows it simply hashes the concatenated salt and password, but with a few twists.

    • DNN uses UTF-16LE to extract the password bytes, rather than CF's typical UTF-8.
    • It also extracts the salt and password bytes separately, which may produce different results than just decoding everything as a single string, which is what hash() does. (See demo below)

    Given that CF9's Hash function does not accept binary (supported in CF11), I do not think it is possible to duplicate the results with native CF functions alone. Instead I would suggest decoding the strings into binary, then using java directly:

    Code:

    <cfscript>
        thePassword = "DT!@12";
        base64Salt = "+muo6gAmjvvyy5doTdjyaA==";
    
        // extract bytes of the salt and password
        saltBytes = binaryDecode(base64Salt, "base64");
        passBytes = charsetDecode(thePassword, "UTF-16LE" );
    
        // next combine the bytes. note, the returned arrays are immutable, 
        // so we cannot use the standard CF tricks to merge them    
        ArrayUtils = createObject("java", "org.apache.commons.lang.ArrayUtils");
        dataBytes = ArrayUtils.addAll( saltBytes, passBytes );
    
        // hash binary using java
        MessageDigest = createObject("java", "java.security.MessageDigest").getInstance("SHA-1");
        MessageDigest.update(dataBytes);    
        theBase64Hash = binaryEncode(MessageDigest.digest(), "base64");
    
        WriteOutput("theBase64Hash= "& theBase64Hash &"<br/>");
    </cfscript>
    


    Demo of Differences:

    <cfscript>
        theEncoding = "UTF-16LE";
        thePassword = "DT!@12";
        base64Salt = "+muo6gAmjvvyy5doTdjyaA==";
    
        // extract the bytes SEPARATELY
        saltBytes = binaryDecode(base64Salt, "base64");
        passBytes = charsetDecode(thePassword, theEncoding );
        ArrayUtils = createObject("java", "org.apache.commons.lang.ArrayUtils");
        separateBytes = ArrayUtils.addAll( saltBytes, passBytes );
    
        // concatenate first, THEN extract the bytes 
        theSalt = charsetEncode( binaryDecode(base64Salt, "base64"), theEncoding );
        concatenatedBytes = charsetDecode( theSalt & thePassword, theEncoding );
    
        // these are the raw bytes BEFORE hashing
        WriteOutput("separateBytes= "& arrayToList(separateBytes, "|") &"<br>");        
        WriteOutput("concatenatedBytes"& arrayToList(concatenatedBytes, "|") );
    </cfscript>
    


    Results:

    separateBytes     = -6|107|-88|-22|0|38|-114|-5|-14|-53|-105|104|77|-40|-14|104|68|0|84|0|33|0|64|0|49|0|50|0
    concatenatedBytes = -6|107|-88|-22|0|38|-114|-5|-14|-53|-105|104|-3|-1|68|0|84|0|33|0|64|0|49|0|50|0 
    


    0 讨论(0)
  • 2020-12-19 19:06

    (Posting a new response to keep the "encrypted" process separate from "hashing")

    For "encrypted" keys, the DNN side uses the standard algorithms ie DES, 3DES or AES - depending on your machineKey settings. But with a few differences you need to match in your CF code. Without knowing your actual settings, I will assume you are using the default 3DES for now.

    Data To Encrypt

    The encrypted value is a combination of the salt and password. But as with hashing, DNN uses UTF-16LE. Unfortunately, ColdFusion's Encrypt() function always assumes UTF-8, which will produce a very different result. So you need to use the EncryptBinary function instead.

        // sample valus
        plainPassword = "password12345";
        base64Salt    = "x7le6CBSEvsFeqklvLbMUw==";
        hexDecryptKey = "303132333435363738393031323334353637383930313233";
    
        // first extract the bytes of the salt and password
        saltBytes = binaryDecode(base64Salt, "base64");
        passBytes = charsetDecode(plainPassword, "UTF-16LE" );
    
        // next combine the bytes. note, the returned arrays are immutable, 
        // so we cannot use the standard CF tricks to merge them    
        ArrayUtils = createObject("java", "org.apache.commons.lang.ArrayUtils");
        dataBytes = ArrayUtils.addAll( saltBytes, passBytes );
    


    Encryption Algorithm

    With block ciphers, ColdFusion defaults to ECB mode. (See Strong Encryption in ColdFusion) Whereas .NET defaults to CBC mode, which requires an additional IV value. So you must adjust your CF code to match.

        // convert DNN hex key to base64 for ColdFusion
        base64Key  = binaryEncode(binaryDecode( hexDecryptKey, "hex"),  "base64");
    
        // create an IV and intialize it with all zeroes
        // block size:  16 => AES, 8=> DES or TripleDES 
        blockSize = 8; 
        iv = javacast("byte[]", listToArray(repeatString("0,", blocksize)));
    
        // encrypt using CBC mode 
        bytes = encryptBinary(dataBytes, base64Key, "DESede/CBC/PKCS5Padding", iv);
    
        // result: WBAnoV+7cLVI95LwVQhtysHb5/pjqVG35nP5Zdu7T/Cn94Sd8v1Vk9zpjQSFGSkv 
        WriteOutput("encrypted password="& binaryEncode( bytes, "base64" ));
    
    0 讨论(0)
提交回复
热议问题