CSRF (подделка межсайтовых запросов)

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

JWT (веб-токен JSON)

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

Генерация CSRF

Если вы хотите успешно атаковать, без этих трех шагов не обойтись.

  • Сначала войдите на сайт жертвы. Если веб-сайт жертвы представляет собой механизм аутентификации пользователя на основе файлов cookie, то при успешном входе пользователя в систему браузер сохраняет SESSIONID сервера.
  • Во-вторых, на этот раз веб-сайт злоумышленника открывается в том же браузере, хотя он не может получить то, что такое SESSIONID (поскольку файл cookie только с http недоступен для JavaScript), но любой из браузера на веб-сайт жертвы. В запросе он будет содержать свой файл cookie, независимо от того, с какого веб-сайта он был отправлен.
  • В-третьих, используя этот принцип, на веб-сайт злоумышленника отправляется запрос, чтобы заставить веб-сайт жертвы выполнить некоторые конфиденциальные операции. Поскольку запрос, сделанный в это время, находится в сеансе, любой запрос будет выполняться, пока у пользователя есть разрешение.

Например, откройте Youku и войдите в систему. Затем откройте сайт злоумышленника, он содержит <img>tag, например:

<img src="http://api.youku.com/follow/123" />

Этот api - всего лишь пример. Конкретный URL-адрес и параметры можно определить заранее с помощью инструментов разработчика браузера (функция сети). Если его роль состоит в том, чтобы позволить вошедшему в систему пользователю обратить внимание на программу или пользователя, определенного 123, то внимание этой программы будет продолжать повышаться за счет атак CSRF.

Объясните два момента. Во-первых, почему этот пример не связан с банковской операцией с деньгами? Очень просто, потому что легко угадать. Для злоумышленника ничто не может быть успешным, например SQL-инъекция, злоумышленник не знает, как устроена база данных веб-сайта, но обычно он пытается на собственном опыте, например, многие веб-сайты устанавливают первичный ключ пользователя для user_id или sys_id. , так далее.

Банковские операции часто подтверждаются несколькими способами, такими как графический проверочный код, проверочный код мобильного телефона и т. Д. Завершить атаку CSRF - это просто фантастика. Но другие типы веб-сайтов часто сознательно не защищают от этих проблем. Хотя получить финансовую выгоду сложно, CSRF может сделать еще много вещей. Например, использование кого-то другого для создания поддельного Weibo и добавления друзей может принести пользу злоумышленнику.

Во-вторых, как убедиться, что пользователь открывает веб-сайт злоумышленника после открытия Youku? Не могу. В противном случае любой, кто откроет Youku, необъяснимым образом обратит внимание на шоу. Но вы должны знать, что цена этой атаки - это просто вызов API. Он может появиться везде. Вы можете скачать изображение откуда угодно, позволить вам запросить этот адрес, и вы можете видеть его, не глядя на него. Пока что?

CSRF защита

Обычно есть три способа защититься от CSRF.

Судите Referer в заголовке запроса

В этом поле записывается источник запроса. Например, http://www.example.com вызывает интерфейс Google http://api.map.google.com/service. Затем на сервере Google вы можете использовать Referer, чтобы определить, откуда пришел запрос.

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

Вы можете использовать фильтр (древняя технология) в сервлетах Java; вы можете строить перехватчики с помощью Spring; в промежуточном программном обеспечении это называется промежуточным программным обеспечением, и это значение получается с помощью request.get ('referer'). На самом деле поток каждой технологии одинаков.

Однако следует отметить, что Referer устанавливается браузером. В эпоху, когда совместимость браузеров сильно отличается, и если есть браузер, который позволяет пользователю изменять это значение, уязвимость CSRF все еще существует.

Добавить токен csrf в параметр запроса

Обсудите запросы GET и POST. Для GET действительно нечего защищаться. Почему? Поскольку GET рассматривается как операция запроса в «соглашении», смысл запроса состоит в том, что вы проверяете его один раз, проверяете дважды и бесчисленное количество раз, результат не изменится (данные, полученные пользователем, могут измениться), это не будет против базы данных. Произведите какое-либо влияние, поэтому нет необходимости добавлять другие дополнительные параметры.

Итак, чтобы напомнить вам, постарайтесь следовать этим соглашениям, не появляйтесь в словах GET request / delete, / update, / edit. Поместите операцию «запись» в POST.

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

<form method="post" action="/delete">
  <!-- Other fields -->
  <input type="hidden" name="csrftoken" value="Generated by the server"/>
</form>

