Тринадесет правила за разработване на защитени Java приложения

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

Добрата новина е, че Java е дългогодишна платформа за разработка с много вградени функции за сигурност. Пакетът Java Security е претърпял интензивно битково тестване и често се актуализира за нови уязвимости в сигурността. По-новият API за защита на Java EE, пуснат през септември 2017 г., адресира уязвимости в архитектури в облак и микроуслуги. Екосистемата на Java включва и широк набор от инструменти за профилиране и докладване на проблеми със сигурността. 

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

Следните основни правила предлагат добра основа за изграждане на по-сигурни Java приложения.

Правило за защита на Java # 1: Напишете чист, силен Java код

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

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

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

Правило за защита на Java # 2: Избягвайте сериализацията

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

Краят на Java сериализацията

Ако не сте чували, Oracle има дългосрочни планове да премахне сериализацията от Java. Марк Рейнхолд, главен архитект на групата платформи Java в Oracle, заяви, че вярва, че една трета или повече от всички уязвимости на Java включват сериализация.

Доколкото е възможно, избягвайте сериализация / десериализация във вашия Java код. Вместо това, помислете за използване на сериализационен формат като JSON или YAML. Никога, никога не излагайте незащитена крайна точка на мрежата, която приема и действа върху поток за сериализация. Това не е нищо друго, освен добре дошла постелка за хаос.

Правило за защита на Java # 3: Никога не излагайте нешифровани идентификационни данни или лични данни

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

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

Правилата за паролите се прилагат за цялата лична информация (PII): кредитни карти, номера на социално осигуряване и др. Всяка лична информация, поверена на вашето приложение, трябва да се третира с най-високо ниво на грижа.

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

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

Правило за защита на Java # 4: Използвайте известни и тествани библиотеки

Насладете се на този въпрос и отговор относно въвеждането на вашия собствен алгоритъм за сигурност. Урокът tl; dr е: използвайте известни, надеждни библиотеки и рамки, когато е възможно. Това важи за целия спектър, от хеширане на пароли до REST API упълномощаване.

За щастие, Java и нейната екосистема са тук назад. За сигурност на приложенията Spring Security е де факто стандарт. Той предлага широка гама от възможности и гъвкавост, за да се побере с всяка архитектура на приложението, и включва набор от подходи за сигурност.

Първият ви инстинкт за справяне със сигурността трябва да бъде да направите изследванията си. Проучете най-добрите практики и след това проучете коя библиотека ще приложи тези практики вместо вас. Например, ако разглеждате използването на JSON Web Tokens за управление на удостоверяване и упълномощаване, погледнете Java библиотеката, която капсулира JWT, и след това научете как да го интегрирате в Spring Security.

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

Правило за защита на Java # 5: Бъдете параноични по отношение на външния вход

Независимо дали идва от потребител, който пише във форма, хранилище за данни или отдалечен API, никога не се доверявайте на външен вход.

Инжектирането на SQL и скриптове между сайтове (XSS) са само най-често известните атаки, които могат да бъдат резултат от неправилно боравене с външен вход. По-малко известен пример - един от многото - е "атаката на милиарди смешки", при която разширяването на XML обекта може да предизвика атака на отказ на услуга.

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

Специален и добре известен екземпляр е SQL инжектирането, което е разгледано в следващото правило.

Правило за защита на Java # 6: Винаги използвайте подготвени изрази за обработка на SQL параметри

Всеки път, когато създавате SQL оператор, рискувате да интерполирате фрагмент от изпълним код.

Знаейки това, добра практика е винаги да използвате класа java.sql.PreparedStatement за създаване на SQL. Подобни съоръжения съществуват за магазини NoSQL като MongoDB. Ако използвате ORM слой, внедряването ще използва PreparedStatements за вас под капака.

Правило за защита на Java # 7: Не разкривайте изпълнението чрез съобщения за грешка

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

Сигналите за неуспешно влизане също попадат в тази категория. Общоприето е съобщението за грешка да се дава като „Влизането не е успешно“ срещу „Не намерих този потребител“ или „Неправилна парола“. Предлагайте възможно най-малко помощ на потенциално злобни потребители.

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

Правило за защита на Java # 8: Поддържайте актуализациите на защитните версии

От 2019 г. Oracle внедри нова схема за лицензиране и график за пускане на Java. За съжаление на разработчиците, новата версия на каданса не улеснява нещата. Независимо от това, вие сте отговорни за честата проверка за актуализации на защитата и прилагането им към вашите JRE и JDK.

