Ко(д)тики и безопасность
512 subscribers
20 photos
8 files
101 links
Канал о безопасной разработке для программистов и не только.
Download Telegram
Немного про Keycloak'и

Keycloak - кажется, одно из самых популярных у нас в Казахстане опенсорсных IAM (Identity and Access Management) решений. По крайней мере, мне попадался часто и при пентестах, и в процессе разработки. Но как и любой другой инструмент, он требует осторожности при настройке, а так же имеет ряд своих архитектурных особенностей, которые требуют пристального внимания, чтобы случайно не сделать ваш инстанс и связанное с ним приложение уязвимыми к разного вида атакам. Это тот случай, когда просто поддерживать актуальную версию совсем недостаточно.

Поэтому хочу поделитсья парой ссылок про него.

1. Разумеется, официальная дока про то, как делать безопасно в приложениях и сервисах: https://www.keycloak.org/docs/25.0.6/securing_apps/index.html

2. Официальная дока про то, как конфигурировать: https://www.keycloak.org/docs/25.0.6/server_admin/index.html#mitigating_security_threats

3. И, собственно, про то, как вас будут ломать (а мы же все понимаем, что будут):
часть 1 - https://csacyber.com/blog/pentesting-keycloak-part-1-identifying-misconfiguration-using-risk-management-tools
часть 2 - https://csacyber.com/blog/pentesting-keycloak-part-2

Вот тут важный момент: дока не самая свежая, но по части разведки (сбора информации о том, как ваше приложение использует keycloak) и основных косяков конфигурации все равно будет актуальна. Важно не забывать, что за последние пару лет еще вышла пачка CVE.


4. Про то, что IAM по-своему сложно бороться с гонками: https://www.cyberark.com/resources/threat-research-blog/you-cant-always-win-racing-the-keycloak
🔥5👍1
https://www.codereviewlab.com/ - а это шикарно, товарищи. Таски небанальные, надо поискать, подумать. В день доступен один таск в бесплатной подписке, да и платная в целом меньше 5000 тенге в месяц. Если кто ищет платформу для своей команды - рекомендую
🔥4👍2
Критическая уязвимость в Node.js библиотеке (и новая таска!)

Пару дней назад вышла критическая (CVE-2025-47949, CVSS 9.9) уязвимость в библиотеке samlify (Node.js). Это библиотека, реализующая аутентификацию в рамках интеграции с SAML SSO системами. И уязвимость, разумеется, позволяет злоумышленнику аутентифицироваться под кем-то другим, если у него есть хотя бы один валидный ответ на SAML-запрос. Поэтому если вы используете эту версию библиотеки, рекомендую как можно скорее обновиться до версии 2.10.0. Понравился комментарий в коде исправления:

// something has gone seriously wrong if we are still here




А пока предлагаю решить задачку на этом языке (ну и заодно ее полный аналог на PHP, если он вам ближе). Задачка с библиотекой не связана, вообще никак. И с уязвимостью в ней. Но это уже подсказка 🙂

Вопрос следующий - каким запросом я могу получить всех пользователей, что за уязвимость присутствует в коде и позволяет это сделать, и, главное, как это исправить?

На всякий случай:

Node.js код можно запустить с express (`node index.js`, поднимется на порту 8000)

PHP код - php -S localhost:8000 (ну или любой незанятый порт на ваш вкус)

P.S. странное чувство - предлагать людям добровольно скачать файлики с кодом и запустить их.
🔥1
просишь копилота подтюнить текст. Он тебе в ответ: а давай запилим инфографику! ну, давай...

пост не имеет смысловой нагрузки
😁4
Про атаки на разработчиков

Вчера с одной из команд говорили про социальную инженерию на разработчиков. Вспомнились кейсы, которые периодически активно обсуждаются в сети - когда на фейковом собеседовании человека просят скачать код с какого-то репозитория и на этом живом коде якобы провести сессию лайф-коддинга, чтобы убедиться в его навыках. Проблема начинается в тот момент, когда проект запускается в IDE и обфусцированный фрагмент одной из библиотек обращается к контрольному центру, чтобы скачать... RAT-файл, ратник, или remote access tool. Иными словами - программку, которая позволит выполнить на ПК жертвы определенные действия. В простом варианте атаки, на самом деле, не нужен даже ратник, потому что у нас и так выполняется код и какие-то доступы у него все равно будут.

