Аутентификация X.509 в Spring Security

X.509 Authentication in Spring Security

1. обзор

В этой статье мы сосредоточимся на основных случаях использованияX.509 certificate authentication -verifying the identity of a communication peer при использовании протоколаHTTPS (HTTP over SSL).

Проще говоря - пока установлено безопасное соединение, клиент проверяет сервер в соответствии с его сертификатом (выданным доверенным центром сертификации).

Но помимо этогоX.509 вSpring Security можно использовать дляverify the identity of a client через сервер при подключении. Это называется“mutual authentication, “, и здесь мы также рассмотрим, как это делается.

Наконец, коснемсяwhen it makes sense to use this kind of authentication.

Чтобы продемонстрировать проверку сервера, мы создадим простое веб-приложение и установим специальный центр сертификации в браузере.

И дляmutual authentication мы создадим сертификат клиента и модифицируем наш сервер, чтобы разрешить доступ только проверенным клиентам.

2. Хранилища ключей

Optional Requirement: чтобы использовать криптостойкие ключи вместе с функциями шифрования и дешифрования, вам необходимо установить‘Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files' в вашемJVM.

Их можно загрузить, например, сOracle (следуйте инструкциям по установке, включенным в загрузку). Некоторые дистрибутивы Linux также предоставляют устанавливаемый пакет через своих менеджеров пакетов.

Чтобы реализоватьX.509 authentication в приложении Spring, мы используемfirst create a keystore in the Java Key-Store (JKS) format.

Этотkeystore должен содержатьcontain a valid certificate of authority or a chain of certificate authorities и собственный сертификат для нашего сервера. Последний должен быть подписан одним из включенныхauthorities и должен быть назван в честьhostname, на котором работает сервер; мы будем использовать здесь приложениеJavakeytool.

To simplify процесс созданияkeys иcertificates с использованиемkeytool, кодаon Github, предоставляет прокомментированныйMakefile для GNUmake , содержащий все шаги, необходимые для завершения этого раздела. Вы также можете легко настроить его с помощью нескольких переменных среды.

Tip: Какall-in-one step, вы можете запуститьmake без аргументов. Это создастkeystore, atruststore и два сертификата для импорта в ваш браузер (один дляlocalhost и один для пользователя с именем“cid”).

Для создания новогоkeystore с центром сертификации мы можем запуститьmake следующим образом:

$> make create-keystore PASSWORD=changeit

Теперь мы добавим сертификат для нашего хоста разработки к созданномуkeystore и подпишем его нашимcertificate authority:

$> make add-host HOSTNAME=localhost

Чтобы разрешитьclient authentication, нам также понадобитсяkeystore с именем“truststore”. Этотtruststore должен содержать действительные сертификаты нашегоcertificate authority и всех разрешенных клиентов. Для справки по использованиюkeytool, пожалуйста, посмотритеMakefile в следующих разделах:

$> make create-truststore PASSWORD=changeit
$> make add-client CLIENTNAME=cid

3. Пример приложения

Наш проект защищенного сервера SSL будет состоять из аннотированного класса приложения@SpringBootApplication (который является разновидностью@Configuration), файла конфигурацииapplication.properties и очень простого внешнего интерфейса в стиле MVC.

Все, что нужно сделать приложению, - это представить страницуHTML с сообщением“Hello {User}!”. Таким образом, мы можем проверить сертификат сервера в браузере, чтобы убедиться, что соединение проверено и защищено.

Сначала мы создаем новый проектMaven с тремя включенными пакетамиSpring Boot Starter:


    org.springframework.boot
    spring-boot-starter-security
    1.4.0.RELEASE


    org.springframework.boot
    spring-boot-starter-web
    1.4.0.RELEASE


    org.springframework.boot
    spring-boot-starter-thymeleaf
    1.4.0.RELEASE

For reference:, вы найдете пакеты наMaven Central (security,web,thymeleaf).

В качестве следующего шага мы создадим основной класс приложения и пользовательский контроллер:

@SpringBootApplication
public class X509AuthenticationServer {
    public static void main(String[] args) {
        SpringApplication.run(X509AuthenticationServer.class, args);
    }
}

