Найдорожчий антипатерн


Дізнайтесь більше про нові кар'єрні можливості в EchoUA. Цікаві проекти, ринкова оплата, гарний колектив. Надсилайте резюме та приєднуйтеся до нас.

Розповідає автор блогу m1el.github.io


У цій статті я розповім Вам про найдорожчий антипатерн, який я знаю, – управління структурованими даними з використанням рядкових методів. Я називатиму це “антипатерн printf”.

“Найдорожчий антипатерн” не порожні слова

Я підрахував кількість уразливостей за їх типами, використовуючи дані із cve.mitre.org, і ось, що я отримав:

  • rexec: 19268
  • DoS: 14849
  • xss: 9236
  • memory: 8212
  • sqlinj: 6230
  • privilege: 3321
  • dirtraversal: 2762
  • arith: 1260
  • csrf: 1117

Ви можете критикувати мене за те, як я це рахував, і спробувати зробити це самостійно.

Ви можете помітити, що XSS (Cross Site Scripting – “Міжсайтовий скриптинг”) і SQL ін’єкції є значною частиною списку. Я вважаю, що в більшості вразливостей цих типів винен саме антипатерн printf. Вставляти якісь рядки прямо в HTML – жахлива ідея. І з SQL те саме.

Приклади використання на різних мовах

Тепер, коли Ви знаєте значення антипатерну, я доведу Вам, що це повсюдне явище. Ви можете думати, що він властивий тільки для HTML і SQL – саме тому і виникли вразливості.

  • Майже кожен сайт на PHP містить щось на кшталт:
    Hello, !

     

  • SQL запит сформований за допомогою рядкових операцій (див. документацію з mysql_query) :
    $query = sprintf ("SELECT firstname, lastname, address, age FROM friends WHERE firstname='%s' AND lastname='%s'", mysql_real_escape_string ($firstname), mysql_real_escape_string ($lastname));
  • Багато програмістів створюють динамічні елементи в JavaScript, використовуючи щось віддалено innerHtml (наприклад, тут), що нагадує:
    var OriginalContent = $ (this).text ();$(this).html ("");
  • Програміст-бідолаха, якого змусили писати динамічний сайт на C, може видати:
    sprintf (buffer, "%s24時間
    

    “, …)

  • Генерування JSON з використанням строкового форматування (наприклад, тут) :
    git log --pretty=format:'{ %n " commit": "%H",%n "abbreviated_commit": "%h",%n " tree": "%T",%n "abbreviated_tree": "%t",%n " parent": "%P",%n "abbreviated_parent": "%p",%n " refs": "%D",%n " encoding": "%e",%n " subject": "%s",%n "sanitized_subject_line": "%f",%n " body": "%b",%n "commit_notes": "%N",%n "verification_flag": "%G"?,%n " signer": "%GS",%n "signer_key": "%GK",%n " author": { %n " name": "%aN",%n " email": "%aE",%n " date": "%aD"%n },%n " commiter": { %n " name": "%cN",%n " email": "%cE",%n " date": "%cD"%n }%n},'
  • Використання sed для роботи з XML:
    # http://askubuntu.com/questions/442013/using-sed-to-search-and-replace-text-in-xml-filesed - i 's##UpdateAndExit#' File.XML# http://askubuntu.com/questions/284983/print-text-between-two-xml-tagssed - n '/<serverName/,/</serverName/p' big_xml_file.xml
  • Генерування коду за допомогою ExtJS (наприклад, тут):
     '',
    ' dest["{name}"] = value === undefined ? __field{#}.convert (__field{#}.defaultValue, record) : __field{#}.convert (value, record);n',...// використання експлоита :// Ext.define ('m',{extend:'Ext.data.Model',fields:['id']});// var store = Ext.create ('Ext.data.Store',{model:m});// store.loadRawData ({metaData:{fields:['"+alert (1) +"']}});
  • MAL (Make – A – Lisp) задає load-file, як результат конкатенції рядків:

    Define a load – file function using mal itself. In your main program call the rep function with this string: ” (def! load – file (fn* (f) (eval (read – string (str ” (do ” (slurp f) “)”))))) “.

Як же правильно обробляти дані?

Отже, якщо я використовую рядкові функції для генерації HTML, що мені треба використати замість цього?

Як Ви можете бачити нижче, всі запропоновані рішення мають один сенс – використати спеціальні методи створення об’єктів, а лише потім серіалізувати їх. Головне не обробляти серіалізовані дані як рядки.

