2015-11-12 4 views
1

Я пытаюсь заставить AngularJS работать с Gorilla CSRF для моего веб-приложения, но документации, которую я могу найти, не так много, поэтому я не уверен, с чего именно начать. Должен ли я установить X-CSRF-Token для каждого запроса GET или должен ли я просто делать это, когда пользователь посещает домашнюю страницу, как сейчас? Кроме того, как я могу заставить работу AngularJS CSRF работать с Gorilla CSRF? Нужно ли мне делать какие-то сравнения? Будут оценены любые примеры кодов.Горилла CSRF с AngularJS

Вот мой код:

package main 

import (
    "github.com/gorilla/csrf" 
    "github.com/gorilla/mux" 
) 

func main() { 
    r := mux.NewRouter() 


    r.HandleFunc("/", Home).Methods("GET") 
    // Other routes handling goes here 

    http.ListenAndServe(":8000", 
     csrf.Protect([]byte("32-byte-long-auth-key"))(r)) 
} 

func Home(w http.ResponseWriter, r *http.Request) { 

    w.Header().Set("X-CSRF-Token", csrf.Token(r)) 
} 
// More routes 

ответ

5

Ты вопрос может быть немного широк, но в целом вы злоупотребляя инструменты, так что я просто буду пытаться объяснить основные идеи. Используемое приложение использует шаблон «двойного представления» для защиты CSRF. Это требует изменений как на базе кода клиента, так и на сервере. Серверу не следует устанавливать заголовок X-CSRF-Token, то есть роль клиента. Недавно я реализовал пару с нуля анти-CSRF-решений, и они довольно просты (оба шаблона двойного представления). Я также использовал несколько пакетов от таких поставщиков, как MSTF и Apache (им пришлось внедрять CSRF как 20-летние приложения на всех типах стеков).

В двойном шаблоне отправки сервер должен установить cookie со случайным значением (например, guid), файл cookie должен быть помечен как безопасный. Вы также можете сделать это httponly, но это потребует от вас гораздо больше работы над вашими внешними ресурсами. На стороне клиента самый простой способ справиться с этим - реализовать некоторый JavaScript, который считывает значение cookie и добавляет его как заголовок перед любым запросом POST. Вам не нужно защищать GET как правило. Вы могли бы, но если ваш GET выполняет конструктивные/разрушительные действия на стороне сервера, тогда вы неправильно используете HTTP-глагол, и я бы исправил это, сделав эти запросы POSTS вместо того, чтобы пытаться защитить каждый отдельный запрос.

На стороне сервера лучше всего проверить CSRF спереди, в общем месте, где входят все запросы. Когда приходит POST, сервер должен читать значение cookie, проверять значение заголовка и сравнивать их. Если они равны, то запрос должен быть пропущен, если нет, то вы должны загрузить их с помощью 403 или что-то в этом роде. После этого сервер должен переписать значение cookie (лучше всего использовать его только для использования).

У вашего сценария на стороне клиента может быть что-то вроде кода ниже, просто убедитесь, что ресурс загружен на каждую страницу, и вы не используете формы, и это будет охватывать все. Если вы отправляете формы, для этого вам понадобится другой код. Некоторые подходы предпочитают записывать значение на стороне сервера DOM. Например, в .NET библиотека CSRF делает значение HTTPOnly и Secure и ожидает, что разработчики помещают токен владельца места в каждой отдельной форме в каждый отдельный файл cshtml в своем проекте ... Я лично считаю, что это очень глупо и неэффективно. Независимо от того, как вы это делаете, вам, вероятно, придется выполнять какую-то специальную работу. Угловой не собирается реализовывать переднюю часть библиотеки CSRF горилл. gorilla, вероятно, не будет поставляться с JavaScript для вашего клиента, так как это библиотека API. Во всяком случае, базовый пример JavaScript;

