Re[14]: Каких программ вам не хватает?
От: Sinclair Россия https://github.com/evilguest/
Дата: 08.04.25 09:19
Оценка:
Здравствуйте, Miroff, Вы писали:

M>Желание похвальное, только эта абстракция практически сразу протекает. Ты же сам рассуждаешь о представлениях ресурса, а представления зависят от того, кто на них смотрит.

Я бы разводил такие вещи по разным "ресурсам", так, чтобы границы безопасности совпадали с границами ресурсов. Потому что это и надёжнее, и эффективнее.
Например: есть у нас, допустим, судебное постановление. Имена и реквизиты упомянутых там лиц — дело чувствительное. Анонимной публике их видеть не положено; а вот авторизованной — да, нужно.
Вариантов три:
1. При отдаче текста постановления смотрим в токен пользователя, и либо заменяем все имена плейсхолдерами, либо вставляем как надо.
2. Делаем два ресурса: "анонимизированное постановление", "полноценное постановление". Анонимный доступ ко второму получает 401, аутентифицированный доступ без прав на данное дело получает 403.
3. Делаем два ресурса: постановление, в "тексте" которого есть ссылки на фигурантов, каждый из которых — самостоятельный ресурс. Постановления отдаём всем желающим, детали фигурантов — только авторизованным пользователям. Остальные получают 403.
Как по мне, так первый вариант, очевидно, самый-самый плохой. Он плохо масштабируется, и крайне плохо проверяется на корректность.

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

Всё верно. Сначала люди создают себе проблему путём принятия неверных архитектурных решений, потом всю жизнь от неё страдают. Интернет полон вопросов "как мне запретить кэширование респонсов моего сервиса?". Это не потому, что кэширование — плохо, а потому, что не все умеют проектировать сервисы.

M>Современная ИБ говорит, что если какой-то функционал пользователю недоступен он и не должен знать о существовании этого функционала.

Можно ссылку на источник, который вы цитируете? Я не эксперт по ИБ, с удовольствием ознакомлюсь.
M>Иначе мотивированный пользователь начнет искать способ для эскалации привилегий и, чем черт не шутит, вдруг найдет.
В той литературе по ИБ, которую я читал в детстве, излагаемая вами концепция называлась "security by obscurity" и считалась однозначным злом. По сравнению, естественно, с нормальной безопасностью, которая не построена на невежестве пользователей.

REST зарубает вашу идею на корню, т.к. весь "функционал" в нём известен заранее: GET/PUT/DELETE.


M>К тому же, с точки зрения UX скрытие кнопки эквивалентно вызову с ошибкой потому что а) причин ошибки бесконечно много и в этом случае все их нужно обрабатывать и б) ИБ не велит раскрывать внутреннее устройство приложения через сообщения об ошибках, так что пользователь максимум что увидит это "тебе нельзя".

Я не понимаю, что вы имеете под пунктом а). Да, совершенно верно, причин ошибки много, и их надо обрабатывать. В любом случае. Как минимум вы должны уметь отличать 4хх от 5хх. Полагаться на то, что ошибок не существует — верный способ заслужить ненависть пользователей. Я знаю, что сейчас модно либо вообще не обрабатывать ошибки (тыкаешь кнопку — и ничего не происходит), либо обрабатывать их в стиле "произошла неизвестная ошибка". Но нужно отдавать себе отчёт в том, что это — не лучший UX. Его можно чем-то оправдывать, но стремиться надо к хорошему — к UX, который пользователя уважает. В частности, не требует от него навыков трассировки веб-сайтов по F12 для того, чтобы отличить ситуацию "в этом детском саду нет мест" от "сессия прокисла, перелогиньтесь".

M>У тебя в любом случае есть связь между двумя ресурсами. Ее можно показать с одного конца, с другого конца или с обоих концов. Последний вариант самый универсальный. Если связь пересекает границы микросервисов, существуют способы это реализовать не увеличивая лишнюю связность: обогащение на уровне gateway, backend for frontend, обогащения на уровне middleware, наконец, просто засунуть в HATEOAS вместо списка туров, ссылку по которой этот список можно получить. Обычно, за HATEOS как раз и отвечает не сам сервис, а middleware.

Можно. Такая реализация, собственно, разрывает жёсткую зависимость микросервисов друг от друга. Фасад, при условии того, что он сам по себе устроен достаточно примитивно — хорошая штука для построения интегрированных сценариев. Но, опять же, он не является необходимым звеном. А вот устранение кольцевых зависимостей микросервисов — как раз суровая необходимость.

M>А давай посчитаем Один указатель (кэшировать нужно не весь результат, а только порядок записей), пусть long -- 8 байт * 300k запросов в сутки * 1000 записей (ты же не забываешь про max_search_results)= всего 2.2Gb При этом 300к уникальных запросов это где-то 20M DAU т.е. федеральная система уровня всего СНГ по поиску с запасом влазит на одну машину. У нас, слава богу, не 2005 год и уже завезли кэши в разделяемой памяти, типа hazelcast и ehcache.

Омг, омг. Во-первых, кэшировать нужно, конечно же, весь результат. Потому что иначе совершенно непонятно, как в поиск Ивановых затесался Петров. Или в список билетов до 12000р затесался перелёт за 58000.
Во-вторых, что такое "указатель"? Я так понял, вы положились на то, что все исходные данные загружены в память вашей единственной машины?

M>Во-первых, проверка изменились ли результаты поиска эквивалентна выполнению самого запроса, так что кэширование результатов поиска не имеет смысла и никто им не пользуется.

Вы только что предложили кэшировать результаты запроса, и сами же пишете "никто не пользуется". Веб устроен так, что вы никуда не денетесь от распределённого состояния. Даже когда вы смотрите на страницу RSDN, вы смотрите не на "сервер", а на локальную копию результата запроса, которую вам отображает браузер. Весь вопрос — в том, можно ли склеить "полный" результат из его постраничных представлений.

M>Во-вторых, допустим клиент узнает что результаты изменились, делать-то ему что? Повторять запрос?

Зачем? REST как раз позволяет "обновить кэш" одним запросом безо всяких повторений.

M>Тогда никакой консистентности при переходе между страницами не будет и получится ровно то же самое что и с параметрами offset + limit в запросе. Настроить промежуточный кэширующий сервер, который примет полные результаты поиска, а отдавать будет с учетом range. Ну так то же хранение и получится.

Всё верно. Только это хранение вы реализуете не за счёт своих средств, дорогостоящих и ограниченных, а за счёт средств клиентов, которые масштабируются автоматически и бесплатно.
Наличие "промежуточного" кэшируюшего сервера — не обязательная часть решения. Можно считать, что у вас есть "кэширующий клиент", который способен построить иллюзию согласованной бесшовной картины.
Вы застали до-гуглмэпные времена? Когда основным картографическим сервисом был MapQuest, который как раз реализовывал концепцию "постраничной навигации". Пользователь мог двигать "окно просмотра" по фиксированной сетке, перемещаясь по ней в четырёх направлениях. Гугл сумел придумать и реализовать клиента, который создаёт иллюзию "бесконечного канваса", несмотря на наличие под капотом точно такого же "постраничного" механизма.
Теперь всем очевидно, что именно такой способ навигации по "огромной плоскости" и является нормальной реализацией концепции просмотра большой картинки через маленькое окно. Карты гугла, яндекса, 2гиса, и примерно кого угодно теперь устроены именно так, и никак иначе. Та же концепция — у Miro, Figma, и бесчисленного множества диаграммных сервисов.
И только "табличные данные", которые являются частным случаем ровно той же задачи, до сих пор реализуются методиками девяностых годов прошлого века. Нет никакой причины так делать, кроме "здесь так принято" и "мне лень думать, как сделать нормально".

M>Мы подняли все ресурсы, входящие в сценарий, убедились, что их состояние позволяет реализовать этот сценарий и только после этого начинаем претворять сценарий в жизнь. Понимаешь, когда речь идет про микро сервисы, когда каждый сервис отвечает за свой домен и управляет одним-двумя ресурсами, почти все сценарии захватывают несколько сервисов. При этом подавляющее большинство сценариев не требует строгой консистентности, вполне достаточно eventual consistency. Поэтому нет необходимости любой сценарий превращать в сагу или двухфазный коммит. Более того, сценарии, требующие строгой консистентности встречаются настолько редко, что большинство разработчиков такого не реализовывали ни разу в жизни. В то же время, eventual consistency это все еще consistency, а если у нас сценарии разваливаются через раз, никакой консистентности не будет. Поэтому, дизайнить систему так, чтобы сценарии не разваливались, это хорошая идея. В том числе поддерживать между сервисами контракт, что если мы получили от строннего сервиса ресурс и список связанных ресурсов, то попытка обратиться к этим ресурсам не вызовет ошибки.

Этот "контракт" невозможно надёжно обеспечить в реальной среде. Всё, что можно делать — это притворяться, что он выполняется. Поэтому существенной разницы между hateoas и "компактной" формой ресурсов с точки зрения достигнутого результата я не вижу.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[15]: Каких программ вам не хватает?
От: Miroff Россия  
Дата: 08.04.25 12:26
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>2. Делаем два ресурса: "анонимизированное постановление", "полноценное постановление". Анонимный доступ ко второму получает 401, аутентифицированный доступ без прав на данное дело получает 403.