И тут важный момент - а как защищаться? Можно поделить защиты на два аспекта.

1. Человек.
Это социальная инженерия, как ни крути. Поэтому то, насколько критично человек относится своим действиям, все еще остается важным. Зачастую разработчики и другие IT специалисты более расслабленно воспринимают стандартные правила кибергигиены, и злоумышленники этим пользуются.

2. Процессы и инструменты.
Докер-образы, плагины для IDE и браузеров, библиотеки в ZIP-архивах... как много всего может попасть к нам из непроверенных источников. Иногда по необходимости, иногда просто из любопытства. И все это нужно воспринимать как потенциально вредоносное, иными словами - ограничивать возможности, запускать все недоверенное в изолированных средах, перепроверять, что все это пришло из официальных источников.
И если говорить именно про эту атаку, то не стоит забывать, что IDE тоже пытается вас защитить (хоть полноценный сендбоксинг в ней и не возможен). Так, для плагинов механизм доверия в большинстве случаев реализован через подписывание, а для проектов есть Workspace Trust / Safe Mode, которые призваны ограничить возможности запускаемого кода, если он пришел из стороннего источника.
🔥2
ну и старый добрый мемчик, чтобы веселее читалось
😁5
Что нового в OWASP ASVS 5.0

Если вы забыли, что это, то можно почитать вот тут

В мае вышел новый релиз OWASP ASVS (самый большой за последние пять лет). И, как мне кажется, новая версия стала гораздо удобнее для разработчиков.

Но самое первое, что бросается в глаза, это изменения в области уровней защищенности. Если коротко, ASVS предлагает пачки контролей, соответствующие уровням L1, L2, L3, где L1 - базовая безопасность, а L3 - продвинутый уровень, соответствующий высокой зрелости продукта. Каждый уровень описывается своим набором требований\контролей, которые применяются к коду и, если все требования выполнены, можно считать, что мы соответствуем какому-то уровню.

Так вот. В старой версии ASVS 4.0.3 для соответствия уровню L1 нужно было выполнить 131 условие. В новой - всего 70. И несмотря на кажущееся противоречие (вроде как время идет, средний уровень зрелости должен расти), этот шаг весьма оправдан и является следствием жарких дискуссий. И здесь важно понимать, что высокое количество правил уровня L1, по всей видимости, являлось одной из причин того, что компании, начиная работать с ASVS, либо не доводили до соответствия первому уровню, либо в принципе бросали всю эту затею (все чаще думаю о том, что с безопасностью надо как с аллергеном - сперва малыми дозами, чтобы не вызывало сразу прям отторжения)

А еще все ожидали от этой версии правил работы с продуктами, использующими LLM, и не дождались. Авторы решили, что это заслуживает отдельного стандарта - и вот он .

А вот из реально прикольного - совсем новый раздел про пост-квантовую криптографию и сокращение длины минимально необходимого пароля (прикиньте! но там хитрая формулировка. Раньше было про "минимальную" длину пароля в 12 символов, сейчас стало "минимальная" - 8, а вот рекомендованная - 15. Но вообще, конечно, все уже присматриваются к историям без паролей).

В общем, новый документ ёмче, в нем меньше дублирования, убрано явно устаревшее и неактуальное и складывается ощущение, что новый документ еще больше адпатирован под разработчиков, а не под безопасников. И это не может не радовать.
🔥6👍1
В последнее время стала часто попадаться либо эта бага, либо близко связанные с ней. Причем не только мне, в статьях и разборах стала тоже часто фигурировать (хотя казалось бы). Предлагаю посмотреть кусочек кода и ответить на вопрос, что с ним не так (там две баги. Одна основная, вторая случайно затесалась). И главное - как такое атаковать.


