SQL инжекция и XSS: какво знаят хакерите с бели шапки за доверието на потребителските данни

Разработчиците на софтуер имат много мисли. Има безброй въпроси, които трябва да зададете, когато става въпрос за създаване на уебсайт или приложение: Какви технологии ще използваме? Как ще бъде настроена архитектурата? От какви функции се нуждаем? Как ще изглежда потребителският интерфейс?

Особено на софтуерен пазар, където изпращането на нови приложения изглежда по-скоро като надпревара за репутация, отколкото добре обмислен процес, един от най-важните въпроси често пада в дъното на графата „Спешно“: как ще бъде защитен нашият продукт?

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

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

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

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

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

Що се отнася до научаването как да открия уязвимости в сигурността, не би трябвало да е изненадващо, че поглъщам каквато и информация да получа. Тази публикация е дестилация на някои ключови области, които са особено полезни за разработчиците при обработка на потребителски данни. Тези уроци бяха събрани колективно от тези отлични ресурси:

  • Ръководствата за проекта за отворена защита на уеб приложения
  • Плейлистът на Hacker101 от YouTube канала на HackerOne
  • Уеб хакерство 101 от Питър Яворски
  • Блогът на Brute Logic
  • Каналът Computerphile в YouTube
  • Видеоклипове с участието на Джейсън Хадикс (@jhaddix) и Том Хъдсън (@tomnomnom) (двама завършени етични хакери с различни, но и двамата ефективни методологии)

Може да сте запознати с крилатата фраза „дезинфекцирайте вашите входове!“ Както се надявам обаче, тази публикация демонстрира, разработването на приложение със стабилна сигурност не е толкова лесно.

Предлагам алтернативна фраза: обърнете внимание на вашите данни. Нека да разработим, като разгледаме най-често срещаните атаки, които се възползват от уязвимостите в тази област: SQL инжектиране и скриптове на различни сайтове.

SQL инжекционни атаки

Ако все още не сте запознати с SQL (Structured Query Language) инжекционни атаки или SQLi, ето едно страхотно видео, подобно на "Аз съм пет" на SQLi. Може би вече знаете за тази атака от Малките Боби таблици на xkcd.

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

Монитор с команда за избор на SQL, който получава цялата ви база

Можете да тествате собствения си сайт, за да видите дали сте податливи на този вид атака. (Моля, тествайте само сайтове, които притежавате, тъй като стартирането на SQL инжекции, където нямате разрешение да правите това, е възможно незаконно във вашето населено място; и определено, универсално, не е много забавно.) Следните полезни товари могат да се използват за тестови входове:

  • ' OR 1='1 изчислява до константа true и при успех връща всички редове в таблицата.
  • ' AND 0='1 оценява на константа false и при успех не връща редове.

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

За щастие има начини за смекчаване на SQL инжекционните атаки и всички те се свеждат до една основна концепция: не се доверявайте на потребителския вход.

Смекчаване на SQL инжектирането

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

Някои рамки ще направят по-голямата част от тежката работа за вас. Например, Django прилага концепцията за обектно-релационно картографиране или ORM с използването на QuerySets. Можем да ги възприемаме като функции на обвивки, които помагат на вашето приложение да търси в базата данни, използвайки предварително определени методи, които избягват използването на суров SQL.

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

  1. Подготвени отчети с променлива обвързване (или параметризирани заявки),
  2. Съхранени процедури; и
  3. Включване на белия списък или избягване на въведеното от потребителя

Ако искате да приложите горните техники, свързаните таблици с мами са чудесна отправна точка за по-задълбочено копаене. Достатъчно е да се каже, че използването на тези техники за получаване на данни, вместо да се използват сурови SQL заявки, помага да се сведат до минимум шансовете SQL да бъде обработен от която и да е част от вашето приложение, която приема данни от потребителите, като по този начин смекчава SQL инжекционните атаки.

Битката обаче е спечелена само наполовина ...

Cross Site Scripting (XSS) атаки

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

Атаките за скриптове на различни сайтове или XSS възникват, когато JavaScript кодът се инжектира в уеб страница и променя поведението на тази страница. Неговите ефекти могат да варират от неприятности на шега до по-сериозни байпаси за удостоверяване или кражба на идентификационни данни. Този доклад за инцидент от Apache през 2010 г. е добър пример за това как XSS може да бъде верижен в по-голяма атака, за да поеме акаунти и машини.

HTML танцово парти с малко JS врязване

XSS can occur on the server or on the client side, and generally comes in three flavors: DOM (Document Object Model) based, stored, and reflected XSS. The differences amount to where the attack payload is injected into the application.

DOM based XSS