А если у тебя десять независимых полей в ресурсе? Будешь делать 100 ресурсов? Сильно сомневаюсь что это хорошее решение, их же придется потом тестировать.

S>3. Делаем два ресурса: постановление, в "тексте" которого есть ссылки на фигурантов, каждый из которых — самостоятельный ресурс. Постановления отдаём всем желающим, детали фигурантов — только авторизованным пользователям. Остальные получают 403.


Опять же, ИБ не велит) Как только у атакующего появляется возможность идентифицировать анонимизированые ресурсы, деанонимизация становится делом техники.

S>Можно ссылку на источник, который вы цитируете? Я не эксперт по ИБ, с удовольствием ознакомлюсь.


Можно, например, начать с википедии и заполировать OWASP Developer Guide. Современный подход к ИБ построен на модели швейцарского сыра: вместо того чтобы обеспечивать безопасность только в одном слое, мы реализуем достаточный уровень безопасности на каждом слое. Один из аспектов такого подхода это принцип минимальных привилегий (пользователю или сервису выдаются как можно меньшие права на как можно более короткий срок достаточный для выполнения операции) и принцип разделения (пользователю выдается только та информация, которая необходима для выполнения операции). И нет, это не security by obscutiry, потому что безопасность на слое ресурсов никак не отменяет проверки прав на уровне сервисов, а лишь дополняет их. Короче, если ты все еще занимаешься разработкой и тем более принятием архитектурных решений, рекомендую пройти какой-нибудь хороший AppSec тренинг, а то с твоего детства многое изменилось )

S>Я не понимаю, что вы имеете под пунктом а). Да, совершенно верно, причин ошибки много, и их надо обрабатывать. В любом случае.


В времена Нового Царства, каждый египтянин после смерти подвергался суду Осириса, где он должен был долго и нужно перечислять чего в жизни он НЕ делал. Вот и с ошибками та же история ) Позитивный сценарий может завершиться только одним способом, негативный -- бесконечным множеством способов из которых восстановимых считанные единицы: 502, да 401 и то не всегда.

S>Во-вторых, что такое "указатель"? Я так понял, вы положились на то, что все исходные данные загружены в память вашей единственной машины?


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

S>Всё верно. Только это хранение вы реализуете не за счёт своих средств, дорогостоящих и ограниченных, а за счёт средств клиентов, которые масштабируются автоматически и бесплатно.


Погоди, ты же только что предлагал в заголовках передавать range. Как у тебя будет работать согласованное кэширование, если часть диапазона клиентом даже не запрашивалась? Не говоря уже о том, что браузеры не поддерживают кэширование совместно с range.

S>И только "табличные данные", которые являются частным случаем ровно той же задачи, до сих пор реализуются методиками девяностых годов прошлого века. Нет никакой причины так делать, кроме "здесь так принято" и "мне лень думать, как сделать нормально".


Вообще говоря, в 25 году мало кто работает с табличными данными вообще. Сейчас в моде разделяемое состояние между сервером и клиентом и реактивное программирование для двусторонней синхронизации этой модели в реальном времени. Если непонятно сформулировал, посмотри на фейсбук.

S>Этот "контракт" невозможно надёжно обеспечить в реальной среде. Всё, что можно делать — это притворяться, что он выполняется. Поэтому существенной разницы между hateoas и "компактной" формой ресурсов с точки зрения достигнутого результата я не вижу.


Так практически вся микросервисная архитектура это история не про гарантии, а про достаточно хорошие допущения.
Re[16]: Каких программ вам не хватает?
От: Sinclair Россия https://github.com/evilguest/
Дата: 08.04.25 12:48
Оценка:
Здравствуйте, Miroff, Вы писали:

M>А если у тебя десять независимых полей в ресурсе? Будешь делать 100 ресурсов?

Это очень странное предположение. Что значит "независимых"? Независимость и означает, что это не один ресурс, а несколько. А их искусственное склеивание — прямой путь создать себе проблемы.
M>Сильно сомневаюсь что это хорошее решение, их же придется потом тестировать.
А в других вариантах их типа можно не тестировать? Как раз нет: вам нужно протестировать не просто корректность раздачи прав доступа на 10 разных ресурсов, а 210 комбинаций вида "есть права на F1 и F3, нет прав на F2 и прочие".

S>>3. Делаем два ресурса: постановление, в "тексте" которого есть ссылки на фигурантов, каждый из которых — самостоятельный ресурс. Постановления отдаём всем желающим, детали фигурантов — только авторизованным пользователям. Остальные получают 403.


M>Опять же, ИБ не велит) Как только у атакующего появляется возможность идентифицировать анонимизированые ресурсы, деанонимизация становится делом техники.

Необязательно. Если делать криво, то да. А если делать по уму, то никакой возможности не появится.

S>>Можно ссылку на источник, который вы цитируете? Я не эксперт по ИБ, с удовольствием ознакомлюсь.


M>Можно, например, начать с википедии и заполировать OWASP Developer Guide. 4

Спасибо, интересно.

M>Не обязательно, любой идентификатор объекта. Хотя, конечно, кэши на разделяемой памяти выгладят красиво.

Ну, вот "любой идентификатор" — это уже не 8 байт, а как минимум 16 (если мы пользуемся гуидами). А то и больше, если у нас ресурсы размазаны по нескольким неймспейсам.

M>Погоди, ты же только что предлагал в заголовках передавать range. Как у тебя будет работать согласованное кэширование, если часть диапазона клиентом даже не запрашивалась? Не говоря уже о том, что браузеры не поддерживают кэширование совместно с range.

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

M>Вообще говоря, в 25 году мало кто работает с табличными данными вообще. Сейчас в моде разделяемое состояние между сервером и клиентом и реактивное программирование для двусторонней синхронизации этой модели в реальном времени. Если непонятно сформулировал, посмотри на фейсбук.

Ок, тем лучше. У меня отвалился антизапрет, а включать VPN чтобы почитать фейсбуковый API guide мне лень. Выражу осторожное сомнение в том, что у фейсбука под капотом — пейджинг на limit offset. Скорее всего, там предикатный метки (примерно так же, как сделаны continuation token в многостраничных респонсах MS Graph API) или там какие-нибудь timestamp ranges.

M>Так практически вся микросервисная архитектура это история не про гарантии, а про достаточно хорошие допущения.

Кмк, это не потому, что такова была цель, а потому что "так получилось". Я же говорю — удачных примеров MSA я видел в единичных количествах, а вот неудачных — как говна за баней.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[15]: Каких программ вам не хватает?
От: · Великобритания  
Дата: 08.04.25 13:09
Оценка: 8 (1)
Здравствуйте, Sinclair, Вы писали:

S>2. Делаем два ресурса: "анонимизированное постановление", "полноценное постановление". Анонимный доступ ко второму получает 401, аутентифицированный доступ без прав на данное дело получает 403.

Такое экспоненциально рванёт. У тебя 2 ресурса для одного permission "смотреть инфу о фигурантах". Представь у тебя 10 таких permissions, в зависимости от роли пользователя. Потребуется 1024 разных ресурса.
А ещё ты можешь запрашивать список документов. К половине у тебя роль полного доступа, а к половине частичного.

S>3. Делаем два ресурса: постановление, в "тексте" которого есть ссылки на фигурантов, каждый из которых — самостоятельный ресурс. Постановления отдаём всем желающим, детали фигурантов — только авторизованным пользователям. Остальные получают 403.

Получаем список из n документов, и в каждом ещё 10 ссылок. Тут же шлём ещё n*10 запросов, некоторые из которых что-то возвращают, а некоторые дают 403 отлуп... Тучи запросов и тормоза на пустом месте.

S>Как по мне, так первый вариант, очевидно, самый-самый плохой. Он плохо масштабируется, и крайне плохо проверяется на корректность.

Зато работает.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[16]: Каких программ вам не хватает?
От: Sinclair Россия https://github.com/evilguest/
Дата: 08.04.25 15:24
Оценка:
Здравствуйте, ·, Вы писали:

S>>2. Делаем два ресурса: "анонимизированное постановление", "полноценное постановление". Анонимный доступ ко второму получает 401, аутентифицированный доступ без прав на данное дело получает 403.

·>Такое экспоненциально рванёт. У тебя 2 ресурса для одного permission "смотреть инфу о фигурантах". Представь у тебя 10 таких permissions, в зависимости от роли пользователя. Потребуется 1024 разных ресурса.
Это ж не настоящие ресурсы, а виртуальные. В параллельном ответе пояснил, что экспоненциальный взрыв наступает даже тогда, когда ресурс "один", но может быть отдан в 1024 разных конфигурациях.

S>>3. Делаем два ресурса: постановление, в "тексте" которого есть ссылки на фигурантов, каждый из которых — самостоятельный ресурс. Постановления отдаём всем желающим, детали фигурантов — только авторизованным пользователям. Остальные получают 403.

