3

有没有办法使用 DNN 登录对来自其他 Web 应用程序的用户进行身份验证?

我们有一个使用 DNN 的主站点,用户登录信息存储在 asp 网络成员表中。从我一直在阅读的内容来看,密码是使用机器密钥加密的,然后加盐。我看到此信息在哪里,但似乎无法使用此方法正确加密密码。

我正在尝试在我们的 DNN 站点所在的同一台服务器上使用 Coldfusion Web 应用程序,但它不想工作。您会认为使用 ColdFusion 加密功能会很困难:

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

无论我尝试什么,我都没有得到匹配的值。

任何帮助、见解或指出我正确的方向将不胜感激!

4

3 回答 3

3

(编辑:原始答案并非在所有情况下都有效。大幅修改......)

根据我的阅读,DNN 默认使用“SHA1”哈希。@barnyr发布的线程显示它只是对连接的盐和密码进行哈希处理,但有一些曲折。

鉴于 CF9 的Hash函数不接受二进制(在 CF11 中支持),我认为仅使用原生 CF 函数无法复制结果。相反,我建议将字符串解码为二进制,然后直接使用 java:

代码:

<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>


差异演示:

<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>


结果:

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 


于 2012-09-21T22:45:21.530 回答
2

密码很可能没有加密,它是散列的。散列不同于加密,因为它是不可逆的。

您不会为此使用 ColdFusion 的 encrypt() 函数,而是使用它的 hash() 函数。

因此,要弄清楚如何在 CF 中对密码进行哈希处理,以便能够针对 DNN 用户进行身份验证,您需要回答的问题是:

  1. DNN 使用什么算法对密码进行哈希处理?
  2. 在散列之前,盐是如何与密码一起使用的?
  3. DNN 是否会迭代哈希 X 次以提高安全性?

必须回答所有这些问题才能确定 CF 必须如何将 hash() 函数与 salt 和用户提交的密码结合使用。

我会做一些假设来提供答案。

如果我们假设 noiteration 正在进行并且在使用 SHA1 对密码进行哈希处理之前只是将盐附加到密码中,那么您将能够像这样重现哈希摘要:

<cfset hashDigest = hash(FORM.usersubmittedPassword & saltFromDB, "SHA1") />
于 2012-09-21T14:09:18.110 回答
1

(发布新的回复以将“加密”过程与“散列”分开)

对于“加密”密钥,DNN 端使用标准算法,即 DES、3DES 或 AES - 取决于您的machineKey设置。但是您需要在 CF 代码中匹配一些差异。在不知道您的实际设置的情况下,我假设您现在使用默认设置3DES

要加密的数据

加密值是盐和密码的组合。但与散列一样,DNN 使用UTF-16LE。不幸的是,ColdFusion 的Encrypt()函数总是假定 UTF-8,这将产生非常不同的结果。因此,您需要改用该EncryptBinary功能。

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


加密演算法

对于分组密码,ColdFusion 默认为ECB 模式。(请参阅ColdFusion 中的强加密)而 .NET 默认为 CBC 模式,这需要额外的 IV 值。所以你必须调整你的CF代码来匹配。

    // 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" ));
于 2012-09-24T20:16:40.590 回答