Для HTML

  • hiccup (більше прикладів тут):
    (html [:ul (for [x (range 1 4)] [:li x])])(defn index [] [:div {:id " content"} [:h1 {:class "text-success"} "Hello Hiccup"]])
  • lxml e – factory:
    html = page =  ( E.html ( # create an Element called " html" E.head ( E.title ("This is a sample document") ), E.body ( E.h1 ("Hello"!, CLASS ("title")), E.p ("This is a paragraph with ", E.b ("bold"), " text in it"!), E.p ("This is another paragraph, with a", "n ", E.a ("link", href="http://www.python.org") "".), E.p ("Here are some reservered characters: <spam&egg>".), ) ))
  • Працюйте з DOM (Document Object Model), потім серіалізуйте; простий приклад:
    html = etree.parse ('template.html') name_node = html.xpath ('//div[@id="user-name"]')[0]
    name_node.text = user.nameprint (etree.tostring (html))
  • Використайте серверний AngularJS або React.
  • Управляйте DOM безпосередньо, наприклад, через jQuery:
    var OriginalContent = $ (this).text ();$(this).empty ().append ($('').val (OriginalContent)) // Жахливий код! Жахливий!// $(this).html ("");

Для JSON

  • Використайте літерали або list compehensions для створення об’єкта JSON, потім серіалізуйте його;
  • генеруйте JSON об’єкти, а потім серіалізуйте.

Для SQL

  • Використайте placeholder ‘и (параметри запиту);
  • працюйте з абстрактними деревами синтаксису (Abstract Syntax Trees – AST) SQL, а потім робіть запит.

Для XML

  • Працюйте з DOM, потім переводьте в XML;
  • користуйтеся XSLT.

Для мета-програмування

  • Використайте Lisp;
  • працюйте з AST для Вашої мови.

Де корінь проблеми?

На мій погляд, у лінощах.

– О, ми можемо створити розмітку просто сполучаючи рядки? Авжеж, давайте так і зробимо!
– Проте якщо рядок міститиме <img/src/onerror=alert#00> це призведе до виконання коду JavaScript!
– Дідько, ну давай напишемо функцію htmlspecialchars і викликатимемо її щоразу, коли треба буде вставити текст у HTML.
– Однак якщо написати , JS все одно спрацює!
– Тільки ідіот писатиме таке!
– А якщо ми забудемо викликати цю функцію в якому-небудь місці, у нас виникнуть проблеми?
– Просто писатимемо акуратніше наступного разу.

І ось, ми генеруємо HTML, використовуючи об’єднання рядків. Звичайно, якщо Ви писатимете код дуже акуратно, то уникнете вразливостей. Навіщо Вам такі проблеми? Ви ж не використовуєте ручне управління пам’яттю для створення веб-сайту, чи не так? Немає сенсу ходити над прірвою, якщо Ви можете просто писати у безпечному ключі.

Трохи про браузери

У цієї історії є веселіша сторона – браузери. Їх розробники пристосовували свої парсери для роботи з неправильним HTML, оскільки багато сайтів містили кривий код. Люди вибирали браузери, які могли сприймати як HTML буквально довільні набори байтів і коректно відображали їх улюблені веб-сайти. Так само були розроблені XSS фільтри, оскільки сайти записували необроблені запити користувачів прямо в HTML. Суть таких фільтрів проста – якщо браузер може запобігти 90 % XSS атак на користувача, користувач буде задоволений. Так що, ці фільтри не можуть захистити від усіх атак.

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

Насамкінець

Структура HTML жахлива тому, що від початку люди управляли нею як рядками. Дуже багато проблем (включаючи, але не обмежуючись: XSS, некоректна розмітка, різний парсинг браузерів) зумовлені неправильним розумінням суті формату HTML.

Припустимо, що доступні інструменти не підштовхували б людей до створення HTML у вигляді рядків – Інтернет тоді був би кращим.

Припустимо, що ми вибрали б інший шлях для обробки веб-сторінок, тоді ми не сприймали б його як рядок, який можна записати через printf.

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

Переклад виконав Петро Сокових
Оригінал: “The Most Expensive Anti – Patternf”

Київ, Харків, Одеса, Дніпро, Запоріжжя, Кривий Ріг, Вінниця, Херсон, Черкаси, Житомир, Хмельницький, Чернівці, Рівне, Івано-Франківськ, Кременчук, Тернопіль, Луцьк, Ужгород, Кам'янець-Подільський, Стрий - за статистикою саме з цих міст програмісти найбільше переїжджають працювати до Львова. А Ви розглядаєте relocate?


Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *