Почему не нужно использовать RJS

    У jQuery есть встроенная фича — если сервер ответит с content-type=text/javascript библиотека выполнит ответ автоматически.

    jQuery.ajaxSetup({
    	accepts: {
    		script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
    	},
    	contents: {
    		script: /(?:java|ecma)script/
    	},
    	converters: {
    		"text script": function( text ) {
    			jQuery.globalEval( text );
    			return text;
    		}
    	}
    }); 
    
    


    Поэтому в рельсах довольно распространена тактика «ответь строчкой Javascriptа вместо правильного JSON, который придется обрабатывать».


    Т.е. ответ от index.js.erb может выглядить так:
    $('#content').html('Hello, id123123')


    image

    А вот тут такая проблема — если я на стороннем сервере вставлю script-тэг с src="/profile.js" то этот запрос вернет валидный джаваскрипт, который выполнится в контексте моей страницы. Чтобы украсть данные достаточно только переобъявить функцию $={html:function(data){ LEAK(data) }};

    Баг присутствовал например на Gitlab, Basecamp, Redmine, Spree, Diaspora. Он мог слить полную форму, которая в свою очередь хранит input type=hidden name=authenticity_token (csrf_token юзера).

    Этот баг по сути перевоплощение JSONP-слития, только менее очевидный для девелоперов. Если у вас есть *.js.* файлы в папке /app/views, вы вероятнее всего уязвимы. Баг исправлен в новой версии RoR.
    Share post

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 16

      +3
      Про какое исправление в какой конкретно новой версии вы говорите?
        0
        Исправлением стало проверка request.xhr? для всех .JS GET запросов. Версию на память не помню, одна из последних.
          0
          Давненько Егор Хомяков не взламывал интернет…
            +7
            Я больше шаловством не занимаюсь. Секурити рисерчер, вери консалтинг, мач индепендент.
            +1
            Заголовок статьи не совсем верный. Это не RJS, который был только в 2.x, это просто JS шаблоны.
              –1
              Да, но люди часто ассоциируют одно с другим. Никто не знает про SJR
                0
                Я сразу и вовсе подумал о r.js (оптимизатор от Require.js). Вводите заголовком в заблуждение.
                  0
                  Егор, RJS сто лет уже никто не использует, ты отстал от жизни.
                    0
                    пост не про RJS. под RJS подразумеваются жс шаблоны и это очевидно
                0
                По мне, вообще порочная практика — возвращать исполняемый код. Я убежден, что общение должно осуществляться данными, а весь код должен лежать отдельно — а для продакшена вообще, отдаваться единым файлом в минимизированном и обфусцированном виде не более одного раза.
                  0
                  DHH так не думает :(
                    +1
                    Для большинства проектов динамичный код не нужен.
                    Мне нравится ответ на первый вопрос здесь: tapestry.apache.org/limitations.html

                    > Q: How do I add new components to an existing page dynamically?
                    (Каким образом я могу добавить новые компоненты на существующую страницу?)
                    >>A: The short answer here is: you don't. The long answer here is you don't have to, to get the behavior you desire.
                    (Коротко: Вы не будете этого делать. Развернуто — а Вам и не нужно так делать, чтобы получить желаемое поведение)
                    и далее:
                    >>What this means is that any incoming request must be handled by a single page instance. Therefore, Tapestry enforces the concept of static structure, dynamic behavior.
                    (Что значит, что любой запрос должен обрабатываться одим экземпляром страницы. Таким образом, Tapestry обязывает придерживаться концепции статичной структуры и динамичного поведения.)

                    В 99% случаев программа не должна генерировать свой (новый) код — только новые данные, обрабатываемые таким кодом, чтобы обеспечивать свое адекватное поведение.
                    0
                    А что если надо будет по этим данным построить нетривиальный кусок html-я?
                    С помощью jquery строить? Неуклюже.
                    Использовать шаблоны на клиентской стороне? А что с дублированием кода тогда? Ведь при первом открытии страницы подобный html уже рендерится на сервере (а часто и кэшируется!), и его можно использовать в таких js-ответах.

                    Плюс в случае проблем явно видно где искать. Желаю Вам не сталкиваться с проектами где весь js-код запихан изначально в один super-main-script.js файл и в нем ничего не найти сразу.

                    Так что не будьте так категоричны.
                      0
                      Согласен, почему-то обычно все поучительные комментарии (не в укор автору) оканчиваются на предыдущем комментарии. Тестирование этого кода кстати так же немаловажно.
                    0
                    Написал и initializer для Rails 3.2, который защищает от этой уязвимости.

                    Для Rails 4.0 достаточно просто сохранить raw2.github.com/rails/rails/4f4fdd643f9d19fbbeeec3ac77674f791c9beffa/actionpack/lib/action_controller/metal/request_forgery_protection.rb в config/initializers/unauthorized_cross-origin_response_fix.rb

                    Only users with full accounts can post comments. Log in, please.