@Controller
public class UserController {
    @RequestMapping(value = "/user")
    public String user(Model model, Principal principal) {

        UserDetails currentUser
          = (UserDetails) ((Authentication) principal).getPrincipal();
        model.addAttribute("username", currentUser.getUsername());
        return "user";
    }
}

Теперь мы сообщаем приложению, где они могут найти нашkeystore и как к нему можно получить доступ. Мы устанавливаемSSL в состояние «включено» и меняем стандартный порт прослушивания наindicate a secured connection.

Кроме того, мы настраиваемuser-details для доступа к нашему серверу черезBasic Authentication:

server.ssl.key-store=../keystore/keystore.jks
server.ssl.key-store-password=${PASSWORD}
server.ssl.key-alias=localhost
server.ssl.key-password=${PASSWORD}
server.ssl.enabled=true
server.port=8443
security.user.name=Admin
security.user.password=admin

Это будет HTML-шаблон, расположенный в папкеresources/templates:




    X.509 Authentication Demo


    

Hello !

Прежде чем мы закончим этот раздел и посмотрим на сайт, нам все равно нужно установить сгенерированный центр сертификации какtrusted certificate в браузере по нашему выбору.

Пример установки нашегоcertificate authority дляMozilla Firefox будет выглядеть следующим образом:

  1. Введитеabout:preferences в адресной строке

  2. ОткрытьAdvanced → Certificates → View Certificates → Authorities

  3. Нажмите наImport

  4. Найдите папкуexample tutorials и ее подпапкуspring-security-x509/keystore

  5. Выберите файлca.crt и щелкнитеOK

  6. Выберите «Trust this CA to identify websites” и щелкнитеOK»

Note: Если вы не хотите добавлять нашcertificate authority в списокtrusted authorities, позже у вас будет возможность сделатьexception и показать сайт жестким, даже когда он упоминается как небезопасный. Но тогда вы увидите «желтый восклицательный знак» в адресной строке, указывающий на небезопасное соединение!

После этого мы перейдем к модулю spring-security-x509-basic-auth и запустим:

mvn spring-boot:run

Наконец, мы нажимаемhttps://localhost:8443/user, вводим наши учетные данные пользователя изapplication.properties и должны увидеть сообщение“Hello Admin!”. Теперь мы можем проверить статус подключения, щелкнув значок «зеленый замок» в адресной строке, и это должно быть защищенное соединение.

image

 

4. Взаимная аутентификация

В этом разделе мы используемSpring Security, чтобы предоставить пользователям доступ к нашему демонстрационному сайту. Процедура делает форму входа устаревшей.

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

Плюсы:

  • Закрытый ключX.509 client certificate -stronger than any user-defined password. Но это нужно держать в секрете!

  • С сертификатомidentity клиентаis well-known легко проверить.

  • Нет больше забытых паролей!

Минусы:

  • Вы должны помнить, что для каждого пользователя, который должен быть проверен сервером, его сертификат должен быть установлен в настроенномtruststore. Для небольших приложений с небольшим количеством клиентов это возможно,with an increasing number of clients it may lead to complex key-management for users.

  • Закрытый ключ сертификата должен быть установлен в клиентском приложении. Фактически:X.509 client authenticationis device dependent, что делает невозможным использование такого типа аутентификации в общественных местах, например в интернет-кафе.

  • Должен быть механизм для отзыва скомпрометированных клиентских сертификатов.

Чтобы продолжить, мы изменяем нашX509AuthenticationServer, чтобы он продолжался отWebSecurityConfigurerAdapter и переопределял один из предоставленных методов настройки. Здесь мы настраиваем механизмx.509 для анализа поляCommon Name (CN) сертификата для извлечения имен пользователей.

С этими извлеченными именами пользователейSpring Security ищет в предоставленномUserDetailsService подходящих пользователей. Поэтому мы также реализуем этот интерфейс сервиса, содержащий одного демо-пользователя.

Tip: В производственной среде этотUserDetailsService может загружать своих пользователей, например, по ссылке: / spring-jdbc-jdbctemplate.