·>Получаем список из n документов, и в каждом ещё 10 ссылок. Тут же шлём ещё n*10 запросов, некоторые из которых что-то возвращают, а некоторые дают 403 отлуп... Тучи запросов и тормоза на пустом месте.
Зато всё безопасно. Причин для тормозов я не вижу: ваш "рабочий" вариант делает всё то же самое "под капотом", т.к. пермишны проверить всё равно надо, и сходить за данными фигуранта тоже надо. Единственная радость — некоторая экономия на хидерах.

S>>Как по мне, так первый вариант, очевидно, самый-самый плохой. Он плохо масштабируется, и крайне плохо проверяется на корректность.

·>Зато работает.
А вы тестировали? Все 1024 комбинации прав и привилегий?

На практике, конечно же, таких мелкогранулярных систем безопасности не бывает. Как правило, всё квадратно-гнездовое, и набор ролей фиксирован в бизнес-модели (и зачастую ещё и продиктован регулятором).
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[17]: Каких программ вам не хватает?
От: · Великобритания  
Дата: 08.04.25 16:15
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>>>2. Делаем два ресурса: "анонимизированное постановление", "полноценное постановление". Анонимный доступ ко второму получает 401, аутентифицированный доступ без прав на данное дело получает 403.

S>·>Такое экспоненциально рванёт. У тебя 2 ресурса для одного permission "смотреть инфу о фигурантах". Представь у тебя 10 таких permissions, в зависимости от роли пользователя. Потребуется 1024 разных ресурса.
S>Это ж не настоящие ресурсы, а виртуальные. В параллельном ответе пояснил, что экспоненциальный взрыв наступает даже тогда, когда ресурс "один", но может быть отдан в 1024 разных конфигурациях.
Гы. Практически с таким же успехом можно засунуть bearer-токен в url, вот у тебя по ресурсу для каждой конфигурации.

S>·>Получаем список из n документов, и в каждом ещё 10 ссылок. Тут же шлём ещё n*10 запросов, некоторые из которых что-то возвращают, а некоторые дают 403 отлуп... Тучи запросов и тормоза на пустом месте.

S>Зато всё безопасно. Причин для тормозов я не вижу: ваш "рабочий" вариант делает всё то же самое "под капотом", т.к. пермишны проверить всё равно надо, и сходить за данными фигуранта тоже надо. Единственная радость — некоторая экономия на хидерах.
Поход внутри сервиса может осуществляться в памяти того же процесса сервиса, в крайнем случае добавлением соответствующих JOIN в sql. А так у тебя будет куча сетевых вызовов... и представь это всё с мобилы через инет! Надо считать roundtrips.

S>·>Зато работает.

S>А вы тестировали? Все 1024 комбинации прав и привилегий?
Каждую комбинацию тестировать не нужно. Нужно тестировать каждую привелегию. Два теста: "разрешено всё -> возвращается инфа о фигурантах", "разрешено всё, кроме инфы о фигурантах -> не возвращается инфа о фигурантах". Ну и отдельно матрица роли <-> привилегии.

Анонимный доступ это такая же роль, как и авторизированный внутренний юзер, внешний юзер, юзер из другого подразделения, админ, аудитор и т.п. И у каждой роли своё подмножество привилегий.

S>На практике, конечно же, таких мелкогранулярных систем безопасности не бывает. Как правило, всё квадратно-гнездовое, и набор ролей фиксирован в бизнес-модели (и зачастую ещё и продиктован регулятором).

Ролей может быть, да. А привилегии — их может быть очень много.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[18]: Каких программ вам не хватает?
От: Sinclair Россия https://github.com/evilguest/
Дата: 09.04.25 06:55
Оценка:
Здравствуйте, ·, Вы писали:

S>>Это ж не настоящие ресурсы, а виртуальные. В параллельном ответе пояснил, что экспоненциальный взрыв наступает даже тогда, когда ресурс "один", но может быть отдан в 1024 разных конфигурациях.

·>Гы. Практически с таким же успехом можно засунуть bearer-токен в url, вот у тебя по ресурсу для каждой конфигурации.
Ну, да. Поэтому я и не назвал этот способ самым лучшим. Он приемлем тогда, когда у нас нет большого разнообразия пермиссий. Скажем, есть инвойс "с точки зрения плательщика", а есть тот же инвойс "с точки зрения получателя".
Вместо того, чтобы искусственно совмещать их в одном ресурсе и отдавать разный контент в зависимости от содержимого bearer token, делается два разных ресурса с похожей структурой.

·>Поход внутри сервиса может осуществляться в памяти того же процесса сервиса, в крайнем случае добавлением соответствующих JOIN в sql. А так у тебя будет куча сетевых вызовов... и представь это всё с мобилы через инет! Надо считать roundtrips.

Можно и считать. В разных задачах — разные приоритеты требований. Безопасность очень часто входит в конфликт с производительностью.

·>Каждую комбинацию тестировать не нужно. Нужно тестировать каждую привелегию. Два теста: "разрешено всё -> возвращается инфа о фигурантах", "разрешено всё, кроме инфы о фигурантах -> не возвращается инфа о фигурантах". Ну и отдельно матрица роли <-> привилегии.

Перед тем, как прийти к таким выводам, придётся как-то доказать независимость code path, которые приводят к появлению тех или иных результатов. Ну, или надеяться на эту независимость, и рисковать пролезанием false negative в каких-то особенных комбинациях привилегий.
·>Анонимный доступ это такая же роль, как и авторизированный внутренний юзер, внешний юзер, юзер из другого подразделения, админ, аудитор и т.п. И у каждой роли своё подмножество привилегий.
Это всё понятно.
S>>На практике, конечно же, таких мелкогранулярных систем безопасности не бывает. Как правило, всё квадратно-гнездовое, и набор ролей фиксирован в бизнес-модели (и зачастую ещё и продиктован регулятором).
·>Ролей может быть, да. А привилегии — их может быть очень много.
Повторюсь: это зависит от задачи. Модель привилегий и ролей — это всего лишь оптимизация процесса "пересмотр ролей". В зарегулированном бизнесе набор привилегий жёстко связан с ролью.
И это не просто так: бездумная раздача привилегий слишком легко позволяет создавать дырки там, где их не ожидаешь. Типа, напрямую посмотреть реквизиты произвольного контрагента я не могу (прав нет), но могу отправить ему 1 рубль через платёж по номеру телефона. А код формирования ресурса "квитанция о платеже" ничего о привилегиях на контрагентов не знает — у него свой набор привилегий, и вот я уже вижу все реквизиты встроенными прямо в тело квитанции.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[19]: Каких программ вам не хватает?
От: · Великобритания  
Дата: 09.04.25 09:27
Оценка: +1
Здравствуйте, Sinclair, Вы писали:

S>>>Это ж не настоящие ресурсы, а виртуальные. В параллельном ответе пояснил, что экспоненциальный взрыв наступает даже тогда, когда ресурс "один", но может быть отдан в 1024 разных конфигурациях.

S>·>Гы. Практически с таким же успехом можно засунуть bearer-токен в url, вот у тебя по ресурсу для каждой конфигурации.
S>Ну, да. Поэтому я и не назвал этот способ самым лучшим. Он приемлем тогда, когда у нас нет большого разнообразия пермиссий. Скажем, есть инвойс "с точки зрения плательщика", а есть тот же инвойс "с точки зрения получателя".
Или нет смешанных пермиссий. Скажем, получить список инвойсов за период, и получится что некоторые инвойсы где ты плательщик, а некоторые получатель. В общем, способ может и красивый, но почти бесполезный на практике.

S>Вместо того, чтобы искусственно совмещать их в одном ресурсе и отдавать разный контент в зависимости от содержимого bearer token, делается два разных ресурса с похожей структурой.

Угу. А потом получится, что сегодня два, завтра внезапно понадобился третий, а через год у нас их уже 1024. Так что ещё и немножечко вредный.

S>·>Поход внутри сервиса может осуществляться в памяти того же процесса сервиса, в крайнем случае добавлением соответствующих JOIN в sql. А так у тебя будет куча сетевых вызовов... и представь это всё с мобилы через инет! Надо считать roundtrips.

S>Можно и считать. В разных задачах — разные приоритеты требований. Безопасность очень часто входит в конфликт с производительностью.
Интересно узнать какой такой магией фрагмент в урле повышает безопасность? Как ты будешь доказывать или тестировать безопасность 1024 конфигураций ресурса, пусть и виртуальных?
По сути ровно те же данные в теле запроса. Просто кусочек инфы переползает из ~третей строчки http запроса (там где Authorization: Bearer хедер) в первую строчку (там где урл). Злоумышленникам по барабану какую часть менять, а программисты с равным успехом могут налажать в проверках любой части запроса.

Урлы имеют смысл не для безопасности, а для кеширующих прокси (та самая производительность!). Но прокси на практике умеют работать только с анонимными ресурсами, у которых никаких пермов нет и можно смело всё отдавать всем. Только в этом случае есть гарантии не нарушения безопасности, т.к. нарушать собственно нечего.

S>·>Каждую комбинацию тестировать не нужно. Нужно тестировать каждую привелегию. Два теста: "разрешено всё -> возвращается инфа о фигурантах", "разрешено всё, кроме инфы о фигурантах -> не возвращается инфа о фигурантах". Ну и отдельно матрица роли <-> привилегии.

