Писать правильный (и простой) авт/вход класса в PHP


Как писать и дизайн простой (но все-таки корректной и безопасной) класс входа для PHP?

В настоящее время я проверяю, существует ли логин запрос (пользователь ввел данные в форму входа) или сессия уже существует и содержит $_SESSION['подлинности'] == истина;. Если обе проверки не удалось, пользователю не (правильно) вошел в систему. В код:

class Auth {
    private function __construct() {
        // new login
        if(isset($_POST['login'], $_POST['username'], $_POST['password']) && validCSRFToken()) {
            $user = $_POST['username'];
            $password = $_POST['password'];

            if(($row = querySingle('
               SELECT `id`, `password`
               FROM `users` u
               WHERE `nick` = "?"',
               $user)))
               // Crypt::hash checks the salted password
               && Crypt::hash($password, $row['password'])) {
                // credential change (guest -> user) regenerate session id
                session_regenerate_id(TRUE);

                $_SESSION['authenticated'] = TRUE;
                $_SESSION['userid'] = $row['id'];
                $_SESSION['user'] = $user;

                // prevent 'your browser has to re-send some data to display this page'
                redirect($_SERVER['REQUEST_URI']);
            } else {
                $this->logout();
                throw new AuthException('login failed. wrong user/password');
            }
        } else if($_SESSION['authenticated'] && $_SESSION['userid'] > 0 && !empty($_SESSION['user'])) {
            // user already logged in, nothing to see here, move on
        } else {
                    // not logged in!
                    throw new AuthException('not logged in. please login');
        }
    }

    public function logout() {
        $this->authenticated = FALSE;
        $this->user = '';
        $this->userid = 0;

        $this->session->destroy();
        $this->session->regenerate_id(TRUE);
    }
}

Объект авт класса должен быть создан на каждой странице, который требует проверки подлинности от пользователей:

try {
  $auth = new Auth();

  /*
   * rest of the page
   */

} catch(AuthException $ex) {
  // something went wrong during login
  displayError();
  displayLoginForm();
  exit; // halt further execution of script
}

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

Любые улучшения приветствуются, спасибо!

(Пожалуйста, не предлагаю использовать PHP-фреймворками как Codeigniter с, Зенд фреймворк, Кохана, и т. д.)



3584
5
задан 15 августа 2011 в 09:08 Источник Поделиться
Комментарии
2 ответа

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


  1. Вместо того, чтобы напрямую использовать $_POST, гдевы можете принимать их в качестве параметров, таким образом делая его похожим больше из API. Пример использования: если вы хотите, чтобы непосредственно войти в людей, которые просто зарегистрированы. Вы не будете привязаны к какому-то $_POST, где параметры.

  2. Склеп::хэш ...: не видя интерьер этого никто не может прокомментировать много, но со стороны выглядит, соли кажется постоянным, если вы не запрашиваете пользователям столом внутри. Другой (и желательно с длиной подбора пароля) соль для каждого пользователя-это вообще путь в безопасности среды разработки.

  3. Похожие на #1, Вы можете использовать класс-оболочку для $_SESSION использования.

  4. остальное, если($_SESSION['подлинности'] && $_SESSION['id_пользователя'] > 0 && !пустой($_SESSION['пользователь'])): вместо прямых запросов к $_SESSION, вы можете сделать другую функцию Как $этом->isLoggedIn(), так ты будешь более устойчив к будущей сессии и войдите в него изменения (наряду с некоторыми другими льготами).

  5. перенаправление (переменная$_SERVER['REQUEST_URI']); опираясь на в$_SERVER переменной всегда выглядел неуверенным и неустойчивым ко мне. Вы можете использовать здесь какие-либо проверки или использовать некоторые из ваших внутренних навигационных переменных вместо, в случае, если вы не хотите, чтобы сделать его полностью универсален таким образом.

4
ответ дан 15 августа 2011 в 10:08 Источник Поделиться

Я бы также добавить валидацию 'логин', 'username' и 'password' перед выполнением запроса.

2
ответ дан 15 августа 2011 в 02:08 Источник Поделиться