Уверете се, че знаете какви критични кръпки са налични, като редовно проверявате началната страница на Oracle за предупреждения за сигурност. Всяко тримесечие Oracle предоставя автоматизирана актуализация на корекциите за текущата версия на LTS (дългосрочна поддръжка) на Java. Проблемът е, че тази корекция е достъпна само ако плащате за лиценз за поддръжка на Java.

Ако вашата организация плаща за такъв лиценз, следвайте маршрута за автоматично актуализиране. Ако не, вероятно използвате OpenJDK и ще трябва да направите корекцията сами. В този случай можете да приложите двоичната корекция или просто да замените съществуващата инсталация на OpenJDK с най-новата версия. Като алтернатива можете да използвате комерсиално поддържан OpenJDK като Zulu Enterprise на Azul.

Имате ли нужда от всяка кръпка за сигурност?

Ако наблюдавате внимателно предупрежденията за сигурност, може да откриете, че не се нуждаете от даден набор от актуализации. Например изданието от януари 2020 г. изглежда критична актуализация на Java; внимателното четене обаче показва, че актуализацията само закърпва дупки в защитата на аплета на Java и не засяга Java сървърите.

Правило за защита на Java # 9: Потърсете уязвимости в зависимост

Налични са много инструменти за автоматично сканиране на вашата кодова база и зависимости за уязвимости. Всичко, което трябва да направите, е да ги използвате.

OWASP, проектът за отворена защита на уеб приложения, е организация, посветена на подобряване на защитата на кода. Списъкът с надеждни, висококачествени инструменти за автоматично сканиране на код на OWASP включва няколко инструмента, ориентирани към Java.

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

Правило за защита на Java # 10: Наблюдавайте и регистрирайте активността на потребителя

Дори обикновена груба сила може да бъде успешна, ако не наблюдавате активно приложението си. Използвайте инструменти за наблюдение и регистриране, за да следите здравето на приложението.

Ако искате да се убедите защо мониторингът е важен, просто седнете и гледайте TCP пакети на вашия порт за слушане на приложения. Ще видите всякакви дейности, далеч отвъд обикновените потребителски взаимодействия. Част от тази дейност ще бъдат ботове и злодеи, които сканират за уязвимости.

Трябва да регистрирате и наблюдавате за неуспешни опити за влизане и да прилагате контрамерки, за да предотвратите безнаказано нападение на отдалечени клиенти.

Мониторингът може да ви предупреди за необясними скокове, а регистрирането може да ви помогне да разгадаете какво се е объркало след атака. Екосистемата Java включва изобилие от търговски решения и решения с отворен код за регистриране и наблюдение.

Правило за защита на Java # 11: Внимавайте за атаки за отказ на услуга (DoS)

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

Oracle поддържа списък с потенциални вектори за този тип проблеми в своите Насоки за безопасно кодиране за Java SE документ, под заглавието „Отказ от обслужване“.

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

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

Правило за защита на Java # 12: Помислете за използването на мениджъра за защита на Java

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

Вие сами ще трябва да решите дали SecurityManagerрешителните мнения си заслужават допълнителния слой за защита на вашите приложения. Вижте документите на Oracle, за да научите повече за синтаксиса и възможностите на мениджъра за защита на Java.

Правило за защита на Java # 13: Помислете за използването на външна услуга за удостоверяване в облак

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

Потърсете наоколо и ще намерите набор от доставчици на удостоверяване в облак. Предимството на такава услуга е, че доставчикът е отговорен за защитата на чувствителни потребителски данни, а не вие. От друга страна, добавянето на услуга за удостоверяване увеличава сложността на вашата корпоративна архитектура. Някои решения, като удостоверяване на FireBase, включват SDK за интегриране в стека.

Заключение

Представих 13 правила за разработване на по-сигурни Java приложения. Тези правила са изпитани и верни, но най-голямото правило от всичко е следното: бъдете подозрителни. Винаги подхождайте към разработването на софтуер с повишено внимание и перспективи, насочени към сигурността. Потърсете уязвимости в кода си, възползвайте се от приложните програмни интерфейси (API) и пакети на Java и използвайте инструменти на трети страни, за да наблюдавате и регистрирате кода си за проблеми със сигурността.

Ето три добри ресурси на високо ниво, за да сте в крак с непрекъснато променящия се пейзаж на сигурността на Java:

  • OWASP Топ 10
  • CWE Топ 25
  • Указания за защитен код на Oracle

Тази история „Тринадесет правила за разработване на защитени Java приложения“ първоначално е публикувана от JavaWorld.