(Отредактировано после внесения изменений в вопрос.)
Метод 1:
Одним из способов решения этой проблемы является использование СА, возможно, вашего собственного.
Метод 2:
Примите любой клиент сертификат на уровне рукопожатия.Хотя принятие любого серверного сертификата с точки зрения клиента является плохой идеей, так как оно вводит возможность атаки MITM (см. здесь и здесь , дляпример), принятие любого клиента сертификата во время рукопожатия не представляет тех же проблем.
В конце рукопожатия, при условии, что сертификат сервера все еще проверен, вы будете знать, что:
- Связь между клиентом и сервером устанавливается безопасно, как это было бы с HTTPS без аутентификации сертификата клиента.
- У клиента есть закрытый ключ для сертификата, который он имеетпредставлены во время рукопожатия.Это гарантируется сообщением TLS
CertificateVerify
, в котором закрытый ключ клиента используется для подписи всех сообщений, которыми обмениваются во время рукопожатия, включая сертификат сервера и сертификат клиента.На самом деле это не зависит от (доверия) проверки самого сертификата клиента и будет работать только в том случае, если открытый ключ в сертификате клиента может проверить подпись в сообщении TLS CertificateVerify
.
При этом вы будете знать, что клиентский сертификат, который получает сервер, используется тем, у кого есть соответствующий закрытый ключ.Чего вы не будете знать, так это , кому принадлежит этот сертификат открытого ключа, то есть тому, кто является пользователем на другом конце, потому что вы пропускаете этап проверки, обычно выполняемый с помощью CA, который сам должен полагатьсяпо внеполосному механизму перед выдачей сертификата.Поскольку они используют самозаверяющие сертификаты, вам все равно придется выполнить этот внеполосный шаг, возможно, с помощью некоторой информации во время регистрации.
Это позволит вам управлять своими пользователями и способомони используют свои сертификаты легче.Вы можете просто сохранить и / или найти сертификат текущего пользователя в базе данных, общей для ваших серверов.Вы можете получить доступ к сертификату, посмотрев на SSLSession
в вашем приложении.Вы найдете сертификат пользователя в позиции 0 массива, возвращенного getPeerCertificates()
.Затем вы можете просто сравнить учетные данные, которые вы видите (опять же, потому что двустороннее рукопожатие прошло успешно) с теми, которые вы видели ранее, с целью аутентификации (и авторизации) в вашем приложении.
Обратите внимание, чтодаже если вы только что приняли самозаверяющие сертификаты, которые вы продолжаете добавлять, вам все равно придется отслеживать эту информацию открытого ключа как часть вашей системы, в дополнение к DN субъекта, поскольку у вас не будет контроля над субъектами DN (два пользователя могутвыберите то же самое, намеренно или нет).
Чтобы реализовать это, вам нужно настроить сервер на SSLContext
, который использует X509TrustManager
, который не выбрасываетлюбое исключение в его методе checkClientTrusted
.(Если вы используете тот же SSLContext
для других целей, я получу PKIX * 1051 * по умолчанию и делегирую ему вызовы checkServerTrusted
.) Поскольку вы, вероятно, не будете знать, что такое Субъект / ЭмитентDN этих самозаверяющих сертификатов будет, вам следует отправить пустой список принятых CA (*), вернув пустой массив в getAcceptedIssuers()
(см. Пример здесь ).
(*) TLS 1.0 молчит на эту тему, но TLS 1.1 явно разрешает пустые списки (с неопределенным поведением).На практике это будет работать с большинством браузеров, даже с SSLv3 / TLSv1.0: браузер предоставит полный список сертификатов на выбор в этом случае (или выберет первый, который он обнаружит, он настроен для автоматического выбора одного).
(я оставляю то, что более конкретно о HTTP, здесь ... Немного вне контекста, но это может представлять интерес для других.)
Метод1:
Вы можете интегрировать выдачу сертификата как часть вашей первоначальной регистрации.Когда пользователи регистрируют свои данные, они также просят сертификат, который сразу же выдается вашим регистрационным сервером в их браузер.(Если вы не знакомы с этим, есть способы выдачи сертификата в браузере, используя <keygen />
, CRMF (в Firefox) или элементы управления ActiveX в IE, который зависит от версииWindows.)
Метод 2:
В среде сервлета вы можете получить его в запросе сервлета javax.servlet.request.X509Certificate
атрибут
Кроме того, этоимеет тенденцию улучшать пользовательский опыт, так как отклонение сертификата клиента не обязательно прерывает соединение.Вы по-прежнему могли бы обслуживать веб-страницу (возможно, со статусом HTTP 401, хотя технически это должно сопровождаться механизмом вызова, а для сертификатов его нет), по крайней мере, сообщая своему пользователю, что что-то не так.Сбои рукопожатия (которые могут быть вызваны проверкой сертификата клиента в рамках рукопожатия в случае возникновения проблемы) могут быть очень запутанными для пользователей, которые действительно не знают о сертификатах.Недостатком является то, что довольно трудно «выйти» (аналогично аутентификации HTTP Basic) из-за отсутствия поддержки пользовательского интерфейса в большинстве браузеров.
Для реализации, если вы используете Apache Tomcat, вывозможно, вас заинтересует этот SSLImplementation
или этот ответ , если вы используете Apache Tomcat 6.0.33 или выше.