Этот html-фрагмент создается сервером, например JSP, PHP и т. Д. Для Node.js это может быть Jade.

Это действительно хорошая мера предосторожности, и если вы добавите некоторую обработку, вы можете предотвратить повторную отправку формы.

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

Добавить заголовок HTTP

Идея состоит в том, что токен помещается в заголовок запроса, и сервер может получить заголовок запроса точно так же, как Referer. Разница в том, что токен генерируется сервером, поэтому злоумышленник не может угадать.

Другой объект этой статьи, JWT, основан на этом подходе. Помимо JWT, это работает так:

Объясните четыре запроса, типы - POST.

  1. Через интерфейс / login пользователь входит в систему, сервер возвращает access_token, а внешний интерфейс сохраняет его, который может быть в памяти, если вы хотите имитировать сеанс. Его также можно сохранить в localStorage, чтобы был возможен автоматический вход.
  2. Вызвать интерфейс / delete, параметр - это идентификатор элемента. Присмотритесь, в этом запросе есть заголовок с именем Authoriaztion, значением которого является access_token, который был ранее отправлен обратно с сервера, и перед ним добавлен «Bearer» (это соглашение с сервером, соглашение в том, что если вы это скажете, добавьте это и сложите вместе. Если вы не добавите это, вы не добавите это ...)
  3. Вызовите интерфейс / logout и передайте access_token в заголовке. После успеха и сервер, и клиентская часть аннулируют токен или удаляют его напрямую.
  4. Снова вызывается интерфейс / delete. Поскольку в это время нет access_token, сервер определяет, что запрос не имеет разрешения, и возвращает 401.

Вы обнаружили, что весь процесс от начала до конца не включает файлы cookie, поэтому CSRF невозможен!

О соглашениях JWT

Если вас не интересует JWT, то статью можно закончить, потому что, увидев здесь, помимо содержания, упомянутого в заголовке главы, вы также можете ввести несколько моментов: во-первых, подумайте больше при разработке API; во-вторых, use Token - это единый вход; в-третьих, cookie и токен отличаются от механизма аутентификации пользователя.

А JWT на самом деле является соглашением для нового заголовка HTTP. Например, параметры в запросе GET должны быть разделены символом &, но можете ли вы использовать что-нибудь еще? Конечно, вы можете использовать запятую или точку с запятой, и сервер установит правило экранирования. Однако соглашение заключается в том, чтобы позволить всем делать вещи более стандартно. Если вы следуете правилам, вам нужно изменить код, который вам нужно изменить, с одного инструмента на другой. Я не буду здесь вдаваться в подробности.

Три компонента

Этот веб-сайт содержит наиболее официальное описание терминологии и содержания JWT.

Каждая часть JWT представляет собой строку, разделенную точками, поэтому ее формат выглядит следующим образом:

XXX1.XXX2.XXX3

Вся строка является URL-безопасной, поэтому ее можно использовать непосредственно в параметрах запроса GET.

Первая часть заголовка JWT

Это объект JSON, который представляет тип и алгоритм шифрования всей этой строки, например

{
  "typ":"JWT",
  "alg":"HS256"
}

После шифрования base64url

eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9

Вторая часть набора заявлений JWT

Это также объект JSON, который однозначно представляет пользователя, например

{
  "iss": "123",
  "exp": 1441593850
}

После шифрования base64url

eyJpc3MiOiIxMjMiLCJleHAiOjE0NDE1OTM4NTB9

На официальном сайте есть подробные описания атрибутов, попробуйте использовать зарегистрированные имена утверждений, упомянутые внутри, что может улучшить чтение. Здесь iss представляет эмитента, то есть человека, инициировавшего запрос. Его ценность связана с бизнесом, поэтому зависит от вашего приложения. Exp представляет собой время истечения срока, то есть когда оно истекает. Обратите внимание, что это значение представляет собой количество секунд, а не количество миллисекунд, поэтому оно находится в целочисленном диапазоне.

Третья часть подписи JWS

Вычисление этой сигнатуры связано с атрибутом alg в первой части. Если это HS256, серверу необходимо сохранить закрытый ключ, например секретный. Затем, после того как две строки, сгенерированные первой частью и второй частью, соединены точками, а затем объединены с закрытым ключом, следующая строка может быть получена с использованием шифрования HS256.

AOtbon6CebgO4WO9iJ4r6ASUl1pACYUetSIww-GQ72w

Теперь сборка из трех частей, с .connection, получает полный токен.

Пример 1/2: Использование Express в качестве сервера