@RestController
@RequestMapping("/users")
public class UserController {

@Autowired
private UserRepository userRepo;

@PostMapping
public User createUser(@RequestBody Map<String, Object> payload) {
User user = new User();
user.setUsername((String) payload.get("username"));
user.setPassword((String) payload.get("password"));
if (payload.containsKey("role")) {
user.setRole((String) payload.get("role"));
} else {
user.setRole("USER");
}
return userRepo.save(user);
}
}


встречается это дело и в других языках, но пример на Java
Поскольку в целом как-то нехорошо отделять безопасность приложений от безопасности сред, в которых они запускаются, считаю важным делиться и такими штуками тоже.

Офигенная диаграмма безопасности для k8s, на которую можно ориентироваться при работе со своими кластерами.

https://kubesec-diagram.github.io/
🔥3👍2
Пятница, а значит, пора разобрать пример, про который писала на этой неделе.

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

Если возвращаться к примеру, то в нем есть в том числе вот такой замечательный фрагмент:


if (payload.containsKey("role")) {
user.setRole((String) payload.get("role"));
} else {
user.setRole("USER");
}


Если в запросе от пользователя пришло поле role, выставить роль в его значение, иначе сделать роль "USER". И если в этом месте вам хочется спросить "да кто же так пишет", то спешу вас обрадовать - еще как пишут. Например в рассчете на то, что сам запрос корректно сформирует фронт.

Уязвимость в примере - чисто логическая, она не задетектится ни статанализатором, ни, будем честны, стандартным процессом QA, если вы заранее с QA не обговаривали, что и такое может случиться. И это тот самый случай, когда чеклисты спасают. Зафиксированные, конкретные чеклисты, содержащие список того, на что обратить внимание.

Более интересный и массовый вариант уязвимости, который может возникнуть в схожем коде, и который получил название Mass Assignement, когда фреймворк дает нам сбайндить параметры запроса напрямую в объекты. И что хорошо - во фреймворках, которые позволяют это сделать, все предусмотрено - всегда есть возможность завайтлистить то, что нам нужно, или заблеклистить.


резюмируя:
1. Код ревью - это такой момент в разработке, когда можно поймать кучу проблем безопасности, непонятных для остальных этапов.
2. Фронт бэку не друг и не товарищ, и наоборот тоже. За свои действия несем ответственность сами и перепроверяем.
3. Инструмент и его возможности всегда надо использовать правильно.
4*. Блэклисты - лучше, чем ничего, вайтлисты - лучше блэклистов.

ну и ссылки
Spring MVC https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/validation/DataBinder.html#setAllowedFields-java.lang.String...-:~:text=custom%20editors%2C%20etc.-,WARNING,-%3A%20Data%20binding%20can

nodeJS https://underscorejs.org/#pick

Python(Django) https://www.coffeeonthekeyboard.com/mass-assignment-security-part-10-855/

PHP Laravel + Eloquent
https://laravel.com/docs/5.2/eloquent#mass-assignment
👍4🔥2
https://t.me/art_code_ai/11

Попалась статья (в telegraph, но instant view) про то, как можно накосячить при работе со структурированными данными. Прям рекомендую посмотреть не косячит ли парсер, который используете вы в вашем стеке - можно узнать много удивительного.
👍2🔥1
ок, про SQL инъекции можно говорить вечно, но они все равно продолжают встречаться (правда, во все более экзотических местах). Обсуждали тут с друзьями SQL инъекции в Java (естественно, Spring) и вспомнилась статья https://www.baeldung.com/sql-injection

и вот тут важный момент - все вроде запомнили, что не надо конкатенацию делать, но есть и такие приколы:


@GetMapping("/users")
public List<User> list(@RequestParam("sort") String sortField) {
return userRepo.findAll(Sort.by(sortField));
}


Spring заинжектит sortField в ORDER BY. Как есть.
👍2🤔1
Мелкая, но важная деталь


