Разбираем магических зверей безопасности: AuthZ: abac/rbac, AuthN и 2FA

90505fcb591c7521cdff2e9461b8ee02

Вы знаете, что меня действительно выбивает из колеи забавит? Даже люди, которые давно работают в IT, путают аутентификацию и авторизацию. На пару проектах я столкнулся с тем, что некоторые ребята, которые работают в индустрии годами, не видят разницы между этими двумя понятиями. И это не просто «я офигеваю» озадачивает — это может быть опасно для безопасности систем, так как из за ложного определения мысли производят совсем не однозначные выводы.

Аутентификация (AuthN) — это способ подтвердить, что вы действительно тот, за кого себя выдаете. Это паспорт в цифровом мире: пароли, различная биометрия и другие экзотические способы — все это примеры аутентификации. Это как сказать: «Привет, это я!»

Авторизация (AuthZ) — это уже другой зверь. Это про то, что вы можете делать после того, как подтвердили свою личность. Представьте, что вы вошли в интернет-магазин. А вот теперь вопрос: можете ли вы просто просматривать товары, добавлять их в корзину или у вас есть доступ к админ-панели для изменения ассортимента? Это и есть авторизация — правила, которые определяют, какие действия вам доступны.

Зачем важно понимать разницу? Потому что, когда путаются эти понятия, возникают большие проблемы. Например, если вы путаете, кто может войти в систему (аутентификация) с тем, что этот пользователь может делать (авторизация), вы открываете двери для множества уязвимостей. Так что давайте раз и навсегда проясним: аутентификация и авторизация — это разные вещи, и понимать их разницу важно для обеспечения безопасности вашего ПО. Также очень классно разбирают данный вопрос в статье Authn vs. authz: How are they different? By Cloudflare!

Аутентификация (AuthN)

Прежде чем пользователи смогут взаимодействовать с вашим ПО, необходимо убедиться, что они являются теми, за кого себя выдают. Это и есть аутентификация (Authentication, AuthN). Примеры с паролем один из базовых, скажем так один из способов первого фактора.

Простой пример аутентификации на spring security который мало вероятно будет сейчас в Production! Но как пример для наглядного понимания имеет место быть, далее в статье буду применять простые снипеты и оставлять ссылки на более богатые варианты =)

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("user").password("{noop}password").roles("USER")
            .and()
            .withUser("admin").password("{noop}admin").roles("ADMIN");
    }
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/", "/home").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
            .logout()
                .permitAll();
    }
}

Достаточно хороший подход расписан в этом варианте и еще более информативнее в данной репе.

Как вы знаете современные системы безопасности все чаще переходят к использованию двухфакторной аутентификации (2FA) для повышения уровня защиты. Однофакторная аутентификация, такая как использование только пароля, больше не считается достаточно надежной из-за множества уязвимостей, связанных с паролями (например, их кража или перебора).

2FA добавляет дополнительный уровень безопасности, требуя второй способ проверки личности пользователя. Обычно это второй фактор из другой категории, например:

  • Что-то, что вы знаете: Пароль или PIN-код.

  • Что-то, что у вас есть: Смартфон или токен.

  • Что-то, что вы являетесь: Биометрические данные, такие как отпечатки пальцев или распознавание лица.

Отправка СМС

public class TwoFactorAuthenticationService {

    // Метод для отправки SMS
    public void sendSmsCode(String phoneNumber) {
        String code = generateCode();
        // Логика для отправки SMS
        SmsSender.send(phoneNumber, "Ваш код подтверждения: " + code);
        // Сохранение кода в базе данных или кэше
        saveCode(phoneNumber, code);
    }

    // Генерация случайного кода
    private String generateCode() {
        // Логика генерации кода
        return String.valueOf(new Random().nextInt(999999));
    }

    // Сохранение кода
    private void saveCode(String phoneNumber, String code) {
        // Логика сохранения кода (например, в базе данных или кэше)
        CodeRepository.save(phoneNumber, code);
    }
}

Проверка той самой СМС

@RestController
@RequiredArgsConstructor
public class TwoFactorAuthenticationController {

    private TwoFactorAuthenticationService twoFactorAuthService;

    // Метод для проверки кода
    @PostMapping("/verifyCode")
    public ResponseEntity verifyCode(@RequestParam String phoneNumber, @RequestParam String code) {
        boolean isCodeValid = twoFactorAuthService.verifyCode(phoneNumber, code);
        if (isCodeValid) {
            return ResponseEntity.ok("Код подтвержден успешно");
        } else {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Неверный код");
        }
    }
}

@Service
public class TwoFactorAuthenticationService {

    // Метод для проверки кода
    public boolean verifyCode(String phoneNumber, String code) {
        String savedCode = getCode(phoneNumber);
        return code.equals(savedCode);
    }

    // Получение кода из базы данных или кэша
    private String getCode(String phoneNumber) {
        // Логика получения кода
        return CodeRepository.findByPhoneNumber(phoneNumber);
    }
}

Да да это все еще псевдокод, тут этот момент разбирается более наглядно.

Понятное дело что 2FA это не предел, не зря ведь есть термин MFA и тут уже все зависит от потребности бизнеса конкретному к вашему ПО.

Авторизация (AuthZ)

После того как пользователь прошел аутентификацию, следующей важной задачей является авторизация (Authorization, AuthZ). Авторизация определяет, что пользователь может делать в системе, к каким ресурсам у него есть доступ и какие действия он может выполнять. Представьте, что вы вошли в интернет-магазин. А вот теперь вопрос: можете ли вы просто просматривать товары, добавлять их в корзину или у вас есть доступ к админ-панели для изменения ассортимента? Это и есть авторизация — правила, которые определяют, какие действия вам доступны.

Role-Based Access Control (RBAC)

RBAC, или управление доступом на основе ролей, предоставляет доступ к ресурсам в зависимости от ролей (пользователь, модератор, администратор и так далее), назначенных пользователю. Это один из наиболее распространенных методов авторизации.

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .requestMatchers("/", "/home").permitAll()
                .requestMatchers("/user/**").hasRole("USER")
                .requestMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
            .logout()
                .permitAll();
    }
}

Attribute-Based Access Control (ABAC)

ABAC, или управление доступом на основе атрибутов, предоставляет доступ на основе атрибутов пользователя, ресурсов и окружающей среды. Этот метод позволяет более гибко управлять доступом.

// Пример реализации ABAC может включать сложные правила на основе атрибутов, 
// таких как должность пользователя, время дня или местоположение.

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .requestMatchers("/", "/home").permitAll()
                .requestMatchers("/user/**").access("hasRole('USER') and hasIpAddress('192.168.1.0/24')")
                .requestMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
            .logout()
                .permitAll();
    }
}
// Здесь мы указываем, что доступ к URL, начинающимся с "/user/**", 
// разрешен только пользователям с ролью "USER" и IP-адресом из подсети 
// "192.168.1.0/24". Это пример использования атрибутов для контроля доступа.

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .requestMatchers("/", "/home").permitAll()
            .requestMatchers("/user/**").access("hasRole('USER') and hasIpAddress('192.168.1.0/24')")
            .requestMatchers("/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated()
            .and()
        .formLogin()
            .loginPage("/login")
            .permitAll()
            .and()
        .logout()
            .permitAll();
}

Таким образом, современные системы безопасности могут использовать различные подходы к авторизации, чтобы обеспечить гибкость и защиту. Также более наглядный пример RBAC/ABAC можно найти в данном материале.

Вот что в итоге Карл!

Аутентификация и авторизация — два различных процесса, которые играют ключевые роли в обеспечении безопасности ваших систем. Несмотря на то, что они часто упоминаются вместе, их цели и методы кардинально различаются.

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

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

© Habrahabr.ru