S>Перед тем, как прийти к таким выводам, придётся как-то доказать независимость code path, которые приводят к появлению тех или иных результатов. Ну, или надеяться на эту независимость, и рисковать пролезанием false negative в каких-то особенных комбинациях привилегий.
Доказывать эту независимость придётся ровно тем же способом, как и для твоих 1024 виртуальных ресурсов.
Единственное, что может помочь, что есть какой-то уже готовый фреймворк, про который авторы зуб дают, что всё безопасно, а твоя аппликуха на него полагается. Но с т.з. системы в целом — ранзицы никакой.

S>>>На практике, конечно же, таких мелкогранулярных систем безопасности не бывает. Как правило, всё квадратно-гнездовое, и набор ролей фиксирован в бизнес-модели (и зачастую ещё и продиктован регулятором).

S>·>Ролей может быть, да. А привилегии — их может быть очень много.
S>Повторюсь: это зависит от задачи. Модель привилегий и ролей — это всего лишь оптимизация процесса "пересмотр ролей". В зарегулированном бизнесе набор привилегий жёстко связан с ролью.
S>И это не просто так: бездумная раздача привилегий слишком легко позволяет создавать дырки там, где их не ожидаешь. Типа, напрямую посмотреть реквизиты произвольного контрагента я не могу (прав нет), но могу отправить ему 1 рубль через платёж по номеру телефона. А код формирования ресурса "квитанция о платеже" ничего о привилегиях на контрагентов не знает — у него свой набор привилегий, и вот я уже вижу все реквизиты встроенными прямо в тело квитанции.
Как твои виртуальные ресурсы помогут? Ну да, "GET /contragents?id=vasya" тебе запрещён, а "POST /payments?to=vasya" тебе выдаст квиток с инфой конртагента.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Отредактировано 09.04.2025 9:28 · . Предыдущая версия .
Re[20]: Каких программ вам не хватает?
От: Sinclair Россия https://github.com/evilguest/
Дата: 09.04.25 11:35
Оценка:
Здравствуйте, ·, Вы писали:

·>Или нет смешанных пермиссий. Скажем, получить список инвойсов за период, и получится что некоторые инвойсы где ты плательщик, а некоторые получатель.

Ну, вот на практике есть два разных списка: "инвойсы, которые выставил я", и "инвойсы, которые выставили мне". Всё, никаких чудес. Зачем делать единый список, а потом мужественно бороться с разнотипностью — .
Посмотрите на тот же Paypal API — он, хоть и не-REST, но устроен именно так.

·>Угу. А потом получится, что сегодня два, завтра внезапно понадобился третий, а через год у нас их уже 1024. Так что ещё и немножечко вредный.

Или не получится.

·>Интересно узнать какой такой магией фрагмент в урле повышает безопасность?

Очень просто: у нас нет "частичной безопасности", когда содержимое ресурса зависит от каких-то эфемерных вещей. У нас для запроса есть ровно два возможных ответа: 403 или 200.

·>Как ты будешь доказывать или тестировать безопасность 1024 конфигураций ресурса, пусть и виртуальных?

Очень просто. 2048 тестов, если уж у нас есть 1024 конфигурации ресурса. Но я повторю ещё раз: у нас не будет 1024 конфигураций. Этот способ не подходит для таких API, в которых есть 10 разных привилегий на один и тот же ресурс.

·>Урлы имеют смысл не для безопасности, а для кеширующих прокси (та самая производительность!). Но прокси на практике умеют работать только с анонимными ресурсами, у которых никаких пермов нет и можно смело всё отдавать всем. Только в этом случае есть гарантии не нарушения безопасности, т.к. нарушать собственно нечего.

На практике прокси прекрасно работают и с ресурсами, у которых cache-control: private. Это как раз позволяет каждому клиенту построить у себя частичную реплику распределённого состояния, и эффективно с ней взаимодействовать.

·>Доказывать эту независимость придётся ровно тем же способом, как и для твоих 1024 виртуальных ресурсов.

Ну так для 1024 ресурсов у нас будет 2048 тестов. Вам же кажется, что можно как-то обойтись 20 тестами.
·>Как твои виртуальные ресурсы помогут? Ну да, "GET /contragents?id=vasya" тебе запрещён, а "POST /payments?to=vasya" тебе выдаст квиток с инфой конртагента.
Виртуальные ресурсы помогут избавиться от иллюзии того, что данные Васи видны только тем, у кого есть привилегия "видеть данные Васи".
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[21]: Каких программ вам не хватает?
От: · Великобритания  
Дата: 09.04.25 13:21
Оценка: +1
Здравствуйте, Sinclair, Вы писали:

S>Ну, вот на практике есть два разных списка: "инвойсы, которые выставил я", и "инвойсы, которые выставили мне". Всё, никаких чудес. Зачем делать единый список, а потом мужественно бороться с разнотипностью — .

S>Посмотрите на тот же Paypal API — он, хоть и не-REST, но устроен именно так.
Я что-то перестал понимать о чём идёт речь. Вроде ты обсуждал возможность, что некий запрос какого-то ресурса, который выдаёт результат, раскрывающий детали других ресурсов. Т.е. когда например результирующий инвойс содержит приватные данные контрагента.
То что Paypal API устроен именно так... ну дык он для того, чтобы человеки хорошо понимали, а не для безопасности.

S>·>Интересно узнать какой такой магией фрагмент в урле повышает безопасность?

S>Очень просто: у нас нет "частичной безопасности", когда содержимое ресурса зависит от каких-то эфемерных вещей. У нас для запроса есть ровно два возможных ответа: 403 или 200.
Частичной нет, верно... да вообще никакой нет. Ну выдал ваш /invoices-for-me?id=123 json 200, в котором внезапно появится секция contragent: {homeAddress: {...}}, хотя разрешено только companyAddress выдавать. А ещё злоумышленник подменит урл на /my-invoices?id=123 и увидит вообще всё.

S>·>Как ты будешь доказывать или тестировать безопасность 1024 конфигураций ресурса, пусть и виртуальных?

S>Очень просто. 2048 тестов, если уж у нас есть 1024 конфигурации ресурса.
Если у тебя уже для такой тривиальной вещи 2048 тестов, то они абсолютно бесполезны, т.к. их никто не сможет проанализировать на безопасность и поддерживать в дальнейшем.

S> Но я повторю ещё раз: у нас не будет 1024 конфигураций. Этот способ не подходит для таких API, в которых есть 10 разных привилегий на один и тот же ресурс.

А пофиг. Привилегии должны проверяться на источнике данных, а не на endpoint-е. Источник данных контрагента — это скорее всего один метод где-то внутрях. И именно он потребует наличие ровно одной конкретной привилегии. И не отдаст данные если привилегии нет, вне зависимости от того как обратились к сервису — через /contragents, через инвойсы или через платежи.
Ещё раз, ресурсы-сервисы-endpoints — это всё о том в каком формате обменяться данными по сети, и отношение к безопасности имеет чисто иллюзорное.

S>·>Урлы имеют смысл не для безопасности, а для кеширующих прокси (та самая производительность!). Но прокси на практике умеют работать только с анонимными ресурсами, у которых никаких пермов нет и можно смело всё отдавать всем. Только в этом случае есть гарантии не нарушения безопасности, т.к. нарушать собственно нечего.

S>На практике прокси прекрасно работают и с ресурсами, у которых cache-control: private. Это как раз позволяет каждому клиенту построить у себя частичную реплику распределённого состояния, и эффективно с ней взаимодействовать.
Не понял. "cache-control: private" — это как раз инструкция отключающая кеш на прокси. Или под "работают" ты тут имел в виду "по идее должен сам отключаться"? И ты так и не пояснил какое это отношение имеет к безопасности.

S>Ну так для 1024 ресурсов у нас будет 2048 тестов. Вам же кажется, что можно как-то обойтись 20 тестами.

S>·>Как твои виртуальные ресурсы помогут? Ну да, "GET /contragents?id=vasya" тебе запрещён, а "POST /payments?to=vasya" тебе выдаст квиток с инфой конртагента.
S>Виртуальные ресурсы помогут избавиться от иллюзии того, что данные Васи видны только тем, у кого есть привилегия "видеть данные Васи".
А откуда такая иллюзия появится в принципе особенно в случае эвфемерных вещей??
Как раз вот илюзия "запретим выдачу деталей контрагента по урлу GET /contragents — значит детали контрагента никому не будут видны без нужной привилегии" и создаётся.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Отредактировано 09.04.2025 13:25 · . Предыдущая версия .
Re[22]: Каких программ вам не хватает?
От: Sinclair Россия https://github.com/evilguest/
Дата: 09.04.25 15:47
Оценка:
Здравствуйте, ·, Вы писали:
·>Я что-то перестал понимать о чём идёт речь. Вроде ты обсуждал возможность, что некий запрос какого-то ресурса, который выдаёт результат, раскрывающий детали других ресурсов. Т.е. когда например результирующий инвойс содержит приватные данные контрагента.
Нет, не содержит он никаких приватных данных контрагента. Инвойс, выставленный мне, ни в каком случае не показывает "закрытые" атрибуты отправителя. Независимо от моих "привилегий".
Инвойс, который выставил я, содержит дополнительные поля, которые на стороне получателя видны не будут. Опять же, мне они видны независимо от моих привилегий.
Доступ к "моим" инвойсам всем остальным пользователям закрыт не на уровне отдельных полей и привилегий, а на уровне всего субресурса
·>То что Paypal API устроен именно так... ну дык он для того, чтобы человеки хорошо понимали, а не для безопасности.
У пейпала с безопасностью всё в порядке.

