Authenticating DotNetNuke Users in ColdFusion

无人久伴 提交于 2019-11-28 05:22:31

问题


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 membership table. From what I have been reading, the passwords are encrypted using the machine key and then salted. I see where this info is, but can't seem to encrypt passwords correctly using this method.

I'm trying with a Coldfusion web application on the same server where our DNN site is, but it doesn't want to work. You'd think it would be strait forward with the ColdFusion encryption function:

    Encrypt(passwordstring, key [, algorithm, encoding, IVorSalt, iterations])

No matter what I try, I never get a matching value.

Any help, insight or pointing me in the right direction would be greatly appreciated!


回答1:


(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 





回答2:


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") />



回答3:


(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" ));


来源:https://stackoverflow.com/questions/12524877/authenticating-dotnetnuke-users-in-coldfusion

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!