Вы должны заметить, что мы аннотируем наш класс с помощью@EnableWebSecurity и@EnableGlobalMethodSecurity с включенной предварительной / пост-авторизацией.

С последним мы можем аннотировать наши ресурсы с помощью@PreAuthorize и@PostAuthorize для детального контроля доступа:

@SpringBootApplication
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class X509AuthenticationServer extends WebSecurityConfigurerAdapter {
    ...

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated()
          .and()
          .x509()
            .subjectPrincipalRegex("CN=(.*?)(?:,|$)")
            .userDetailsService(userDetailsService());
    }

    @Bean
    public UserDetailsService userDetailsService() {
        return new UserDetailsService() {
            @Override
            public UserDetails loadUserByUsername(String username) {
                if (username.equals("cid")) {
                    return new User(username, "",
                      AuthorityUtils
                        .commaSeparatedStringToAuthorityList("ROLE_USER"));
                }
            }
        };
    }
}

Как было сказано ранее, теперь мы можем использоватьExpression-Based Access Control в нашем контроллере. В частности, наши аннотации авторизации соблюдаются из-за аннотации@EnableGlobalMethodSecurity в нашем@Configuration: __

@Controller
public class UserController {
    @PreAuthorize("hasAuthority('ROLE_USER')")
    @RequestMapping(value = "/user")
    public String user(Model model, Principal principal) {
        ...
    }
}

Обзор всех возможных вариантов авторизации можно найти вofficial documentation.

В качестве последнего шага модификации мы должны сообщить приложению, где находится нашtruststore и чтоSSL client authentication необходимо (server.ssl.client-auth=need).

Итак, мы помещаем в нашapplication.properties следующее:

server.ssl.trust-store=../keystore/truststore.jks
server.ssl.trust-store-password=${PASSWORD}
server.ssl.client-auth=need

Теперь, если мы запустим приложение и укажем в браузереhttps://localhost:8443/user, мы узнаем, что узел не может быть проверен, и он отказывает в открытии нашего веб-сайта. Таким образом, мы также должны установить нашclient certificate, который показан здесь в качестве примера дляMozilla Firefox:

  1. Введитеabout:preferences в адресной строке

  2. ОткрытьAdvanced → View Certificates → Your Certificates

  3. Нажмите наImport

  4. Найдите папкуexample tutorials и ее подпапкуspring-security-x509/keystore

  5. Выберите файлcid.p12 и щелкнитеOK

  6. Введите пароль для сертификата и нажмитеOK

В качестве последнего шага мы обновляем нашу вкладку браузера, содержащую веб-сайт, и выбираем наш сертификат клиента во вновь открывшемся диалоговом окне выбора.

image

Если мы видим приветственное сообщение типа“Hello cid!”, значит, все прошло успешно!

5. Взаимная аутентификация с помощью XML

Также возможно добавлениеX.509 client authentication кhttp security configuration in XML:


    ...
    

    
        
            
                
            
        
    
    ...

Чтобы настроить базовыйTomcat, мы должны поместить нашиkeystore и нашиtruststore в его папкуconf и отредактироватьserver.xml:

Tip: Если дляclientAuth установлено значение“want”,SSL по-прежнему включен, даже если клиент не предоставляет действительный сертификат. Но в этом случае мы должны использовать второй механизм аутентификации, например форму входа, для доступа к защищенным ресурсам.

6. Заключение

In summary, мы узнали, как создатьkeystore, содержащийcertificate authority иself-signed certificate for our development environment.

Мы создалиtruststore containing a certificate authority and a client certificate, и мы использовали оба параметра дляverify our server на стороне клиентаand our client на стороне сервера.

Если вы изучилиMakefile, вы сможете использоватьcreate certificates, make certificate-requests and import signed certificates, используя Javakeytool.

Кроме того, теперь вы должны иметь возможностьexport a client certificate into the PKCS12 format и использовать его в клиентском приложении, таком как браузер, например,Mozilla Firefox.

И мы обсудили, когда имеет смысл использоватьSpring Security X.509 client authentication, поэтому вам решать, внедрять его в свое веб-приложение или нет.

И в заключение вы найдете исходный код этой статьиon Github.

Related