Для сервера уже существуют различные библиотеки для поддержки JWT. Рекомендуются следующие:

Java: Maven com.auth0 / java-jwt / 0.4
PHP: композитору требуется lcobucci / jwt
Ruby: Gem install jwt
.NET: Install-Package System.IdentityModel.Tokens.Jwt
Node.js: npm install jsonwebtoken

Если у вас есть предыдущий опыт работы с Node.js и Express, следующий код должен быть легким для понимания.

var express = require('express'),
    jwt     = require('jsonwebtoken');
var router      = express.Router(),
    PRIVATE_KEY = 'secret';
router.post('/login', function(req, res, next) {
    // generate JWT
    var token = jwt.sign({
        iss: '123'
    }, PRIVATE_KEY, {
        expiresInMinutes: 60
    });
    // Return JWT to the front end
    res.send({
      access_token: token
    });
});
router.post('/delete', function(req, res, next) {
    var auth    = req.get('Authorization'),
        token   = null;
// Determine if there is an Authoriaztion field in the request header, and reduce other verification in order to shorten the code.
    if (auth) {
        token = /Bearer (.+)/.exec(auth)[1];
        res.send(jwt.decode(token));
    } else {
        res.sendStatus(401);
    }
});

См. Руководство по использованию jsonwebtoken.

В примере определены два API.

  • / login, который возвращает строку JWT. Он содержит идентификатор пользователя и время жизни, на этот раз будет преобразовано в exp и iat (проблема в момент запроса), разница между ними - время выживания.
  • / delete, проверяет, есть ли поле авторизации в заголовке запроса, и является ли оно законным, если есть, запрос обрабатывается, в противном случае возвращает 401.

Обратите внимание, что ожидаемый сервером заголовок запроса Authororiaztion имеет следующий формат:

Authorization: Bearer XXX1.XXX2.XXX3

Это не имеет ничего общего с JWT и является форматом OAuth 2.0. Поскольку поле авторизации также сокращено, оно состоит из типа и значения токена. Помимо упомянутого выше Bearer, существуют Basic, MAC и так далее.

Пример 2/2: Backbone как интерфейс

Интерфейсная работа разделена на два аспекта: один - хранить jwt, а другой - добавлять Authoriaztion ко всем заголовкам запросов.

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

Возьмем, к примеру, Backbone.

// Save the original sync method first
var sync = Backbone.sync;
Backbone.sync = function (method, model, options) {
  var token = window.localStorage.getItem('jwt');
  // If there is a token, add it to the request header
  if (token) {
    options.headers.Authorization = 'Bearer ' + token;
  }
  // Call the original sync method
  sync(method, model, options);
};

Дополнительная обработка по доменам

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

Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Authorization

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

Если сервер использует nginx, то эти конфигурации можно записать в файл nginx.conf. Если настроено в коде, и Java, и Node.js имеют метод response.setHeader.

Резюме

Мое понимание веб-безопасности не слишком глубокое, поэтому у меня нет большого опыта, о котором можно было бы говорить. Безопасность - это область, которую редко ценят, потому что приоритетом при завершении проекта всегда является: Функция ›Ценность› Производительность, Безопасность. По крайней мере, убедитесь, что пользователь не сделает ошибок во время использования, а затем сделает круто или свежо, производительность и безопасность учитываются только тогда, когда выполняются первые два пункта или когда они неизбежны. Когда сервер не может позволить себе такую ​​высокую нагрузку, он добавит больше серверов, но бизнес-функции не могут быть меньше с самого начала.

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

Одно из слов, неоднократно упоминаемых в этой статье, - «соглашение», что, кажется, противоречит пункту «традиционный специфический анализ», сумма….

Соглашение - это консенсус между людьми, например, запрос GET, тогда первая реакция другой стороны - это запрос. Когда кто-то разрушает контракт и использует запрос GET для выполнения операции удаления, это затрудняет понимание другими (когда много людей, которые делают это, понять нетрудно…). Или, когда мы упоминаем JWT, он должен состоять из трех частей. Если кто-то просто генерирует токен в соответствии со своим собственным алгоритмом и может также однозначно идентифицировать пользователя, то он должен объяснить это как коллега. Безопасность алгоритмов, способы использования и т. Д.

С другой стороны, если вы действительно чувствуете, что не обязательно делать что-то в соответствии с «условностями», это слишком много проблем, и вы можете принять последствия «умной игры», тогда делайте это в соответствии со своими собственными идеями. (правда больше не рассматриваю).

Почему HTML5 добавил так много семантических тегов, потому что все движется в более общем направлении.