Content Security Policy, для зла

    Есть такой специальный хедер для безопасности вебсайтов CSP.

    CSP ограничивает загрузку каких либо ресурсов если они не были пре-одобрены в хедере, то есть отличная защита от XSS. Атакующий не сможет загрузить сторонний скрипт, inline-скрипты тоже отключены…

    На уровне браузера вы можете разрешить только конкретные урлы для загрузки а другие будут запрещены. Помимо пользы этот механизм может принести и вред — ведь факт блокировки и есть детекция! Осталось только придумать как ее применить.


    function does_redirect(url, cb){
      var allowed = url.split('?')[0];
      var frame = document.getElementById('playground');
      window.cb = cb;
      window.tm = setTimeout(function(){
      	window.cb(false);
      },3000);
      frame.src = 'data:text/html,<meta http-equiv="Content-Security-Policy" content="img-src '+allowed+';"><img src="'+url+'" onerror=parent.postMessage(1,"*") onload=parent.postMessage(2,"*")>'
    }
    
    

    Мы можем узнать редиректит ли конкретный URL на другой, а в некоторых случаях даже посчитать конкретный URL путем брутофорса от 1 до миллиона например (больше — займет много времени)

    Попробуйте демо страницу.

    Самое крутое в этом баге что его невозможно «правильно» исправить. Он основан на детекции загрузился ли ресурс или нет, а задача CSP блокировать ресурс, что не дает ему загрузиться. Единственным решением я вижу «эмуляцию» onload события, можно попробывать редиректить на data:, URL как это сделали с похожим моим багом в XSS Auditor (интересный баг кстати, и все еще не исправленный).

    В данный момент никаких защит не введено, значит мы еще долгое время сможем детектить ID пользователя на многих ресурсах и является ли он пользователем SomeSite. Работает в Firefox, Safari и Chrome, поддержка в IE очень ограничена но они скоро это исправят.

    Комментарии 20

      +22
      Противоречивые эмоции вызывают у меня статьи Хомякова. Вроде бы вещи правильные пишет, проблемы реальные указывает. А мысли свои связно выражать не умеет совершенно. Текста всего полстраницы, а читать труднее, чем тома классиков. Может поэтому баги им зарепорченные не исправляют, пока не обнародует и не найдутся люди, которые нормально изложат?
        +9
        А я уже думал это я такой глупый, что перечитываю предложения по три раза.
          +1
          Я стараюсь писать коротко. Как написать тоже самое но другими словами, например? Я может пишу с плохой грамматикой но технические вещи называю довольно внятно же
            +21
            Грамматика это еще не все. Есть, например, стилистика — построение предложений и выбор слов. Но даже в технической части вы умудрились не привести напрямую даже банального примера, который в одно предложение бы все объяснил. Такая подача материала очень сильно затрудняет понимание.

            Сравните, по-моему даже короче получилось:

            Большинство современных браузеров поддерживает заголовок Content-Security-Policy. Данный заголовок позволяет явно указать список ресурсов, разрешенных для загрузки с текущей страницы. Запрет на загрузку сторонних скриптов и выполнение inline скриптов сильно усложняет проведение XSS атаки.

            К сожалению, данный механизм может принести и вред. Создав на странице frame, в котором через <meta http-equiv=«Content-Security-Policy»> разрешено загружать только vk.com/login, можно узнать, залогинен ли пользователь Вконтакте или нет. Для залогиненного пользователя произойдет редирект на vk.com/news, который будет заблокирован. С помощью событий onerror и onload можно отследить произошла ли блокировка. Здесь можно посмотреть демо.

            Если сервис автоматически редиректит на страницу, адрес которой содержит id пользователя, то перебором можно узнать этот id. Например, разрешив загрузку m.vk.com/photos (редиректит на страницу m.vk.com/photos%user_id%) и http://m.vk.com/photos[1-100000] можно выяснить, лежит ли id пользователя в диапазоне от 1 до 100000.

            В данный момент проблема присутствует в Firefox, Safari и Chrome. Поддержка в IE очень ограничена, но это скоро исправят.


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

            1. Получение frame location после редиректа. Позволяло получить те же самые результаты. После исправления скрипты с другого домена могут получить только тот location, который установили сами, а не полученный в результате редиректа.

            2. Брутфорс посещенных ссылок через другой цвет. Исправили возвращая в JS всегда цвет непосещенной ссылки, независимо от ее текущего состояния.

            А в чем проблема не вызывать onerror, если блокировка произошла по вине CSP? И всегда вызывать onload?
              0
              >1. Получение frame location после редиректа. Позволяло получить те же самые результаты. После исправления скрипты с другого домена могут получить только тот location, который установили сами, а не полученный в результате редиректа.

              Наверно это было очень давно? сейчас такой глупой ошибки по прочтению src после редиректа уже и не встретишь.

              >2. Брутфорс посещенных ссылок через другой цвет. Исправили возвращая в JS всегда цвет непосещенной ссылки, независимо от ее текущего состояния.

              Не совсем связано, вы например не вычислите ID по посещенным ссылкам.

              Проблема в том что это может сломать текущие скрипты. Сейчас если в вконтакте какой то скрипт не подгрузился то страница сама об этом узнает и выдает сообщение об ошибке / перезагружается. Так это будет по сути «обман». Но другого способа я и не вижу.
                0
                > Наверно это было очень давно? сейчас такой глупой ошибки по прочтению src после редиректа уже и не встретишь.

                Ну конечно давно. Но, насколько я помню, изначально о такой проблеме не подумали.

                > Не совсем связано, вы например не вычислите ID по посещенным ссылкам.

                Да, но прикрыть можно схожими методами.

                > Проблема в том что это может сломать текущие скрипты. Сейчас если в вконтакте какой то скрипт не подгрузился то страница сама об этом узнает и выдает сообщение об ошибке / перезагружается. Так это будет по сути «обман». Но другого способа я и не вижу.

                Хммм, это интересная мысль. Только по-моему VK детектит незагруженные скрипты на случай плохого соединения или блокировки через расширения браузера. В случае с CSP сервер ведь сам устанавливает запрет, зачем ему потом это самому детектить что от этого сломается? Мне кажется, что сломаться может только если parent window CSP имеет приоритет перед CSP дочернего фрейма. Тогда действительно, сторонние сайты могут поломать работоспособность всяких встраиваемых кнопок (like, и т.п.), но такое поведение было бы странным.

                Возможно какие-то незлонамеренные скрипты действительно сломаются, но это будет значить, что скрипты эти используют неправильные методы для достижения цели.
                  +1
                  Не совсем связано, вы например не вычислите ID по посещенным ссылкам.
                  Открываем m.vk.com/photos, она редиректит пользователя на m.vk.com/photos12345. Теперь можно перебрать ссылки вида m.vk.com/photos[\d+] и найти, какая из них фиолетовая.
                    0
                    Во первых этот баг исправлен а во вторых фиолетовыми будет пара сотен тк вся история браузера
                      0
                      С чего бы всей истории быть фиолетовой? Вы часто заходите с компьютера на мобильные страницы с фотографиями других пользователей?
                        0
                        А даже если много фиолетовых, это скорее всего друзья и набор посещенных будет уникальным для каждого пользователя. Так что узнать id все равно можно, хотя точность будет ниже.
                          0
                          Да, баг полезный, но уже не рабочий.
            0
            Интересное использование. Относительно Facebook можно узнать залогинен ли юзер и через API.
            >сможем детектить ID пользователя на многих ресурсах
            Можно пример такого ресурса? У FB и ВК, напремер, нет редиректа со страницы юзера.
              0
              У вк — m.vk.com/photos
              У фб facebook.com/profile.php
                0
                Я имел ввиду обратный, чтобы с моей m.vk.com/photos12345 был, а с чужой m.vk.com/photos12346 не было.
                >Мы можем узнать редиректит ли конкретный URL на другой
                Куда редиректит мы же не увидим, т.е. для ВК перебрать ID не получится? Или я не так понял?
                Приведенная в посте методика не показывает же отличие между m.vk.com/photos12345 и m.vk.com/photos12346
                  0
                  Для ВК это тяжело по причине 100 миллионов айдишников. Если айди в пределах миллиона то можно перебрать. Для ФБ тоже, там лучше использовать готовый «пул» потенциальных вариантов. Скажем, из тысячи, быстро найдет кто вы.
                    0
                    Как с помощью данной методики отличить, что m.vk.com/photos12345 это id юзера, а m.vk.com/photos12346 — нет? Они же одинаково блокируются?
                      0
                      > data:, URL как это сделали с похожим моим багом в XSS Auditor

                      Тут я не стал вдаваться в подробности, но суть была в том что мы шлем «банч» из 1000 разрешенных урлов 1...1000 и смотрим заблокировало или нет. Если заблокировало значит ищем дальше. Если загрузилось значит урл в нашем «банче» и мы его дробим дальше по 100. В общем виде это map-reduce bruteforce
              0
              Firefox 27 (linux), пишет Not authorized, хотя залогинен и на фейсбуке, и на гитхабе.
                0
                Аналогино. Windows FF26 и Opera 12 — не работает. Chrome 32 — работает.
                +2
                Стиль изложения конечно нужно менять. Но всеравно спасибо за полезную информацию. Пойду вставлять CSP себе на сайт.

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

                Самое читаемое