Аутентификация пользователей DotNetNuke в ColdFusion

Есть ли способ аутентифицировать пользователей из других веб-приложений, используя DNN-логины?

У нас есть основной сайт, который использует DNN, а логины пользователей хранятся в таблице членства в asp. Из того, что я читал, пароли зашифрованы с использованием ключа машины, а затем засолены. Я вижу, где эта информация, но не могу правильно зашифровать пароли с помощью этого метода.

Я пытаюсь использовать веб-приложение Coldfusion на том же сервере, где находится наш сайт DNN, но оно не хочет работать. Можно подумать, что с функцией шифрования ColdFusion было бы немного проще:

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

Независимо от того, что я пытаюсь, я никогда не получаю подходящее значение.

Любая помощь, понимание или указание мне в правильном направлении будет принята с благодарностью!

3 ответа

(Изменить: оригинальный ответ не работал во всех случаях. Существенно пересмотрено...)

Из того, что я прочитал, DNN по умолчанию использует хэш SHA1. barnyr ветка barnyr показывает, что она просто хэширует объединенную соль и пароль, но с несколькими изменениями.

Учитывая, что CF9Hash функция не принимает двоичные файлы (поддерживается в 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 


Скорее всего, пароль не зашифрован, он хешируется. Хеширование отличается от шифрования, потому что оно не обратимо.

Для этого вы бы не использовали функцию encrypt() ColdFusion, вы бы использовали функцию hash().

Итак, на вопросы, на которые вам нужно ответить, чтобы выяснить, как хэшировать пароли в CF, чтобы иметь возможность авторизации против пользователей DNN:

  1. Какой алгоритм использует DNN для хэширования паролей?
  2. Как соль используется с паролем перед хэшированием?
  3. DNN итерирует по хэшу X количество раз, чтобы улучшить безопасность?

На все эти вопросы необходимо ответить, чтобы определить, как CF должен использовать функцию hash() в сочетании с солью и паролями, предоставленными пользователем.

Я сделаю некоторые предположения, чтобы дать ответ.

Если мы предположим, что выполняется нотерация и что соль просто добавляется к паролю перед использованием SHA1 для хеширования пароля, то вы сможете воспроизвести хэш-дайджест, например, так:

<cfset hashDigest = hash(FORM.usersubmittedPassword & saltFromDB, "SHA1") />

(Отправка нового ответа, чтобы отделить "зашифрованный" процесс от "хеширования")

Для "зашифрованных" ключей сторона DNN использует стандартные алгоритмы, т.е. DES, 3DES или AES - в зависимости от настроек вашего machineKey. Но с некоторыми отличиями вы должны соответствовать в вашем коде CF. Не зная ваших фактических настроек, я предполагаю, что вы используете настройки по умолчанию 3DES теперь.

Данные для шифрования

Зашифрованное значение представляет собой комбинацию соли и пароля. Но, как и в случае хеширования, DNN использует UTF-16LE. К сожалению, ColdFusion's 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" ));
Другие вопросы по тегам