// three functions to enable CSRF protection in the client. Sets the nonce header with value from cookie 
// prior to firing any HTTP POST. 
function addXMLRequestCallback(callback) { 
    var oldSend; 
    if (!XMLHttpRequest.sendcallback) { 
     XMLHttpRequest.sendcallback = callback; 
     oldSend = XMLHttpRequest.prototype.send; 

     // override the native send() 
     XMLHttpRequest.prototype.send = function() { 
      XMLHttpRequest.sendcallback(this); 

      if (!Function.prototype.apply) { 
       Function.prototype.apply = function (self, oArguments) { 
        if (!oArguments) { 
         oArguments = []; 
        } 
        self.__func = this; 
        self.__func(oArguments[0], oArguments[1], oArguments[2], oArguments[3], oArguments[4]); 
        delete self.__func; 
       }; 
      } 

      // call the native send() 
      oldSend.apply(this, arguments); 
     } 
    } 
} 

addXMLRequestCallback(function (xhr) { 
    xhr.setRequestHeader('X-CSRF-Token', getCookie('X-CSRF-Cookie')); 
}); 

function getCookie(cname) { 
    var name = cname + "="; 
    var ca = document.cookie.split(';'); 
    for (var i = 0; i < ca.length; i++) { 
     var c = ca[i]; 
     while (c.charAt(0) == ' ') c = c.substring(1); 
     if (c.indexOf(name) == 0) return c.substring(name.length, c.length); 
    } 
    return ""; 
} 

Теперь, если вы можете сузить вопрос немного, я могу предоставить некоторые более конкретные указания, но это только предположение (возможно, я буду читать их документы, когда у меня есть минута). Gorilla автоматически собирается установить ваш файл cookie и выполнить проверку на сервере, если вы используете csrf.Protect. Код, который вы задаете для заголовка в Go, для этого вам нужен JavaScript. Если вы установите заголовок на стороне сервера, вы не обеспечили безопасность вообще. Это должно произойти в браузере. Если вы отправляете стоимость вместе со всеми вашими запросами, горилла, скорее всего, покроет остальное для вас.

Некоторые другие случайные мысли о пространстве проблемы.Как правило, если злоумышленник не может воспроизвести запрос, они, вероятно, не смогут использовать CSRF. Вот почему этот простой метод настолько эффективен. Каждый входящий запрос имеет ровно одно случайное значение GUID, которое требуется для прохождения. Вы можете сохранить это значение в файле cookie, чтобы не беспокоиться о сеансе, перемещающемся по ect серверов (для чего потребуется общая сторона сервера хранилища данных, если вы не используете шаблон двойного представления, это значение для сравнения файлов cookie). Нет никаких реальных шансов на то, что это значение будет принудительным с использованием существующих аппаратных ограничений. Политика одиночного происхождения в браузерах не позволяет злоумышленникам читать установленное вами значение cookie (только сценарии из вашего домена смогут получить к нему доступ, если он установлен как безопасный). Единственный способ воспользоваться этим - это то, что пользователь ранее использовал XSS, что я имею в виду, вроде поражения цели CSRF, поскольку у атакующего уже будет больше контроля/умения делать вредоносные вещи с помощью XSS.

+0

«Если вы установите заголовок на стороне сервера, вы не обеспечили безопасность вообще». это неверно - он передается по тому же каналу (который должен быть HTTPS), поскольку cookie есть, поскольку значение cookie также является заголовком. – elithrar

+0

@elithrar, если вы установили значение на стороне сервера, вы вообще не внедрили функцию безопасности. Двойной шаблон отправки основан на идее, что вы собираетесь предоставить клиенту секретную ценность, о которой только может знать. Когда приходит запрос, вы будете проверять это значение. Это гарантирует, что злоумышленник не может просто подделывать запросы к вашему API. – evanmcdonnal

+0

@elithrar, смотрящий на код, OP устанавливает заголовок ответа. Я не уверен, что это безопасно, но я не думаю, что это слишком важно. Соглашение состоит в том, чтобы выровнять значение в файле cookie. Нет никаких оснований для того, чтобы он был заголовком, и учитывая, что я не знаю, как управление заголовками контролируется браузером, я не собираюсь его размещать, когда безопасный и/или httponly cookie является отраслевым стандартом. Сервер ставит значение в cookie, клиент отправляет его в заголовок. Не изобретайте велосипед, он уже круглый. – evanmcdonnal