Ін’єкція SQL та XSS: що хакери білих капелюхів знають про довіру до користувацьких даних

Розробники програмного забезпечення багато чого думають. Щодо створення веб-сайту чи програми є безліч питань: які технології ми будемо використовувати? Як буде налаштована архітектура? Які функції нам потрібні? Як буде виглядати інтерфейс?

Особливо на ринку програмного забезпечення, де доставка нових додатків здається скоріше змаганням за репутацію, аніж продуманим процесом, одне з найважливіших питань часто падає до кінця стовпця „Терміново”: як буде захищений наш продукт?

Якщо ви використовуєте надійний фреймворк з відкритим кодом для побудови свого продукту (і якщо такий застосовний і доступний, чому б і вам не робити?), То деякі основні проблеми безпеки, такі як маркери CSRF та шифрування пароля, вже можуть бути оброблені для ви.

Тим не менш, швидким розробникам було б добре допомогти розібратися у своїх знаннях про загальні загрози та підводні камені, хоча б лише для того, щоб уникнути незручних помилок новачка. Зазвичай найслабшим місцем у безпеці вашого програмного забезпечення є ви.

Нещодавно я більше зацікавився інформаційною безпекою загалом і, зокрема, практикую етичні злому. Етичний хакер, якого іноді називають хакером «білого капелюха», а іноді просто «хакером», - це той, хто шукає можливі вразливі місця безпеки і відповідально (приватно) повідомляє про них власників проектів.

Навпаки, зловмисник або хакер "чорної капелюхи", який також називають "зломщиком", - це той, хто використовує ці вразливі місця для розваги чи особистої вигоди.

І хакери з білим капелюхом, і з чорними капелюхами можуть використовувати однакові інструменти та ресурси, і, як правило, намагаються потрапити туди, де вони не повинні бути. Але білі капелюхи роблять це з дозволу та з наміром зміцнити захист, замість того щоб його знищити. Чорні капелюхи - це погані хлопці.

Коли мова заходить про те, як навчитися знаходити вразливі місця безпеки, не дивно, що я поглинаю будь-яку інформацію, яка потрапляє до мене. Ця публікація являє собою перегонку деяких ключових областей, які особливо корисні розробникам при обробці даних користувача. Ці уроки були спільно отримані з цих чудових ресурсів:

  • Посібники проекту Open Web Application Security
  • Плейлист Hacker101 від YouTube-каналу HackerOne
  • Веб-злом 101 Пітера Яворського
  • Блог Brute Logic
  • Канал Computerphile YouTube
  • Відео з Джейсоном Хаддіксом (@jhaddix) та Томом Хадсоном (@tomnomnom) (двоє досвідчених етичних хакерів з різними, але обома ефективними методологіями)

Можливо, ви знайомі з крилатою фразою: "Дезінфікуйте свої дані!" Однак, як я сподіваюся, ця публікація демонструє, розробка програми з надійною безпекою не є настільки простою.

Я пропоную альтернативну фразу: зверніть увагу на свої введення. Давайте детальніше розглянемо, вивчивши найпоширеніші атаки, які використовують переваги вразливостей у цій галузі: введення SQL та сценарії між сайтами.

Атаки введення SQL

Якщо ви ще не знайомі з атаками інжекцій SQL (мова структурованих запитів) або SQLi, ось чудове відео про SQLi, що нагадує "Мені п'ять". Можливо, ви вже знали про цю атаку з таблиць Маленького Боббі xkcd.

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

Монітор із командою SQL Select, який отримує всю вашу базу

Ви можете протестувати власний сайт, щоб побачити, чи сприйнятливі ви до такого роду нападів. (Будь ласка, протестуйте лише ті сайти, якими ви володієте, оскільки запуск SQL-ін’єкцій там, де у вас немає дозволу робити це, можливо, заборонено у вашому населеному пункті; і, безумовно, універсально, не дуже смішно.) тестові входи:

  • ' OR 1='1 обчислює до константи істина, а в разі успіху повертає всі рядки таблиці.
  • ' AND 0='1 обчислюється константою false, і при успішному виконанні не повертає жодного рядка.

Це відео демонструє вищезазначені тести та чудово показує, наскільки сильною може бути атака введення SQL.

На щастя, є способи пом'якшити атаки ін'єкції SQL, і всі вони зводяться до однієї базової концепції: не довіряти введенню користувачем.

Пом'якшення ін'єкції SQL

Для того, щоб ефективно пом'якшити ін'єкції SQL, розробники повинні забороняти користувачам успішно надсилати необроблені команди SQL на будь-яку частину сайту.

Деякі каркаси зроблять більшу частину важкої атлетики за вас. Наприклад, Django реалізує концепцію об’єктно-реляційного відображення (ORM) із використанням QuerySets. Ми можемо розглядати їх як функції обгортки, які допомагають вашій програмі запитувати базу даних за допомогою заздалегідь визначених методів, які уникають використання необробленого SQL.

Однак можливість використання фреймворку ніколи не є гарантією. Маючи справу безпосередньо з базою даних, існують інші методи, якими ми можемо безпечно абстрагувати наші SQL-запити від введення користувачем, хоча вони різняться за ефективністю. Нижче наводяться накази, які є найменш бажаними та мають посилання на відповідні приклади:

  1. Підготовлені оператори зі змінною прив'язкою (або параметризованими запитами),
  2. Зберігаються процедури; і
  3. Додавання користувачем дозволеного або закритого списку.

Якщо ви хочете застосувати вищезазначені методи, пов’язані шпаргалки - чудова відправна точка для глибшого копання. Достатньо сказати, що використання цих методів для отримання даних замість використання необроблених запитів SQL допомагає мінімізувати шанси на обробку SQL будь-якою частиною вашої програми, яка отримує введення від користувачів, таким чином пом'якшуючи атаки ін'єкції SQL.

Однак битва виграна лише наполовину ...

Атаки між сайтами сценаріїв (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

Розробники програмного забезпечення знаходяться у вигідному становищі, коли справа доходить до конкуренції з чорною шапкою або зловмисними хакерами. Для всієї роботи, яку ми робимо для забезпечення кожного входу, який може потенційно скомпрометувати нашу програму, зловмиснику потрібно знайти лише той, який ми пропустили. Це як встановити засувки на всі двері, але залишити вікно відкритим!

Навчившись думати так само, як і зловмисник, ми можемо краще підготувати наше програмне забезпечення для протистояння поганим акторам. Як би це не було захоплююче доставити функції якомога швидше, ми уникнемо накопичення великої заборгованості за безпеку, якщо заздалегідь задумаємося над процесом нашої програми, прослідкуємо за даними та звернемо увагу на наші дані.