Всем привет! сегодня хочу предложить почитать еще немного уязвимого кода (в этом есть какой-то свой кайф, не правда ли?). Уязвимость, которая объединяет эти фрагменты, имеет очень низкий уровень критичности. И поэтому ее часто пропускают на код ревью. Проблема обычно всплывает гораздо позже, чем этапы написания, запуска и зачастую даже во время эксплуатации проблема очень хорошо скрывается. Итак, что не так с кодом ниже и как бы вы это проэксплуатировали, будь вы на месте злоумышленника?

Java, Spring


@GetMapping("/search")
public void search(@RequestParam String q) {
log.info("User search query: " + q);
}


PHP, Laravel

public function search(Request $request) {
$q = $request->input('q');
Log::info("User search query: $q");
}


Node.js

app.get('/search', (req, res) => {
const q = req.query.q;
console.log("User search query: " + q);
});


.Net

[HttpGet("search")]
public IActionResult Search(string q)
{
_logger.LogInformation("User search query: " + q);
return Ok();
}
🤔5👍4
>>> To address this challenge, GitLab's Vulnerability Research team recently developed an automated detection system designed to proactively identify malicious dependencies in software supply chains

понятное дело, они дают инструменты безопасности у себя в продукте и наверняка вопросами собственной безопасности всерьез озабочены, но какой кайф читать о том, как разработческая компания внутри ведет security исследования. А теперь вопрос к разработчикам в чате (риторический): у вас в компании SCA работает?) не просто стоит, а прям работает?)
Интересный пост в блоге Gitlab о том, как они обнаружили supply chain attack в модуле для GO. В компании есть своя комбинированная система обнаружения таких атак. Это смесь песочницы, анализа работы кода подключаемого модуля + ревью модуля человеком. Всегда впечатляет когда такие системы конструируются и создаются в компании самостоятельно, это ли не из показатель развитой инженерной культуры.

https://about.gitlab.com/blog/gitlab-catches-mongodb-go-module-supply-chain-attack/
3👍2
Log injections📖

Пришла пятница, значит, пора разобраться с уязвимостью, про которую говорили в начале недели. Хочу немного поговорить о том, что может сделать злоумышленник с этой, на первый взгляд непримечательной, багой.

Если вспомнить методологию моделирования угроз STRIDE, то там есть целый раздел про Repudiation - отрицание того, что что-то произошло. Или как злоумышленник скроет следы. Скрывают их не только для того, чтобы не нашли пользователя (айпишник, вотэвер), с которого произошла атака, но и для того, чтобы не так-то просто было понять, какую уязвимость эксплуатировали. Итак, давайте посмотрим пример:


@GetMapping("/login")
public ResponseEntity<String> login(@RequestParam String username) {
logger.info("Login attempt by: " + username);
// ... authenticate user
return ResponseEntity.ok("OK");
}


Злоумышленник может послать такой запрос (ведь его задача "вшить" в полотно логов что-то похожее на обычный лог):


/login?username=admin\n2024-06-30 10:00:00 [INFO] Login successful for attacker


И теперь лог будет выглядеть так:


[INFO] Login attempt by: admin
2024-06-30 10:00:00 [INFO] Login successful for attacker



А что если попробовать такое? А вдруг салертит?
username = attacker\n[ERROR] Database compromised


И вот тут важный момент, а что происходит с нашими логами дальше? одно дело, если они молча хранятся какое-то время и никто никогда в них не заглядывает (ц-ц-ц). Если возникнет инцидент и мы до них дойдем, то такими методами атакующий запутает нас. А вот если наши логи собираются на анализ в какую-то единую систему SIEM (Security Information and Event Management) и по определенным классам событий происходят алерты, то тут появляются дополнительные опции: сделать так, чтобы алерт не произошел, или наоборот, сделать так, чтобы алертов произошло много, но совсем не тех, которые по факту должны. В общем, с этой штукой можно здорово нашкодить. Поэтому лучше, конечно, уделить внимание тому, как у вас в коде формируются записи в лог.
👍2🔥2
С днём любимого города!

А тем временем обновилась подборка каналов. Кажется, многие сюда попали из-за неё
4