Как защитить сайт от хакерских скриптов
Как защитить сайт от хакерских скриптов
Как защитить сайт от хулиганских скриптов

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

Для нас как авто­ров скрип­та это пло­хо. А для нас как веб-мастеров это инте­рес­но: мож­но ли защи­тить наши соб­ствен­ные сай­ты от взло­мов через скрипты?

👉 В этой ста­тье мы раз­бе­рём толь­ко один спо­соб защи­ты. В жиз­ни всё рабо­та­ет несколь­ко слож­нее и век­то­ров ата­ки гораз­до боль­ше. Мы наме­рен­но несколь­ко упро­ща­ем подачу.

Зачем нужна защита от вставки скриптов

Допу­стим, у нас есть сайт, кото­рый обра­ба­ты­ва­ет пер­со­наль­ные дан­ные поль­зо­ва­те­лей: Ф. И. О. и номе­ра теле­фо­нов. Часть этих дан­ных полу­ча­ет­ся и обра­ба­ты­ва­ет­ся в JS-скрипте. Если немно­го изме­нить этот скрипт, мож­но обра­бо­тать не толь­ко свои дан­ные, но и полу­чить дан­ные всех поль­зо­ва­те­лей сайта.

Что­бы изме­нить скрипт на стра­ни­це или доба­вить в него новые коман­ды, исполь­зу­ют раз­ные спо­со­бы, например:

  • встав­лять спе­ци­аль­ные коман­ды в кон­со­ли, как это дела­ли мы;
  • пере­да­вать вре­до­нос­ный код внут­ри пара­мет­ров адре­са сайта;
  • отпра­вить спе­ци­аль­ную JSON-строку, при пар­син­ге кото­рой может выпол­нить­ся нуж­ный нам код.

Каж­дый из этих спо­со­бов может доба­вить на стра­ни­цу свой код и выпол­нить её как бы от име­ни стра­ни­цы сай­та. Опас­ность тут в том, что обыч­но сайт дове­ря­ет тому, что дела­ют его соб­ствен­ные стра­ни­цы. Если от неё при­дёт запрос «Отдай мне спи­сок всех фами­лий и теле­фо­нов» и сер­вер смо­жет это сде­лать — он это сде­ла­ет, и спи­сок уйдёт в чужие руки.

Решение: политика безопасности контента

Что­бы защи­тить сайт и стра­ни­цы от таких атак, при­ду­ма­ли CSP — поли­ти­ку без­опас­но­сти кон­тен­та. Рабо­та­ет это так: 

  1. Вы спе­ци­аль­ны­ми коман­да­ми гово­ри­те сай­ту, из каких источ­ни­ков мож­но загру­жать дан­ные для страницы.
  2. Эти коман­ды отправ­ля­ют­ся бра­у­зе­ру при каж­дой загруз­ке страницы.
  3. Бра­у­зер смот­рит, что напи­са­но в этих коман­дах, и запре­ща­ет любые дей­ствия с содер­жи­мым стра­ни­цы, если это не раз­ре­ше­но правилами.

CSP может запре­щать загруз­ку чужих:

  • скрип­тов,
  • кар­ти­нок,
  • аудио- и видеофайлов,
  • CSS-стилей,
  • шриф­тов.

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

Про­ще гово­ря, CSP — это фей­с­кон­троль для любых дан­ных, кото­рые кто-то хочет доба­вить на стра­ни­цу. Напри­мер, мы ука­за­ли в поли­ти­ке, что кар­тин­ки и скрип­ты мож­но загру­жать с наше­го сай­та. Когда зло­умыш­лен­ник попро­бу­ет встро­ить на стра­ни­цу дру­гую кар­тин­ку и свой скрипт, у него ниче­го не получится.

Покажите примеры

Мы хотим запре­тить выпол­не­ние чужих скрип­тов на стра­ни­це. За это отве­ча­ет свой­ство script-srс, у кото­ро­го может быть один из этих параметров:

  • ‘self’ — озна­ча­ет, что мож­но выпол­нять толь­ко те скрип­ты, кото­рые лежат на том же сер­ве­ре, что и страница
  • ‘none’ — вооб­ще запре­ща­ет любые скрип­ты на стра­ни­це, даже если они там есть
  • ‘unsafe-inline’ — опас­но, пото­му что этот пара­метр раз­ре­ша­ет выпол­не­ние любых внеш­них скрип­тов на странице

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