DOM based XSS occurs when a JavaScript payload affects the structure, behavior, or content of the web page the user has loaded in their browser. These are most commonly executed through modified URLs, such as in phishing.

To see how easy it would be for injected JavaScript to manipulate a page, we can create a working example with an HTML web page. Try creating a file on your local system called xss-test.html (or whatever you like) with the following HTML and JavaScript code:

  My XSS Example   

Hello there!

var name = new URLSearchParams(document.location.search).get('name'); if (name !== 'null') { document.getElementById('greeting').innerHTML = 'Hello ' + name + '!'; }

This web page will display the title “Hello there!” unless it receives a URL parameter from a query string with a value for name. To see the script work, open the page in a browser with an appended URL parameter, like so:

file:///path/to/file/xss-test.html?name=Victoria

Fun, right? Our insecure (in the safety sense, not the emotional one) page takes the URL parameter value for name and displays it in the DOM. The page is expecting the value to be a nice friendly string, but what if we change it to something else? Since the page is owned by us and only exists on our local system, we can test it all we like. What happens if we change the name parameter to, say, ?

Екранна снимка на примера за XSS страница

This is just one example, largely based on one from Brute’s post, that demonstrates how an XSS attack could be executed. Funny pop-up alerts may be amusing, but JavaScript can do a lot of harm, including helping malicious attackers steal passwords and personal information.

Stored and reflected XSS

Stored XSS occurs when the attack payload is stored on the server, such as in a database. The attack affects a victim whenever that stored data is retrieved and rendered in the browser. For example, instead of using a URL query string, an attacker might update their profile page on a social site to include a hidden script in, say, their “About Me” section. The script, improperly stored on the site’s server, would successfully execute at a later time when another user views the attacker’s profile.

One of the most famous examples of this is the Samy worm that all but took over MySpace in 2005. It propogated by sending HTTP requests that replicated it onto a victim’s profile page whenever an infected profile was viewed. Within just 20 hours, it had spread to over a million users.

Reflected XSS similarly occurs when the injected payload travels to the server, however, the malicious code does not end up stored in a database. It is instead immediately returned to the browser by the web application.

An attack like this might be executed by luring the victim to click a malicious link that sends a request to the vulnerable website’s server. The server would then send a response to the attacker as well as the victim, which may result in the attacker being able to obtain passwords, or perpetrate actions that appear to originate from the victim.

XSS attack mitigation

In all of these cases, XSS attacks can be mitigated with two key strategies: validating form fields, and avoiding the direct injection of user input on the web page.

Validating form fields

Frameworks can again help us out when it comes to making sure that user-submitted forms are on the up-and-up. One example is Django’s built-in Field classes, which provide fields that validate to some commonly used types and also specify sane defaults. Django’s EmailField, for instance, uses a set of rules to determine if the input provided is a valid email. If the submitted string has characters in it that are not typically present in email addresses, or if it doesn’t imitate the common format of an email address, then Django won’t consider the field valid and the form will not be submitted.

If relying on a framework isn’t an option, we can implement our own input validation. This can be accomplished with a few different techniques, including type conversion, for example, ensuring that a number is of type int(); checking minimum and maximum range values for numbers and lengths for strings; using a pre-defined array of choices that avoids arbitrary input, for example, months of the year; and checking data against strict regular expressions.

Thankfully, we needn’t start from scratch. Open source resources are available to help, such as the OWASP Validation Regex Repository, which provides patterns to match against for some common forms of data. Many programming languages offer validation libraries specific to their syntax, and we can find plenty of these on GitHub. Additionally, the XSS Filter Evasion Cheat Sheet has a couple suggestions for test payloads we can use to test our existing applications.

While it may seem tedious, properly implemented input validation can protect our application from being susceptible to XSS.

Avoiding direct injection

Elements of an application that directly return user input to the browser may not, on a casual inspection, be obvious. We can determine areas of our application that may be at risk by exploring a few questions:

  • How does data flow through our application?
  • What does a user expect to happen when they interact with this input?
  • Where on our page does data appear? Does it become embedded in a string or an attribute?

Here are some sample payloads that we can play with in order to test inputs on our site (again, only our own site!) courtesy of Hacker101. The successful execution of any of these samples can indicate a possible XSS vulnerability due to direct injection.

  • ">

    test

  • '+alert(1)+'
  • "onmouserover="alert(1)
  • //"onmouseover="alert(1)

As a general rule, if you are able to design around directly injecting input, do so. Alternatively, be sure to completely understand the effect of the methods you choose; for example, using innerText instead of innerHTML in JavaScript will ensure that content will be set as plain text instead of (potentially vulnerable) HTML.

Pay attention to your inputs

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

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