[Перевод] Рассказ о том, как не дать мне украсть номера кредиток и пароли у посетителей ваших сайтов

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

4kxvio7tyoiwfj9poibufj6dtss.jpeg


Тот пост вызвал живой и эмоциональный отклик аудитории. Кто-то говорил о том, что всё пропало, и теперь он не сможет спокойно спать, кто-то утверждал, что уж его-то проектов это точно не коснётся, кто-то задавал вопросы о том, как от такого защититься… К проблеме, поднятой в предыдущем материале, можно относиться по-разному, но она вполне реальна, поэтому сегодня мы публикуем продолжение истории того, кто ворует номера кредиток. Сегодня он расскажет о методах защиты веб-проектов от потенциально опасного кода.

В двух словах о самом главном


Прежде чем переходить к деталям, рассмотрим, в двух словах, основные идеи, которые будут здесь раскрыты.

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

А именно, сбор подобных данных необходимо проводить средствами выделенной веб-страницы, которую следует выводить в отдельном iframe. Размещать её надо на сервере для статических веб-страниц, расположенном на домене, отличном от домена основного сайта. Это — если вы хотите работать, скажем, с банковскими картами, самостоятельно. Здесь можно пойти и другим путём, например, если вы сомневаетесь в действенности вышеописанных защитных мер, или просто не хотите усложнять свой проект. Этот путь заключается в том, что обработку подобных данных можно полностью передать специализированному сервису.

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

Хомяк и доберман


Немного страха — это обычно полезно. Это мобилизует и заставляет действовать. Предлагаю вам оценить ощущения, которые возникли бы у вас, если бы вам пришлось делать заявление, подобное тому, которое недавно пришлось сделать компании OnePlus:

…в код страницы обработки платежей был внедрён вредоносный скрипт, который предназначен для кражи данных кредитных карт в процессе их ввода… Этот скрипт работал с перерывами, перехватывая данные и отправляя их злоумышленникам прямо из браузеров пользователей… это происшествие может затронуть до 40 тысяч пользователей oneplus.net.


Страх, о котором мы говорили выше, не имеет конкретной формы. Для того чтобы с ним разобраться, давайте обратимся к зоологии, найдём его материальное воплощение в животном мире.

Я представляю сторонний код как здоровенного матёрого добермана. Он выглядит спокойным, даже благодушным. Но в его чёрных немигающих глазах таятся искры неизвестного. Достаточно сказать, что я не оставлю ничего, что мне дорого, там, куда он может добраться.

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

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

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

Я считаю, что код, который взят из npm, GTM, DFP, или откуда угодно ещё, не нужно считать бесспорно опасным. Но я хочу предложить, чтобы, если вы не можете гарантировать того, что этот код будет вести себя достойно, вы учитывали бы то, что безответственно оставлять его наедине с конфиденциальными данными пользователей.

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

Пример: защита уязвимого сайта


Сайт, который мы рассмотрим в этом примере, имеет форму для ввода данных кредитных карт, к которой может получить доступ вредоносный код. Подобные формы можно увидеть в нескольких очень крупных интернет-магазинах, которые вы, вероятно, считали хорошо защищёнными.

f13bc1a2a91c6569bb24e319ea514c7a.png


Форма для ввода данных банковской карты

Эта страница буквально переполнена сторонним кодом. Она использует React и была создана с помощью Create React App, поэтому даже до начала серьёзной работы над ней у неё уже было 886 зависимостей.

Кроме того, на ней имеется Google Tag Manager (если кто не знает — GTM — это удобный механизм, который позволяет совершенно неизвестным вам людям внедрять JS-код на ваш сайт, успешно обходя помехи в виде анализа кода).

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

(Тут мне хотелось бы отметить, что меня, в связи со всем этим, разочаровывает Google. Его сотрудники, пропагандирующие правильные подходы к программированию, тратят уйму времени, рассказывая нам о том, как сделать веб быстрым. Там убрали несколько десятков килобайт, тут сэкономили несколько миллисекунд… Всё это замечательно, но в то же время они позволяют собственной рекламной сети DFP отправлять мегабайты данных на устройства пользователей, выполняя сотни сетевых запросов и отнимая секунды процессорного времени. Google, я знаю, в твоём распоряжении достаточно квалифицированных специалистов, умственного потенциала которых хватит для того, чтобы создать более интеллектуальный и более быстрый способ работы с рекламными объявлениями. Почему же этого до сих пор не сделано?)

Итак, вернёмся к нашей теме. Очевидно, мне нужно выдернуть секретные данные пользователей из загребущих рук стороннего кода. Мне хочется, чтобы форма, о которой идёт речь, жила бы на собственном маленьком острове.

df3111721fe8ab44df90fb189847af9c.jpg


Сначала надо найти симпатичную картинку, а потом придумать метафору, которая свяжет эту картинку с темой статьи

Теперь, когда вы достаточно настроились на серьёзную работу, прочитав некоторую часть моего сегодняшнего рассказа, я собираюсь приступить к описанию практических подходов по защите ценных данных от стороннего кода. А именно, тут мы рассмотрим три варианта защиты:

  • Вариант 1: перемещение формы для ввода данных кредитной карты в её собственный документ, в котором нет стороннего кода, и обслуживание этого документа как отдельной страницы.
  • Вариант 2: по сути, то же самое, что и первый вариант, но страница для ввода данных карты размещается в iframe.
  • Вариант 3: то же, что и второй вариант, но родительская страница и iframe обмениваются данными с использованием механизма postMessage.


▍Вариант 1: отдельная страница для конфиденциальных данных


В целях безопасности проще всего будет создать новую страницу для работы с конфиденциальными данными, на которой вообще нет JavaScript-кода. Когда пользователь щёлкает по кнопке «Купить», его, вместо показа ему какой-нибудь симпатичной формы, встроенной в страницу и стилизованной в соответствии с её дизайном, отправляют на примерно такую страницу:

eb03e699eecc7748932fa99f54d8b6d3.png


Выделенная страница для работы с данными банковских карт

К несчастью, так как шапка, подвал и панель навигации моего сайта являются компонентами React, я не могу использовать их на этой странице, созданной без привлечения стороннего кода. Поэтому её шапка, синий прямоугольник с надписью, представляет собой вручную сделанную копию полнофункциональной шапки. Самодельная шапка, конечно, не обладает теми же возможностями.

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

Для того, чтобы файл с формой не содержал ничего лишнего, я воспользовался стандартными механизмами проверки формы вместо того, что можно сделать на JavaScript. Как результат, уровень поддержки такой страницы превышает 97%, а работа с атрибутами required и pattern позволяет оценить то, насколько далеко продвинулась реализация проверки введённых данных с помощью JavaScript.

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

Если вы собираетесь пользоваться подобным подходом на практике, рекомендую держать код, имеющий отношение к форме, в одном файле. Сложность — это враг такого подхода (в нашей ситуации подобное отношение к сложности особенно справедливо). HTML-файл вышеприведённого примера, вместе со встроенным CSS в теге