·>Частичной нет, верно... да вообще никакой нет. Ну выдал ваш /invoices-for-me?id=123 json 200, в котором внезапно появится секция contragent: {homeAddress: {...}}, хотя разрешено только companyAddress выдавать. А ещё злоумышленник подменит урл на /my-invoices?id=123 и увидит вообще всё.

Нет, не увидит. Внутри ресурса /my-invoices/ нет никаких чужих инвойсов.
·>Если у тебя уже для такой тривиальной вещи 2048 тестов, то они абсолютно бесполезны, т.к. их никто не сможет проанализировать на безопасность и поддерживать в дальнейшем.
У меня складывается впечатление, что вы читаете не всё, что я пишу. Давайте вы ещё раз перечитаете всё с самого начала и внимательно посмотрите, с какими тезисами вы спорите.

·>А пофиг. Привилегии должны проверяться на источнике данных, а не на endpoint-е.

Забавная идея. Ну, вот у вас "источник данных" — реляционная БД. Какие вы там привилегии собрались проверять?

·>Ещё раз, ресурсы-сервисы-endpoints — это всё о том в каком формате обменяться данными по сети, и отношение к безопасности имеет чисто иллюзорное.

Ну, иллюзорную так иллюзорную.

·>Не понял. "cache-control: private" — это как раз инструкция отключающая кеш на прокси.

Я неправильно написал. Речь не о прокси, а о кэшировании на стороне клиента. Оно точно так же поднимает производительность, т.к. позволяет нам не отдавать неизменные данные; при этом оно никак не противоречит безопасности.


S>>Виртуальные ресурсы помогут избавиться от иллюзии того, что данные Васи видны только тем, у кого есть привилегия "видеть данные Васи".

·>А откуда такая иллюзия появится в принципе особенно в случае эвфемерных вещей??
Ну вот у вас она уже возникла.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[23]: Каких программ вам не хватает?
От: · Великобритания  
Дата: 10.04.25 11:20
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>·>Я что-то перестал понимать о чём идёт речь. Вроде ты обсуждал возможность, что некий запрос какого-то ресурса, который выдаёт результат, раскрывающий детали других ресурсов. Т.е. когда например результирующий инвойс содержит приватные данные контрагента.

S>Нет, не содержит он никаких приватных данных контрагента. Инвойс, выставленный мне, ни в каком случае не показывает "закрытые" атрибуты отправителя.
S>Независимо от моих "привилегий".
Закрытые для кого? Закрытость — вещь относительная. На какие-то атрибуты у тебя есть привилегии, на какие-то нет. У других пользователей будет другой доступ к атрибутам.

S>Инвойс, который выставил я, содержит дополнительные поля, которые на стороне получателя видны не будут. Опять же, мне они видны независимо от моих привилегий.

S>Доступ к "моим" инвойсам всем остальным пользователям закрыт не на уровне отдельных полей и привилегий, а на уровне всего субресурса
Каким образом закрыт-то? Заклятие наложено что-ли? Субресурс возвращает джсон, как ты ресурсом гарантируешь отстутствие там какого-нибудь contragent.homeAddress?

S>·>То что Paypal API устроен именно так... ну дык он для того, чтобы человеки хорошо понимали, а не для безопасности.

S>У пейпала с безопасностью всё в порядке.
Верю. Но не потому, что "API устроен именно так".

S>·>Частичной нет, верно... да вообще никакой нет. Ну выдал ваш /invoices-for-me?id=123 json 200, в котором внезапно появится секция contragent: {homeAddress: {...}}, хотя разрешено только companyAddress выдавать. А ещё злоумышленник подменит урл на /my-invoices?id=123 и увидит вообще всё.

S>Нет, не увидит. Внутри ресурса /my-invoices/ нет никаких чужих инвойсов.
Почему ты так решил? Ты так говоришь, что ресурс это какая-то охраняемая зона за колючей проволокой. Нет, это просто несколько байт в определённом месте хедера запроса, а обрабатывает всё это дело тот же самый условно питонячий код, что и для других ресурсов.

S>·>Если у тебя уже для такой тривиальной вещи 2048 тестов, то они абсолютно бесполезны, т.к. их никто не сможет проанализировать на безопасность и поддерживать в дальнейшем.

S>У меня складывается впечатление, что вы читаете не всё, что я пишу. Давайте вы ещё раз перечитаете всё с самого начала и внимательно посмотрите, с какими тезисами вы спорите.
Я спорю с тем, что ресурсы и урлы каким-то образом обеспечивают хоть какую-то безопасность. Что в зависимости от того куда поместить данные — в урл или хедер — вдруг внезапно станет "Зато всё безопасно".

S>·>А пофиг. Привилегии должны проверяться на источнике данных, а не на endpoint-е.

S>Забавная идея. Ну, вот у вас "источник данных" — реляционная БД. Какие вы там привилегии собрались проверять?
А чё так мелко? Сразу уж говори — источник данных — заряд на затворе транзистора. Да, там с привилегиями как-то не очень. Я вообще-то говорил о дизайне самого сервиса. БД — это уже другой сервис.

S>·>Не понял. "cache-control: private" — это как раз инструкция отключающая кеш на прокси.

S>Я неправильно написал. Речь не о прокси, а о кэшировании на стороне клиента. Оно точно так же поднимает производительность, т.к. позволяет нам не отдавать неизменные данные; при этом оно никак не противоречит безопасности.
А, так да. Но собственно тут обсуждалось "Безопасность очень часто входит в конфликт с производительностью", мой вопрос был "Интересно узнать какой такой магией фрагмент в урле повышает безопасность?". И в качестве ответа ты внезапно рассказываешь о "поднимает производительность" "не противоречит безопасности".

S>·>А откуда такая иллюзия появится в принципе особенно в случае эвфемерных вещей??

S>Ну вот у вас она уже возникла.
С чего ты взял? Никогда не было. А вот у тебя иллюзия в полный рост, цитирую: "чтобы границы безопасности совпадали с границами ресурсов. Потому что это и надёжнее,", "Зато всё безопасно". Нет, конечно. Надёжность тут не причём. Так просто удобнее и понятнее для человеков: не видно, что не должно быть видно. Т.е. чисто иллюзорные результаты.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Отредактировано 10.04.2025 11:24 · . Предыдущая версия .
Re[24]: Каких программ вам не хватает?
От: Sinclair Россия https://github.com/evilguest/
Дата: 11.04.25 05:11
Оценка: 2 (1)
Здравствуйте, ·, Вы писали:
S>>Независимо от моих "привилегий".
·>Закрытые для кого? Закрытость — вещь относительная. На какие-то атрибуты у тебя есть привилегии, на какие-то нет. У других пользователей будет другой доступ к атрибутам.
Нет. Вот как раз предлагаемая вами модель чревата дырками и крайне тяжела в поддержке и верификации.
Я вам рассказываю практический замкнутый пример: нет никаких "привилегий на втрибуты". Есть два вида ресурсов. Доступ к каждому их них либо есть, либо нету.

·>Каким образом закрыт-то? Заклятие наложено что-ли? Субресурс возвращает джсон, как ты ресурсом гарантируешь отстутствие там какого-нибудь contragent.homeAddress?

Очень просто: contragent.homeAddress там нет вообще, вне зависимости от привилегий.

·>Верю. Но не потому, что "API устроен именно так".



·>Почему ты так решил? Ты так говоришь, что ресурс это какая-то охраняемая зона за колючей проволокой.

Потому что я так спроектировал, и это легко проверить как методом "белого ящика", так и "чёрного ящика".
·>Нет, это просто несколько байт в определённом месте хедера запроса, а обрабатывает всё это дело тот же самый условно питонячий код, что и для других ресурсов.
Если у вас так, то всё плохо. Попробуйте перепроектировать так, чтобы в одном коде не смешивалась обработка "своих" и "чужих" инвойсов. Человечество изобрело массу способов факторизации кода.

·>Я спорю с тем, что ресурсы и урлы каким-то образом обеспечивают хоть какую-то безопасность. Что в зависимости от того куда поместить данные — в урл или хедер — вдруг внезапно станет "Зато всё безопасно".

Не внезапно, а благодаря чистому дизайну с понятным набором ортогональных требований.

·>А чё так мелко? Сразу уж говори — источник данных — заряд на затворе транзистора. Да, там с привилегиями как-то не очень. Я вообще-то говорил о дизайне самого сервиса. БД — это уже другой сервис.

