Реализация CRAM-MD5

Я рассматриваю реализацию аутентификации CRAM-MD5 для сервера IMAP и SMTP. Проблема в том, что CRAM, по-видимому, требует постоянного доступа к открытому текстовому паролю. Сервер отправляет клиенту уникальный вызов, и клиент возвращает:

MD5( MD5(password, challenge), MD5( password ) )

Я не вижу способа проверить это без открытого текстового пароля, в спецификации не сказано, что он должен быть доступным, но это только кажется логичным.

Единственное решение, которое я могу придумать, это зашифровать (правильно зашифровать, а не хешировать) пароль в базе данных (вероятно, используя AES на основе ключа RSA, поскольку у меня уже есть что с этим делать) и расшифровать его, когда мне нужно сравнить, кажется очень медленным, поскольку для каждого входа в систему по SMTP и IMAP потребуется расшифровка и хеширование.

Это лучшее решение/самое эффективное решение?

Или, лучше сказать, CRAM уже устарела, потому что теперь даже менее безопасная аутентификация по сети защищена с помощью SSL?


person Paystey    schedule 20.07.2011    source источник


Ответы (3)


хитрость в том, что все, что вам действительно нужно, это незавершенный md5 пароля, который совпадает с промежуточным состоянием контекста md5 перед завершением.

MD5_CTX ctx;
MD5Init(&ctx);
MD5Update(&ctx, password, length);

если вы сделаете это, а затем сохраните значение ctx как hashed, тогда можно будет использовать его копии в CRAM MD5, как это

для MD5(password, challenge)

MD5Update(&hashed, challenge, length);
MD5Final(&digest, &hashed);

и для MD5( password )

MD5Final(&digest, &hashed);

остальная часть MD5( MD5(password, challenge), MD5( password ) ) довольно проста

я бы хотел использовать python для этого примера, но в стандартном md5 нет способа получить доступ к состоянию объекта md5, поэтому я использовал API libmd5

person Dan D.    schedule 23.07.2011
comment
Хотелось бы, чтобы вы написали это на питоне, вот на чем я пишу это: p. Кажется, это лучшее решение. Сохраняет пароль в некоторой степени безопасным (насколько MD5 может быть в любом случае). Так что я мог бы в любом случае использовать свою идею шифрования, а затем по-прежнему иметь возможность обеспечивать функциональность CRAM MD5. - person Paystey; 24.07.2011
comment
Это может быть лучше, чем хранение пароля в виде обычного текста, поскольку пользователи, использующие один и тот же пароль в нескольких местах, могут быть менее затронуты, но база данных по-прежнему содержит все, что вам нужно для входа в систему. Чего трудно избежать для CRAM. - person Christopher Creutzig; 28.07.2011

В настоящее время существует проект RFC, предлагающий перевести DIGEST-MD5 в исторический статус, CRAM MD5 также находится не в лучшем состоянии.

Если вам нужна надлежащая безопасность, начните с TLS и SASL — в этом режиме PLAIN считается приемлемым, но, если вас это не устраивает, я бы рекомендовал внедрить GSSAPI или NTLM поверх него.

person Olipro    schedule 23.07.2011
comment
Спасибо, статус RFC очень помогает мне понять. Я изо всех сил пытался понять смысл CRAM MD5 в эти дни, поскольку TLS с более простым протоколом выглядел намного лучше. Я не хочу добавлять еще один слой между базой данных и программой, потому что он вообще не предназначен для абстрагирования, поэтому GSSAPI или NTLM на самом деле не являются вариантами. - person Paystey; 23.07.2011
comment
Надеюсь, вы тоже планируете написать свой собственный почтовый клиент ;) - person Olipro; 23.07.2011
comment
Почему так? Обеспечивают ли GSSAPI и NTLM аутентификацию клиентов? Из беглого взгляда я понял, что это механизмы аутентификации на стороне сервера. - person Paystey; 24.07.2011
comment
Единственными известными мне протоколами, поддерживаемыми почтовыми клиентами, совместимыми с RFC, являются CRAM, DIGEST, NTLM, GSSAPI, PLAIN и Login. - person Olipro; 24.07.2011
comment
Я рассмотрю некоторые данные об использовании NTLM и GSSAPI, чтобы понять, стоит ли их внедрять, поскольку я, честно говоря, никогда о них не слышал. Спасибо за внимание. - person Paystey; 24.07.2011

Исходники Python для hashlib.py говорят, что вы можете инициализировать экземпляр хэша с помощью двоичных данных, но, судя по использованию, это означает «инициализировать с помощью хэша этих данных».

Однако вы можете клонировать объект с неповрежденным внутренним состоянием, чтобы вы могли замариновать объект и сохранить его вместо пароля. Чтобы получить пароль MD5, расшифруйте объект, а чтобы получить хеш-вызов, распаковайте его и вызовите его метод update() с данными-вызовами.

person Adrian    schedule 28.07.2011
comment
Но это может потом кто-нибудь распаковать и наверняка использовать? Если код имеет доступ к состоянию открытого текста, чтобы иметь возможность обновить хэш, то, безусловно, его все еще можно найти. Я ценю, что это все еще довольно хорошо с точки зрения запутывания, потому что потребуется некоторое усилие, чтобы понять, что это такое и как это отменить. Но я думаю, что я собираюсь запустить его с полным шифрованием в БД. - person Paystey; 28.07.2011
comment
Не проверяя источник, я бы предположил, что объект сохраняет только текущий хэш, поскольку вам не нужно сохранять открытый текст, который будет вектором инициализации, который вы хотите, как указано в принятом ответе выше. - person Adrian; 22.08.2011