это все, что мне нужно сделать, чтобы предотвратить атаки CSR с php и ajax? - PullRequest
4 голосов
/ 04 марта 2012

Я использую Codeigniter, и я включил CSRF через его config.php файл ...

$config['csrf_protection'] = TRUE;
$config['csrf_token_name'] = 'csrf_token_name';
$config['csrf_cookie_name'] = 'csrf_cookie_name';

, затем по моим запросам ajax я получаю cookie name

var cct = $.cookie('csrf_cookie_name');

и parameters:

csrf_token_name : cct

Мой вопрос: нужно ли мне что-то еще делать или все?

Ответы [ 2 ]

7 голосов
/ 07 марта 2012

Хорошо, большинство общего случая (или проще всего реализовать) CSRF выглядит примерно так:

<img src="http://bank.example.com/withdraw?account=bob&amount=1000000&for=Fred" />

Так что, если вы предполагаете, что вы вошли в bank.example.com ваши куки "живы" и будут отправлены с запросом, поэтому запрос будет делать то, что хочет злоумышленник, поэтому:

Файлы cookie не защитят вас от CSRF

Что можетвы делаете:

Посылайте столько запросов через POST, сколько можете (не мешая пользователю), особенно редактирование, создание и удаление.Проще скрыть безопасность в input type='hidden', чем в URL.

Проверить referrer (да, эта небольшая вещь предотвращает вас почти от каждой атаки CSRF со стороны внешних сайтов):

$url = parse_url( isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '');
if( isset( $url['host']) && ($url['host'] == $_SERVER['SERVER_NAME'])){
   // Request have a go
}

Добавьте временные токены безопасности к URL-адресам, подобным этому /article/delete/25/axdefm ...

Если вы потратили некоторое время на генерацию хороших URL-адресов, вы будете отправлены, потому что это просто приведетих, и это вызывает некоторые проблемы, такие как:

  • несколько действий в то время
  • поток запросов на новый токен безопасности
  • как долго разрешать токенlive

Solution

Вы можете создать таблицу для токенов безопасности, например, такую:

tokens (
  id INT,
  user_id INT,
  created DATETIME,
  expires DATETIME, -- One of those two should be enough
  value CHAR(30),
  PRIMARY (id),
  FOREIGN KEY (user_id) ...
);

И когда для какого-либо действия потребуется авторизационный токен, вы загрузитепоследний из БД или создайте новый, допустим, вы создадите новый токен, только если все доступные токены старше 15 минут:

function getToken( $userId, $eventIdentificator){
    // Hope this is self explanatory :)
    $db->deleteExpiredTokens();

    // Try to load token newer than 15 minutes
    $row = $db->fetchRow( 'SELECT value FROM tokens WHERE created >= ADD_INTERVAL( NOW(), -15 MINUTES) AND user_id = ?', array( $userId));

    // createToken will return `value` directly
    if( !$row){
        $row = createNewToken( $userId);
    } else {
        $row = $row['value'];
    }

    // Real token will be created as sha1( 'abacd' . 'delete_article_8');
    return sha1( $row . $eventIdentificator);
}

echo 'url?token=' . getToken( $userId, 'delete_article_' . $article['id']);

Как это будет действовать:

  • если вы будете запрашивать токен безопасности для того же действия в течение 15 мильЧерез несколько минут вы получите тот же токен
  • , который вы получите уникальный токен для каждого действия
  • , если вы установите срок действия токена на 4 часа, токен будет активен с 3:45 до 4: 00
  • если злоумышленник попытается отправить вам 200000 запросов токенов за одну минуту, у вас останется только одна строка в базе данных
  • , каждый пользователь будет иметь максимум 16 записей в таблице одновременно

Как проверить токен?

function checkToken( $userId, $eventIdentificator, $token){
    $db->deleteExpiredTokens();

    // Just find matching token with brute force
    $rs = $db->fetch_rowset( 'SELECT value FROM tokens WHERE created >= ADD_INTERVAL( NOW(), -15 MINUTES) AND user_id = ?', array( $userId));
    while( $row = $rs->fetch_row){
       if( $token == sha1( $row['value'] . $eventIdentificator)){
           return true;
       }
    }
    return false;
}

Если вы не хотите, чтобы действие не повторялось дважды (например, редактирование статьи, это прекрасно работает для удаления), просто добавьтеrevision_number или что-то похожее на ваше $eventIdentificator).

Попробуйте подумать, что произойдет, если:

  • злоумышленник запросит МНОГИ токенов
  • пользователь напишет статьюв течение нескольких часов
  • если у вас есть таблица с кнопками удаления для сотен статей

Я бы пошел с упомянутой системой токенов, это похоже на сбалансированное решение между пользователемкомфорт / сложность реализации и безопасность, комментарии с идеями иожидаются заметки:)

4 голосов
/ 07 марта 2012

Самый распространенный метод предотвращения атак подделки межсайтовых запросов (CSRF) - добавлять непредсказуемые токены запроса к каждому запросу и связывать их с сеансом пользователя.я думаю, что все в порядке; -)

...