Нет, БД — это не "другой сервис", это неотъемлемый компонент сервиса, оборудованного персистентным состоянием.
Впрочем, можно спроектировать и так, как вы предлагаете — вынести БД в отдельный сервис, из которого торчит очень широкий контракт.
И, естественно, у него очень грубый набор привилегий. Ваша модель "давайте мы будем ограничивать доступ путём передачи пользовательского токена вдоль всей иерархии вызовов" работает примерно никогда.
Все практики безопасности как раз так и устроены, что у принципала X нету привилегий к "сырому" ресурсу A, но есть привилегии на доступ к "производному" ресурсу B. Сервис, выполняющий построение ресурса B, выполняется под принципалом Y, который имеет полные привилегии для A, но учитывает привилегии X при отдаче ему производного ресурса B.
Типичный пример применения концепции в рамках SQL99: пользователю нельзя видеть часть строк в таблице X. Мы не можем навесить привилегию на каждую строку. Зато можем сделать следующее:
1. Отбираем у пользователя привилегии на таблицу X
2. Строим на основе X представление Y, в котором добавлен предикат безопасности (типа select * from X where TotalAmount < 100000)
3. Выдаём пользователю привилегии на Y и указываем, что Y исполняется под привилегиями админа, а не пользователя.
Аналогично мы могли бы поступить и с ограничениями на колонки таблицы. Квадратно-гнездовая система, где чётко видна вся схема Y и легко проверить, что туда попадает, а что нет, как методом статического анализа, так и методом выполнения динамических тестов. Вы предлагаете заменить её на некий невнятный код "хранимой процедуры", которая возвращает всякий раз разный набор строк и колонок в зависимости от рантайм-содержимого параметров.
И всё это под тем предлогом, что "какая нам разница, где передаётся информация о привилегиях — всё равно это текст SQL запроса".
Нет, увы. Факторизация кода позволяет нам изолировать разные сценарии.

·>А, так да. Но собственно тут обсуждалось "Безопасность очень часто входит в конфликт с производительностью", мой вопрос был "Интересно узнать какой такой магией фрагмент в урле повышает безопасность?". И в качестве ответа ты внезапно рассказываешь о "поднимает производительность" "не противоречит безопасности".

Фрагмент в урле существует не сам по себе. Структура урла применятся для роутинга — выбора кода, который будет обслуживать поступивший запрос. Правила роутинга — простая, понятная логика, которую легко отладить и гарантировать отсутствие неожиданностей вроде "в ответ на запрос чужих инвойсов внезапно вызвался код по подготовке своих инвойсов".
Следующим шагом мы можем очень легко проверить, что код по подготовке "чужих" инвойсов никогда не возвращает приватных данных. Просто потому, что в этом коде вообще нет такой ветки, которая бы это делала.
Дальше нам остаётся проверить, что мы корректно проверяем claims в токене для того, чтобы понять, что входит в "свои" и в "чужие" инвойсы.
Собственно, на этом всё.

В вашем же подходе в коде какая-то каша, отдаётся примерно произвольный набор атрибутов с соответствии с хитро устроенными предикатами, смешивающими проверку нескольких разных claims. Доказать, что код выдаёт корректное сочетание атрибутов для произвольного сочетания claims — та ещё задача.

·>С чего ты взял? Никогда не было. А вот у тебя иллюзия в полный рост, цитирую: "чтобы границы безопасности совпадали с границами ресурсов. Потому что это и надёжнее,", "Зато всё безопасно". Нет, конечно. Надёжность тут не причём. Так просто удобнее и понятнее для человеков: не видно, что не должно быть видно. Т.е. чисто иллюзорные результаты.

Это оттого, что я плохо объясняю. Разница в подходах есть. Понятно, что достичь приемлемого результата можно в любом подходе, но стоимость получается разной. Когда границы безопасности совпадают с границами ресурсов, это сильно упрощает доказательство корректности. Я выше примерно написал, каким именно способом. Но вы можете мне не верить и писать более дорогостоящие и трудноподдерживаемые системы — у нас же нет архитектурной полиции
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[25]: Каких программ вам не хватает?
От: · Великобритания  
Дата: 11.04.25 12:24
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>·>Закрытые для кого? Закрытость — вещь относительная. На какие-то атрибуты у тебя есть привилегии, на какие-то нет. У других пользователей будет другой доступ к атрибутам.

S>Нет. Вот как раз предлагаемая вами модель чревата дырками и крайне тяжела в поддержке и верификации.
S>Я вам рассказываю практический замкнутый пример: нет никаких "привилегий на втрибуты". Есть два вида ресурсов. Доступ к каждому их них либо есть, либо нету.
Где есть два вида? В спеке?

S>·>Каким образом закрыт-то? Заклятие наложено что-ли? Субресурс возвращает джсон, как ты ресурсом гарантируешь отстутствие там какого-нибудь contragent.homeAddress?

S>Очень просто: contragent.homeAddress там нет вообще, вне зависимости от привилегий.
Как конкретно это гарантируется? Только не говори: "в API нету!". Не слыхал историй, когда какие-нибудь rest-endpoints случайно возвращали json с неожиданными полями. All tests passed, всё у всех работает.

S>·>Почему ты так решил? Ты так говоришь, что ресурс это какая-то охраняемая зона за колючей проволокой.

S>Потому что я так спроектировал, и это легко проверить как методом "белого ящика", так и "чёрного ящика".
Ну о чём и говорю. "Спроектировал" — это написал тонну word-документов и презентаций. И проверить легко, не спорю. А на самом деле json генерится питонячим кодом, который рефлексией вываливает всё что есть. И даже если всё было красиво в начале проекта, то после нескольких лет поддержки, рефакторингов и переписывания вдруг может что-то где-то вылезти.

S>·>Нет, это просто несколько байт в определённом месте хедера запроса, а обрабатывает всё это дело тот же самый условно питонячий код, что и для других ресурсов.

S>Если у вас так, то всё плохо. Попробуйте перепроектировать так, чтобы в одном коде не смешивалась обработка "своих" и "чужих" инвойсов. Человечество изобрело массу способов факторизации кода.
Может такое только в каких-то мелких проектах и пройдёт... И то никакой гарантии, что кто-то куда-то по ошибке не скопипастит. В серьёзных случаях у тебя будет 1024 вида своих и чужих.

S>·>А чё так мелко? Сразу уж говори — источник данных — заряд на затворе транзистора. Да, там с привилегиями как-то не очень. Я вообще-то говорил о дизайне самого сервиса. БД — это уже другой сервис.

S>Нет, БД — это не "другой сервис", это неотъемлемый компонент сервиса, оборудованного персистентным состоянием.
Надо технически смотреть, а не по поверпоинт презентациям. БД — компонент, если embedded, в лучшем случае. А так по сути другой сервис — формируешь запрос (query) и получаешь ответ (recordset). Ничем по факту от какого-нибудь rest не отличается, только протокол общения другой, вместо http у тебя sql.

S>Впрочем, можно спроектировать и так, как вы предлагаете — вынести БД в отдельный сервис, из которого торчит очень широкий контракт.

S>И, естественно, у него очень грубый набор привилегий. Ваша модель "давайте мы будем ограничивать доступ путём передачи пользовательского токена вдоль всей иерархии вызовов" работает примерно никогда.
Что значит "вынести"? Попробуй хоть как-нибудь не "вынести" какой-нибудь оракл из твоего питоячего сервиса.

S>Все практики безопасности как раз так и устроены, что у принципала X нету привилегий к "сырому" ресурсу A, но есть привилегии на доступ к "производному" ресурсу B. Сервис, выполняющий построение ресурса B, выполняется под принципалом Y, который имеет полные привилегии для A, но учитывает привилегии X при отдаче ему производного ресурса B.

S>Типичный пример применения концепции в рамках SQL99: пользователю нельзя видеть часть строк в таблице X. Мы не можем навесить привилегию на каждую строку. Зато можем сделать следующее:
S>1. Отбираем у пользователя привилегии на таблицу X
S>2. Строим на основе X представление Y, в котором добавлен предикат безопасности (типа select * from X where TotalAmount < 100000)
S>3. Выдаём пользователю привилегии на Y и указываем, что Y исполняется под привилегиями админа, а не пользователя.
S>Аналогично мы могли бы поступить и с ограничениями на колонки таблицы. Квадратно-гнездовая система, где чётко видна вся схема Y и легко проверить, что туда попадает, а что нет, как методом статического анализа, так и методом выполнения динамических тестов. Вы предлагаете заменить её на некий невнятный код "хранимой процедуры", которая возвращает всякий раз разный набор строк и колонок в зависимости от рантайм-содержимого параметров.
Я как-то более о практике. Статический анализ, конечно, хорошо... Но если тебе для этого придётся описывать "1024 виртуальных ресурсов" и писать 2048 тестов для них, но это не заработает на практике, хотя в теории, конечно, красота...

S>Нет, увы. Факторизация кода позволяет нам изолировать разные сценарии.

Если у тебя два сценария, то, конечно, это щастье. А вот когда сценариев 1024...

S>·>А, так да. Но собственно тут обсуждалось "Безопасность очень часто входит в конфликт с производительностью", мой вопрос был "Интересно узнать какой такой магией фрагмент в урле повышает безопасность?". И в качестве ответа ты внезапно рассказываешь о "поднимает производительность" "не противоречит безопасности".