Content-Security-Policy: script-src 'self'

Если мы ещё дове­ря­ем сер­ве­рам Яндек­са и хотим встра­и­вать их скрип­ты у себя на стра­ни­цах (напри­мер, пла­ги­ны Яндекс Музы­ки), то можем напи­сать так:

Content-Security-Policy: script-src 'self' yandex.ru

Когда мы вооб­ще не дове­ря­ем нико­му и хотим сами кон­тро­ли­ро­вать и постав­лять весь кон­тент на стра­ни­це, то исполь­зу­ем свой­ство default-src. Оно отве­ча­ет за все источ­ни­ки сра­зу, хоть скрип­ты, хоть кар­тин­ки. Поэто­му наша поли­ти­ка без­опас­но­сти в этом слу­чае может выгля­деть так:

Content-Security-Policy: default-src 'self'

А как это использовать?

Что­бы вся эта магия рабо­та­ла, нам нуж­но сооб­щить бра­у­зе­ру о нашей поли­ти­ке без­опас­но­сти. Это мож­но сде­лать несколь­ки­ми способами.

Настро­ить поли­ти­ку на сер­ве­ре. Если так сде­лать, то все стра­ни­цы, кото­рые отправ­ля­ют­ся с наше­го сер­ве­ра, будут уже идти с нуж­ны­ми настрой­ка­ми без­опас­но­сти. Самый про­стой спо­соб — про­пи­сать поли­ти­ку в фай­ле .htaccess, кото­рый лежит в корне сайта:

<ifModule mod_headers.c> 

     Header set Content-Security-Policy "default-src 'self'" 

</ifModule>

Если у вас на хостин­ге сто­ит отдель­ный веб-сервер Apache, то в его кон­фи­гу­ра­ци­он­ный файл httpd.conf мож­но напи­сать так:

Header set Content-Security-Policy "default-src 'self';"

Настро­ить поли­ти­ку на уровне движ­ка сай­та. Напри­мер, у вас есть сайт на Ворд­прес­се или дру­гой CMS, кото­рая рабо­та­ет на PHP. Тогда мы можем доба­вить в модуль, кото­рый отве­ча­ет за сбор­ку стра­ни­цы, такую строку:

header("Content-Security-Policy: default-src 'self'");

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

Вруч­ную писать нуж­ные пара­мет­ры в мета­те­гах внут­ри стра­ни­цы. Это самый слож­ный путь — нам при­дёт­ся напи­сать теги внут­ри каж­дой стра­ни­цы. Ещё один минус тако­го реше­ния — теги не дей­ству­ют на ресур­сы, кото­рые рас­по­ло­же­ны на стра­ни­це перед ним. Напри­мер, в раз­де­ле <head> мы под­клю­чим скрип­ты и сти­ли, рас­по­ло­жен­ные на дру­гих сай­тах, а потом напи­шем так:

<meta http-equiv="Content-Security-Policy" content="default-src 'self'">

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

И что, этого достаточно?

Нет, но это ещё один уро­вень защи­ты сай­та от зло­умыш­лен­ни­ков и хаке­ров. Вот несколь­ко дру­гих инструментов:

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

И есть вещи, с кото­ры­ми очень слож­но бороть­ся с помо­щью про­грам­ми­ро­ва­ния, — напри­мер, фишинг и соци­аль­ная инже­не­рия. Но всё это темы для отдель­ных разговоров.

Что дальше

Даль­ше настро­им поли­ти­ку без­опас­но­сти на нашем учебно-боевом сер­ве­ре и про­ве­рим, как она рабо­та­ет. Заод­но посмот­рим, какие ещё у неё есть важ­ные пара­мет­ры и как ими управлять.

Текст:

Миха­ил Полянин

Редак­тор:

Мак­сим Ильяхов

Худож­ник:

Даня Бер­ков­ский

Кор­рек­тор:

Ири­на Михеева

Вёрст­ка:

Мария Дро­но­ва

Соц­се­ти:

Олег Веш­кур­цев