S>Фрагмент в урле существует не сам по себе. Структура урла применятся для роутинга — выбора кода, который будет обслуживать поступивший запрос. Правила роутинга — простая, понятная логика, которую легко отладить и гарантировать отсутствие неожиданностей вроде "в ответ на запрос чужих инвойсов внезапно вызвался код по подготовке своих инвойсов".
S>Следующим шагом мы можем очень легко проверить, что код по подготовке "чужих" инвойсов никогда не возвращает приватных данных. Просто потому, что в этом коде вообще нет такой ветки, которая бы это делала.
Ну будет у тебя 1024 кусков кода и неподдерживаемая кодовая база.

S>В вашем же подходе в коде какая-то каша, отдаётся примерно произвольный набор атрибутов с соответствии с хитро устроенными предикатами, смешивающими проверку нескольких разных claims. Доказать, что код выдаёт корректное сочетание атрибутов для произвольного сочетания claims — та ещё задача.

У меня проверка конкретного claim одна же. Я писал выше. Будет что-то
Json getInvoiceForRest(..., securityContext, ...) {
  verifyPrivilegesForTheInvoice(..., securityContext, ...);//тут мы проверяем привилегии для данного инвойса
  return new Invoice {
    date: getInvoiceDate(...)
    contragent: getContragentDetails(..., securityContext, ...)// вот внутри этого метода и проверятся имеющиеся привилегии и вернутся только доступные данные конртагента.
    shipping: getShippingDetails(..., securityContext, ...)// вот внутри этого метода и проверятся имеющиеся привилегии и вернутся только доступные данные о доставке.
  }
}

Конечно, это не отменяет "Правила роутинга" и другие подобные подходы, а дополняет. Как тут Miroff швейцарский сыр упоминал.

S>·>С чего ты взял? Никогда не было. А вот у тебя иллюзия в полный рост, цитирую: "чтобы границы безопасности совпадали с границами ресурсов. Потому что это и надёжнее,", "Зато всё безопасно". Нет, конечно. Надёжность тут не причём. Так просто удобнее и понятнее для человеков: не видно, что не должно быть видно. Т.е. чисто иллюзорные результаты.

S>Это оттого, что я плохо объясняю. Разница в подходах есть. Понятно, что достичь приемлемого результата можно в любом подходе, но стоимость получается разной. Когда границы безопасности совпадают с границами ресурсов, это сильно упрощает доказательство корректности. Я выше примерно написал, каким именно способом. Но вы можете мне не верить и писать более дорогостоящие и трудноподдерживаемые системы — у нас же нет архитектурной полиции
Ну я просто написал когда этот твой способ не работает. Но я, конечно, верю, что в некоторых случаях и твой способ работает. Но это не значит, что он универсальный всемогутер.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[26]: Каких программ вам не хватает?
От: Sinclair Россия https://github.com/evilguest/
Дата: 12.04.25 06:20
Оценка:
Здравствуйте, ·, Вы писали:

·>Где есть два вида? В спеке?

Да, прямо в спеке.

·>Как конкретно это гарантируется? Только не говори: "в API нету!". Не слыхал историй, когда какие-нибудь rest-endpoints случайно возвращали json с неожиданными полями. All tests passed, всё у всех работает.

Я вроде написал, как. Историй про то, как all tests passed, а результат не соответствует — нет, не слышал.
Но вы отклоняетесь: если у вас такие кривые тесты, которые пропускают наличие лишних полей, то в системе с "привилегией на атрибуты" у вас тем более будет бардак.

S>>Потому что я так спроектировал, и это легко проверить как методом "белого ящика", так и "чёрного ящика".

·>Ну о чём и говорю. "Спроектировал" — это написал тонну word-документов и презентаций.
Нет конечно. "Спроектировал" — это построил фреймворк, в котором не так много возможностей накосячить. Архитектура софта не исчерпывается "внешними" требованиями.

·>И проверить легко, не спорю. А на самом деле json генерится питонячим кодом, который рефлексией вываливает всё что есть.

Вот это ваше "На самом деле" означает, что вы пытаетесь тестировать код как чёрный ящик. Это не единственный (и не самый эффективный) способ обеспечения качества.
Надо смотреть внутрь, и желающих генерить всё что есть через рефлексию бить палкой на code review.
·>Может такое только в каких-то мелких проектах и пройдёт...
Вот то, что вы предлагаете, как раз и проходит только в мелких проектах. В крупных проектах требуется более строгий контроль, чем "я проверил всю динамику глазами и всё сошлось".
·>И то никакой гарантии, что кто-то куда-то по ошибке не скопипастит.
Гарантия предотвращения ошибочных копипастов достигается юнит-тестированием. Преимущество тут в том, что в коде нет ветвлений — поэтому нам не надо беспокоиться, что "вдруг" в результате образуется сontragent: {homeAddress: {...}}. Достаточно 1 (одного) теста на то, что такого в json нету, и вопрос закрыт.
·>В серьёзных случаях у тебя будет 1024 вида своих и чужих.
Это как раз в несерьёзных случаях. Серьёзные случаи — это как раз какой-нибудь банковский API. И вот там всё именно так, как я сказал. Потому что нельзя позволить ни криворукому девелоперу нечаянно проверить не ту привилегию, так и криворукому админу нечаянно выдать кому-то не ту привилегию.

·>Надо технически смотреть, а не по поверпоинт презентациям. БД — компонент, если embedded, в лучшем случае. А так по сути другой сервис — формируешь запрос (query) и получаешь ответ (recordset). Ничем по факту от какого-нибудь rest не отличается, только протокол общения другой, вместо http у тебя sql.

Верно мыслите, так всё и есть.

·>Что значит "вынести"? Попробуй хоть как-нибудь не "вынести" какой-нибудь оракл из твоего питоячего сервиса.

Ну вот так и не выносим. Оракл является подробностью реализации этого "питонячьего сервиса" и ниоткуда больше не виден. Впрочем, это может быть и не оракл — "питонячьему сервису" с запасом может хватить sqlite.

·>Я как-то более о практике.

Это я о практике, а вы рассказываете какие-то сказки. Ну, точнее вы предлагаете заведомо неудачные решения, через которые мы проходили по нескольку раз начиная ещё с девяностых.
·>Статический анализ, конечно, хорошо... Но если тебе для этого придётся описывать "1024 виртуальных ресурсов" и писать 2048 тестов для них, но это не заработает на практике, хотя в теории, конечно, красота...
Не придётся. Я уже писал причины.
·>Если у тебя два сценария, то, конечно, это щастье. А вот когда сценариев 1024...
Когда у вас 1024 сценария, то деваться некуда. Но чаще это означает, что кто-то не справился с факторизацией сценария, в котором есть 8 отдельных подсценариев, каждый из которых работает независимо и его можно протестировать отдельно, т.к. там вариантов гораздо меньше.

·>Ну будет у тебя 1024 кусков кода и неподдерживаемая кодовая база.

И какая альтернатива?

·>У меня проверка конкретного claim одна же. Я писал выше. Будет что-то

·>
·>Json getInvoiceForRest(..., securityContext, ...) {
·>  verifyPrivilegesForTheInvoice(..., securityContext, ...);//тут мы проверяем привилегии для данного инвойса
·>  return new Invoice {
·>    date: getInvoiceDate(...)
·>    contragent: getContragentDetails(..., securityContext, ...)// вот внутри этого метода и проверятся имеющиеся привилегии и вернутся только доступные данные конртагента.
·>    shipping: getShippingDetails(..., securityContext, ...)// вот внутри этого метода и проверятся имеющиеся привилегии и вернутся только доступные данные о доставке.
·>  }
·>}
·>

Прекрасно. Видна некоторая попытка факторизации. Которая, к слову, совершенно бесполезна в вашем подходе с чёрным ящиком: а вдруг завтра кто-то заменит всю вашу кунсткамеру на "питонячий код, который по рефлексии вываливает сразу всё"?
Ну, и вредна конечно тоже: потому что завтра кто-то в эксплуатации не нарулит кому-то такой набор привилегий, который не даёт выполнить реальный сценарий. Зачем так делать — непонятно. Ну, кроме "нам было лень проектировать, и мы свалили ответственность на кого-то другого.

·>Ну я просто написал когда этот твой способ не работает. Но я, конечно, верю, что в некоторых случаях и твой способ работает. Но это не значит, что он универсальный всемогутер.

Скорее наоборот: бывают задачи с низкой ответственностью, где можно игнорировать best practices и писать с надеждой на авось.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Отредактировано 13.04.2025 2:39 Sinclair . Предыдущая версия .
Re[27]: Каких программ вам не хватает?
От: · Великобритания  
Дата: 14.04.25 10:43
Оценка: :)
Здравствуйте, Sinclair, Вы писали:

S>·>Где есть два вида? В спеке?

S>Да, прямо в спеке.
Именно. А толку? Никакой безопасности это само по себе не обеспечит. В проде у тебя работает код, а не спека. Cпека ничего не может гарантировать о реализации.

S>·>Как конкретно это гарантируется? Только не говори: "в API нету!". Не слыхал историй, когда какие-нибудь rest-endpoints случайно возвращали json с неожиданными полями. All tests passed, всё у всех работает.

S>Я вроде написал, как. Историй про то, как all tests passed, а результат не соответствует — нет, не слышал.
Ну лень гуглить, но периодически выскакивают истории типа как из сайтов авиакомпаний и продаж билетов выковыривают инфу о том кто куда летает и где живёт.

S>Но вы отклоняетесь: если у вас такие кривые тесты, которые пропускают наличие лишних полей, то в системе с "привилегией на атрибуты" у вас тем более будет бардак.

Очередная иллюзия у тебя. Даже если в тесте не выдаётся лишних полей, это не значит что они не выдаются.

S>·>Ну о чём и говорю. "Спроектировал" — это написал тонну word-документов и презентаций.

S>Нет конечно. "Спроектировал" — это построил фреймворк, в котором не так много возможностей накосячить. Архитектура софта не исчерпывается "внешними" требованиями.
Гы. Очередной фреймворк-всемогутер.

S>·>И проверить легко, не спорю. А на самом деле json генерится питонячим кодом, который рефлексией вываливает всё что есть.

S>Вот это ваше "На самом деле" означает, что вы пытаетесь тестировать код как чёрный ящик. Это не единственный (и не самый эффективный) способ обеспечения качества.
S>Надо смотреть внутрь, и желающих генерить всё что есть через рефлексию бить палкой на code review.
Именно. Т.е. твой "правильный API" — это каша из топора. Начал ты "нарисуем границы API — и всё безопасно", а оказывается ещё надо досыпать тестирование, ящики разных цветов, палки и review.

Ещё раз повторю мой тезис: дизайн API — это в первую очередь про то как обеспечить взаимодействие систем удобным для человеков и эффективным для железяк способом. Поэтому твой 3й способ с ссылками никуда не годится, только снижает эффективность взаимодейсвтвия, а твоё "Зато всё безопасно" — чистая иллюзия.

S>·>И то никакой гарантии, что кто-то куда-то по ошибке не скопипастит.

S>Гарантия предотвращения ошибочных копипастов достигается юнит-тестированием.
Хорошо, но уже лучше. Осталось раскрыть а причём тут вообще "API устроен именно так".

S>Преимущество тут в том, что в коде нет ветвлений — поэтому нам не надо беспокоиться, что "вдруг" в результате образуется сontragent: {homeAddress: {...}}. Достаточно 1 (одного) теста на то, что такого в json нету, и вопрос закрыт.

Тут ведь как. Либо где-то будут ветвления, либо 1024 копипасты, в которой хрен разберёшься.

S>·>В серьёзных случаях у тебя будет 1024 вида своих и чужих.

S>Это как раз в несерьёзных случаях. Серьёзные случаи — это как раз какой-нибудь банковский API. И вот там всё именно так, как я сказал. Потому что нельзя позволить ни криворукому девелоперу нечаянно проверить не ту привилегию, так и криворукому админу нечаянно выдать кому-то не ту привилегию.
Я как раз такое и видел в банковском API. Когда есть какие-то таблицы роутингов и пермишеннов. Настолько огромные, что их никто толком проверить не может. В итоге эти таблицы либо копипастятся на авось, либо генерятся скриптами, с ветвлениями. Зато статичное и проверяемое (правда в теории только).

S>·>Что значит "вынести"? Попробуй хоть как-нибудь не "вынести" какой-нибудь оракл из твоего питоячего сервиса.

S>Ну вот так и не выносим. Оракл является подробностью реализации этого "питонячьего сервиса" и ниоткуда больше не виден. Впрочем, это может быть и не оракл — "питонячьему сервису" с запасом может хватить sqlite.
Он виден с т.з. анализа безопасности.

S>·>Если у тебя два сценария, то, конечно, это щастье. А вот когда сценариев 1024...

S>Когда у вас 1024 сценария, то деваться некуда. Но чаще это означает, что кто-то не справился с факторизацией сценария, в котором есть 8 отдельных подсценариев, каждый из которых работает независимо и его можно протестировать отдельно, т.к. там вариантов гораздо меньше.
Ты почему-то с больной головы на здоровую стал перекладывать. 1024 виртуальных ресурса предложил ты, так что 1024 сценария это у вас. А я как раз писал: "Каждую комбинацию тестировать не нужно. Нужно тестировать каждую привелегию." С чем ты тут же стал спорить. Ты уж определись.

S>·>Ну будет у тебя 1024 кусков кода и неподдерживаемая кодовая база.

S>И какая альтернатива?
Написал же неделю назад: "Каждую комбинацию тестировать не нужно".

S>Прекрасно. Видна некоторая попытка факторизации. Которая, к слову, совершенно бесполезна в вашем подходе с чёрным ящиком: а вдруг завтра кто-то заменит всю вашу кунсткамеру на "питонячий код, который по рефлексии вываливает сразу всё"?

Про тестирование чёрного ящика ты придумал сам, сам и спорь.

S>Ну, и вредна конечно тоже: потому что завтра кто-то в эксплуатации не нарулит кому-то такой набор привилегий, который не даёт выполнить реальный сценарий. Зачем так делать — непонятно. Ну, кроме "нам было лень проектировать, и мы свалили ответственность на кого-то другого.

Не очень понял проблему. Если реальный сценарий не ложится на привилегии — это ошбика бизнес-требований.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[4]: Помогите правильно спроектировать микросервисное приложение
От: busk  
Дата: 16.04.25 06:30
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Можем посмотреть на пример:


S>Сервис номер 2 расположен по адресу https://graph.microsoft.com/{version}/{resource}?{query-parameters}.

S>Токены для него получаем из сервиса номер 1 по адресу https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize

S>Наличие в сервисе 1 авторизации означает, что у вас сервис номер один возвращает в токене не просто идентити пользователя, а и некий набор привилегий, которые сервис номер 2 считывает для принятия решения о том, чего пользователю делать можно, а чего — нельзя. В частности, для Microsoft Graph мы прямо в запросе авторизационного токена сервису логина указываем список scopes, к которым хотим получить доступ. И в случае успеха, токен будет содержать информацию об этом.


а вот у меня получается 2 бэкенд сервиса, а на фронте тоже 2 реакт приложения, или на фронте одним можно разрулить?
Re[5]: Помогите правильно спроектировать микросервисное приложение
От: busk  
Дата: 16.04.25 07:11
Оценка:
Здравствуйте, busk, Вы писали:


S>>Наличие в сервисе 1 авторизации означает, что у вас сервис номер один возвращает в токене не просто идентити пользователя, а и некий набор привилегий, которые сервис номер 2 считывает для принятия решения о том, чего пользователю делать можно, а чего — нельзя. В частности, для Microsoft Graph мы прямо в запросе авторизационного токена сервису логина указываем список scopes, к которым хотим получить доступ. И в случае успеха, токен будет содержать информацию об этом.


B>а вот у меня получается 2 бэкенд сервиса, а на фронте тоже 2 реакт приложения, или на фронте одним можно разрулить?


вопрос еще связан с тем, что у меня SPA а если будет 2 фронт приложения то тут же получается будет обновление страницы после страницы логина на основное приложение
Re[6]: Помогите правильно спроектировать микросервисное приложение
От: Qulac Россия  
Дата: 16.04.25 07:26
Оценка:
Здравствуйте, busk, Вы писали:

B>Здравствуйте, busk, Вы писали:



S>>>Наличие в сервисе 1 авторизации означает, что у вас сервис номер один возвращает в токене не просто идентити пользователя, а и некий набор привилегий, которые сервис номер 2 считывает для принятия решения о том, чего пользователю делать можно, а чего — нельзя. В частности, для Microsoft Graph мы прямо в запросе авторизационного токена сервису логина указываем список scopes, к которым хотим получить доступ. И в случае успеха, токен будет содержать информацию об этом.


B>>а вот у меня получается 2 бэкенд сервиса, а на фронте тоже 2 реакт приложения, или на фронте одним можно разрулить?


B>вопрос еще связан с тем, что у меня SPA а если будет 2 фронт приложения то тут же получается будет обновление страницы после страницы логина на основное приложение


А зачем так делать? Фронт можно один оставить, просто сервис на беке будет сам вызывать сервис авторизации когда это надо.
Программа – это мысли спрессованные в код
Re[7]: Помогите правильно спроектировать микросервисное приложение
От: busk  
Дата: 16.04.25 11:39
Оценка:
Здравствуйте, Qulac, Вы писали:



B>>>а вот у меня получается 2 бэкенд сервиса, а на фронте тоже 2 реакт приложения, или на фронте одним можно разрулить?


B>>вопрос еще связан с тем, что у меня SPA а если будет 2 фронт приложения то тут же получается будет обновление страницы после страницы логина на основное приложение


Q>А зачем так делать? Фронт можно один оставить, просто сервис на беке будет сам вызывать сервис авторизации когда это надо.


а я думал что фронт тоже распиливают на отдельные сервисы, но подумал, что для SPA не получится тогда сделать без третьего агрегирующего фронт сервиса.
Тогда одно на фронте, понял