the presentation describes a lot of very technical details about row level security, possibble security breaches in relational databases like Oracle and Postgres. A lot of examples how to protect data is shown.
4. RLS
1. Enable row-level access control
2. Simplify application development
3. Centralize security management
5. Security requirements
We need new security now!
Initial requirements
1. Users should see only own data
One year after development started:
1. GDPR audit
2. SOX audit
3. 5 severe security violations = 20 new rules
6. Security requirements
1. Minimal application changes
2. Low impact to performance
3. Centralized security management
4. All applications should be affected
5. Implementation should be fast
=
Oracle Virtual Private Database
RLS in DBMS
8. Application server
1. Modify queries to DB
+ performance, agile
- hand-made
2. Filter fetched data
+ supported by frameworks
- extra app/db server traffic, complicated search, paging, etc
9. DB server
1. Security views
+ performance
- issues with DML
2. Stored procedures API
+ performance
- out of fashion
3. Embedded row level security
+ full of myths
- full of myths
11. RLS location
1. Application server
+ high level language
- access via application server only
2. Database server
+ performance, close to data
- too much myths
3. Mixture
+ very scalable
- complicated implementation
12. DBMS RLS myths
1. Bad performance
2. Complicated implementation
3. Easy to hack
4. No interaction with UI
5. Exists in old database engines only
6. Only for 2-tier applications
14. Access types
1. User observes own records only
2. Users observes records shared with him by others user
3. User observes records for given permitted customer list
.
.
.
20. User observes records for given permitted record type list
15. Security source
Customer
Security DB
Microsoft
Active Directory
Oracle
main
Oracle
DG
Application
server
Application
server
Load
balancer
Client
browser
InMemory
cluster
Application
server
GCC
Apache
Solr
CRM
300 roles per user300 000 permissions
mappings
16. VPD glossary
• Context – key-value pair storage
• Security object – object controlled by VPD
• Security predicate – SQL string appended to query
• Policy function – PL/SQL populating predicate
• Policy – metadata which glues all together
26. ACL policy
1. Based on AD groups only
2. AD groups store permission mappings
3. Mostly IN or EXISTS/NOT EXISTS predicates
division_type_code in (‘BRANCH’, ‘DEPO’, ‘ARCH’)
Not exists (
select 1
from restricted_user_measures m
where m.measure_id = customer.measure_id
)
31. DBMS RLS myths
1. Bad performance
2. Complicated implementation
3. Easy to hack
4. No interaction with UI
5. Exists in old database engines only
6. Only for 2-tier applications
37. External systems interaction pain
1. Customer security DB – DB links are prohibited
Solution: dedicated ETL job – 5 minute delay
2. Active Directory – no access from Oracle
Solution: pass all user roles to context from Java
42. DBMS RLS myths
1. Bad performance
2. Complicated implementation
3. Easy to hack
4. No interaction with UI
5. Exists in old database engines only
6. Only for 2-tier applications
43. Performance degradation
1. Query plans hard parse – 3x more
2. Get connection from pool – 3x more
3. Query execution time – up to 2x more
4. Context switches – up to 2x more
44. Plan to fix
1. Get connect from pool
2. Securities predicates
3. Hard parse
4. Wild execution plans
5. Cache
6. Denormalization
45. Get connection pain
1. Java – get AD roles
2. Java – filter security roles
3. Java – send to Oracle as input parameter:
- AD user name
- AD roles list
4. Oracle – VPD predicates magic
80%
0.4 sec
47. Connection pain solution
1. Do not pass AD roles from Java side
2. Connect to AD from Oracle DBMS
3. Use DBMS_LDAP package
0.4 seconds => 0.08 seconds!
50. Policy types
1. Dynamic
Predicate is produced each call
2. Static
Predicate produced once
3. Context-sensitive
Predicate produced if security context is changed
51. Policy types
1. Static
when predicate string is constant
ad_user = sys_context(‘security_ctx’, ‘ad_user’)
2. Context-sensitive
when predicate string is built from context
environment_code in (‘SANDBOX’, ‘PROD’, ‘HOME’)
Taken from context
59. Bad ACL query plans resolution
Dreams
1. Use InMemory structures – plsql collections
2. Fast
3. No disk I/O
Reality
1. PL/SQL context switches – low performance
2. No options for cardinality estimate – bad plans
3. Very hard to debug
90. Securities predicates
LIKE = FULL scan mostly!
Denormalization not very efficient in Oracle!
1. Ingestion degradation up to 10%
2. Additional maintenance
3. Sudden deterioration
92. Caching parameters
N Code Current
value
Purpose
1 VPD_CACHE N Should be invoke vpd.connect if user hasn’t changed
2 ACL_CACHE N Do we need call Active Directory
3 AD_CACHE Y Cache access control list population
4 AD_EXPIRING 300 Lifetime in seconds
5 VPD_EXPIRING 600 Lifetime in seconds
6 ACL_EXPIRING 120 Lifetime in seconds
Was changed ~8 times in Production!
94. Final performance metrics
1. Query plans hard parse – 10%
2. Get connection from pool – 5%
3. Query execution time – up to 20%
4. Context switches – eliminated
95. DBMS RLS myths
1. Bad performance
2. Complicated implementation
3. Easy to hack
4. No interaction with UI
5. Exists in old database engines only
6. Only for 2-tier applications
96. RLS side channel attacks
1. Security predicates/caches/context sniffing
Identify data by security filters content
2. Fake user name calls
Direct connect to DB via superuser as an application user
3. Hand-crafted queries
Tricky queries based on a particular DB issues
4. Dump analysis
- SGA
- Library cache
- Data files
97. Security predicate sniffing
Events
1. 10053 – Cost Based Optimizer decisions
2. 10730 – VPD predicates
3. 10060 – All Predicates
4. 43905 – Result Cache
98. Security predicate sniffing mitigation
1. Close an access to VPD-related views:
- V$VPD_POLICY
- %_POLICIES
- %_POLICY_ATTRIBUTES
- %_POLICY_CONTEXTS
- %_POLICY_GROUPS
2. Close an access to DB trace files
3. Use context – not direct values
4. Use session level temporary tables for cache
99. Fake user name attack
1. Connect to DB directly
2. Process as though application:
121. DBMS RLS myths
1. Bad performance
2. Complicated implementation
3. Easy to hack
4. No interaction with UI
5. Exists in old database engines only
6. Only for 2-tier applications
128. RLS in Postgres ACL
Very efficient in Postgres!
Overall performance – 15% degradation
129. DBMS RLS myths
1. Bad performance
2. Complicated implementation
3. Easy to hack
4. No interaction with UI
5. Exists in old database engines only
6. Only for 2-tier applications
130. DBMS RLS pros
1. Works automagicaly
2. Tiny client code modification
3. Security rules are equal for all clients
4. No options to bypass common security hacks
5. Security management centralization
6. Works on Oracle Standby database
131. DBMS RLS cons
1. Works automagicaly
2. Sophisticated debug
3. Complicated interaction with external
systems
4. SQL knowledge required
5. Interaction with UI impossible
6. Copy-paste if there are many databases
132. DBMS RLS myths
1. Bad Unpredictable performance
2. Complicated implementation debug
3. Easy A lot of efforts to hack
4. No interaction with UI
5. Exists in old database engines only
6. Only for 2-tier applications
133. When use DBMS RLS
1. Fast tech debt resolution
2. Different applications use direct DB connection
3. Newly implemented applications
4. SOX, GDPR, ISO/IEC 27001/27002,
FedRAMP/FISMA, SOC, HIPAA и PCI DSS
compliance requirements
134. When not to use DBMS RLS
1. Applications uses application server only
2. Sophisticated microservices architecture
3. Very old applications
4. High-loaded OLTP applications
135. Lessons learned
1. Plan security in advance
2. Use data-driven caching
3. Denormalize data
4. Invent simple policies
5. Care about hackers
6. RLS in DBMS works fine
7. Even in Postgres
136. THANK YOU
WE ARE HIRING!
Alexander Tokarev
Database expert
DataArt
atokarev@dataart.com
https://github.com/shtock
RuOUG
Editor's Notes
Всем привет. Меня зовут Александр и я занимаюсь в компании DataArt вопросами, связанными с производительностью баз данных и архитектурой приложений.
Сегодня мы обсудим такую вещь, как смысл наличия безопасности на уровне строк, подходы к её реализации в целом и как решали мы данную задачу в одном из наших проектов. Я попытаюсь рассказать какие уроки из всего этого мы вынесли и с удовольствием отвечу на ваши вопросы.
На самом деле это всё детали.
Безопасность на уровне строк, да ровно как и все задачи, связанные с безопасностью, окутаны плеядой разнообразных мифов и именно их разрушению или подтверждению будет посвящён наш разговор. Ну и конечно же я надеюсь вы узнаете всех мифических персонажей, которые нам попадутся.
Перед тем, как мы начнём рассматривать мифы давайте очень кратко вспомним, зачем же нужна безопасность на уровне строк и где её реализуют. В целом всё очевидно из названия.
Rls нужна, чтобы фильтровать данные по строкам на основе идентификатора пользователя, его ролей или контекста выполнения
Её наличие упрощает разработку приложения
За счёт централизации логики безопасности
Вопрос в зал у кого политики сложнее, чем показывать клиенту только свои данные
Но самое страшное, что все требования к безопасности появились через год после начала разработки
Объяснить какие – это важный момент по замечаниям
Gdpr + sox
Так как времени на реализацию Security было мало был, а список пожеланий был весьма большой и противоречивый, а ещё и разработчики среднего слоя настойчиво не хотели менять DAO, то единственным выходом была концентрация логики Security в базе данных через встроенную row level security, так как использование security view привело бы к изменению DAO.
Фильтрация строк очевидно может быть реализована на
Сервере приложений
Сервере баз данных
И всегда остаётся место для смешанных вариантов
Собственно тут 2 основных подхода:
Все запросы к серверу БД на уровне DAO содержат в себе все необходимые предикаты безопасности и Применение фильтрации к уже загруженным данным
Достоинства и недостатки обоих методов весьма очевидны.
Когда вручную создаются запросы очевидно их скорость весьма высока, можно делать что угодно, но ручное их написание может привести к ошибкам. Самые частые – в каком-то из классов DAO предикаты забываются.
Я имею ввиду антотации Filter и where в Hibernate
Для фильтрации тоже все понятно. Оно уже реализовано весьма богато во многих фреймворках, таких как Spring Security или Jango guardian, но приводит к росту трафика между серверами, усложняет и замедляет задачи поиска, пейджинга и прочего
Тут идёт разговор о PredFilter и PostFilter в Spring Security или о Spring ACL
Существует множество вариантов реализации безопасности на стороне сервера баз данных.
Самый простой и очевидный это в представлениях, куда мы помещаем все наши security предикаты.
Далее мы можем создать api из хранимых процедур
И, наконец, использовать встроенные в базу данных средства row level security
Опять таки, + и – ясны.
Представления очень быстрые и гибкие, но становится тяжелее делать DAO, ибо прямые операции вставки и изменения данных уже не проходят или надо делать instead of триггеры, что совсем уж грустно
Хранимые процедуры быстры, но уже не модны
Что касается встроенной безопасности на уровне базы данных то тут полный простор для мифов как в части плюсов, так и в части минусов
Тут можно придумывать множество комбинаций, но самым распространённым является шардирование по клиентам, но само собой бывают более сложные политики, чем разделение доступа по одному клиенту.
Исходя из плюсов и минусов каждого варианта вытекают плюсы и минусы каждого решения
Вопрос к аудитории про сложность security
Лучше всего рассматривать мифы на примере конкретной архитектуры. Собственно рассмотрим архитектуру нашего приложения. Как вы видите типичная архитектура трёхзвенного enterprise-приложения за исключением того, что ряд серверов в AWS.
Ключевая печаль в том, что по ряду причин CRM система, системы получения отчётности и система виртуализации данных ходят прямыми запросами в базу данных и поменять это невозможно, а требования безопасности должны быть едины для всех.
Важно заметить, что хранимая логика в базе данных запрещена.
Рассмотрим какие у нас есть вариации для row level security
Всё начинается с простейшего Пользователь видит только свои записи, и то там не всё так просто, но я не могу раскрывать детали. Также другие пользователи могут шарить записи с другими пользователями, для некоторых типов объектов определён список пользователей, с которыми они могут работать, а для некоторых пользователей определены только определённые типы объектов. Сейчас в системе около 20-ти типов правил row level security.
Всё бы было ничего, но проблема в том, что ещё и не вся информация для формирования предикатов безопасности лежит у нас в системе. Так, например, информация по разрешённым покупателям находится в отдельной БД, а маппинги между покупателями и нашими пользователями присваиваются через набор групп в Active Directory. Причём, что важно одна запись из ActiveDirectory может соответствовать набору записей из БД покупателей.
Вопрос к аудитории про сложность security
Нарисовать 3 этапа
Определение что секурити
Формирование предиката
реврайт
Чтобы объяснить как это работает проще показать, я расскажу какие политики у нас есть в проекте и попытаемся создать одну из них
Итак, давайте создадим простейшую политику, практически аналогичную используемой у нас
Юзер бд – тут создаём предикат
Юзер бд – тут создаём предикат
Юзер бд – тут создаём политику
Тут простой селект и показ во что он превратился. Сам для себя глянуть в v$sqlplan + вьюху + залогиниться под другим юзером и др кол-во
Обратить внимание, что всё пусто
Тут простой селект и показ во что он превратился. Сам для себя глянуть в v$sqlplan + вьюху + залогиниться под другим юзером и др кол-во
Тут простой селект и показ во что он превратился. Сам для себя глянуть в v$sqlplan + вьюху + залогиниться под другим юзером и др кол-во
Тут простой селект и показ во что он превратился. Сам для себя глянуть в v$sqlplan + вьюху + залогиниться под другим юзером и др кол-во
Мы не будем рассматривать сами функции, но если кратко, то ACL политики это политики по access control list, который формируется либо из набора групп AD либо на основе маппингов AD групп и других систем.
Собственно IN или EXISTS выбираются на основе объёма списка для ограничений данных. Малый – IN. Большой – exists.
Ключевая боль, что тут пользователь БД, а все приложения ходят под connection pool. Что же делать? В контексте USERENV есть один атрибут, который создан специально для таких целей и может быть единственный изменён извне. Т.е. мы берём session_user и заменяем его на
Ключевая боль, что тут пользователь БД, а все приложения ходят под connection pool. Что же делать? В контексте USERENV есть один атрибут, который создан специально для таких целей и может быть единственный изменён извне. Т.е. мы берём session_user и заменяем его на
Таким образом, каждое приложение при получении соединения из connection pool вызывает простую команду указывая имя именно application user, а не пользователя базы данных. Таким образом проблема 3-х звенных приложений прекрасно решается. Собственно у нас имя AD пользователя проходит через соответствующие http header, проваливается на jboss и на каждом получении коннекта мы вызываем установку идентификатора.
Таким образом, каждое приложение при получении соединения из connection pool вызывает простую команду указывая имя именно application user, а не пользователя базы данных. Таким образом проблема 3-х звенных приложений прекрасно решается. Собственно у нас имя AD пользователя проходит через соответствующие http header, проваливается на jboss и на каждом получении коннекта мы вызываем установку идентификатора.
Вопрос к аудитории про сложность security
После того, как всё это завели начались проблемы
Девелоперы не видят данные, dba не видят данные (это же не постгресс, где есть роль суперюзер, в которой обходятся все security вещи), только из приложения что-то видно. В общем, наступила полная медитация.
Как мы помним нашу старую policy function в ней мы данные помещаем под защиту всегда
По новому концепту мы внедряем на уровне continuous integration переменную, которая при деплое резолвится нужным образом
Либо в 1 = 1 для продакшна и все данные под защитой всегда, т.е. если контекст не взведён, то данных и не увидят
Либо для дева проверяется, установлен ли контекст и фильтруются, только если он есть, т.е. запущено приложение
Как я уже сказал, одна из проблем, что данные для безопасности лежат в других системах. Часть в сторонней бд, в которую нельзя ходить напрямую, а часть в active directory. Соответственно для внешней бд etl разработчики сделали соответствующую процедуру загрузки, а для AD решили передавать список ролей из джавы прямо в контекст.
Отлаживать можно через план выполнения, view со списком предикатов, но есть одна проблема. Это работает только тогда, когда в политике нет ошибок.
Если мы внесём какую-либо опечатку в политику, то
Мы не получим ни плана выполнения, ни информации во вью, а все запросы начнут отваливаться с ошибками
как мы обнаружили, единственный выход это найти соответствующий трейс-файл, который оказывается в случае таких ошибок создаётся автоматически и разбираться в нём
Вопрос к аудитории про сложность security
Как и следовало ожидать, когда делаешь всё по мануалу, отваливается производительность
Увеличилось количество генерации планов, время получения коннекта из пула, да и сами запросы изрядно просели по скорости
Мы определили план действий по решению проблем
Как устроено получение коннекта из пула
Вначале ява получает список ролей, потом фильтрует и отправляет в оракл имя ad пользователя и список ролей.
Далее работают уже знакомые нам процедуры по инициализации контекста. Обнаружилось, что 80% уходило именно на передачу параметра
А так как у пользователя под 300 AD ролей в целом это походило на правду
В итоге было принято внезапное, но работающее решение – получать AD роли прямо в базе данных и это помогло нам в 4 раза сократить время
Вы помните как работает row level security? Так вот один из этих этапов вполне может быть объектом кэширования, хотя это всё находится в ядре. Причём этот этап вносит весьма высокий вклад в падение производительности.
Этап формирования предикатов может быть частично исключён, а они переключены на кэш политик
Есть 3 типа политик. Динамические, которые пересоздаются каждый раз, ститические, которые создаются разово и контекст-зависимые, которые инвалидируются, если контекст меняется
Соответственно 2 и 3 типы помещаются в кэш
Соответственно статика применяется, если строка предиката константа, хотя значения в контексте меняются.
Динамические когда сами строки строятся из контекста
В целом настройки для политик устанавливаются очень просто. Мы просто указываем, что политика должна быть static, как например для политики фильтрации по имени пользователя. Итого исключив ненужные создания предикатов мы получили прирост скорости около 10%.
В целом настройки для политик устанавливаются очень просто. Мы просто указываем, что политика должна быть static, как например для политики фильтрации по имени пользователя. Итого исключив ненужные создания предикатов мы получили прирост скорости около 10%.
Производительность улучшилась, но количество hard parse не уменьшалось и это видно по плану выполнения запроса. На каждое имя пользователя свой план или дополнительные затраты на технологию adaptive cursor sharing.
Решение это проблемы очень простое – не надо собирать предикат через конкатенацию
А надо использовать непосредственно значение из контекста
Таким образом для любых значений у нас одинаковый план и часть hard parse ушла
Как вы думаете вообще с чего надо начать боль с плохими планами?
Правильно, надо добавить индексы.
Не забыть упомянуть отдельно про боль с хардпарсами и inmemory
Эта странная на первый взгляд конструкция позволяет выбирать данные из InMemory кэшей как из обычных таблиц
Решение очень простое – убрать красоту и использовать session level temprorary table
Что в оракле 12.2 уже в inmemory по дефолту
Всё было бы хорошо, но как всегда начали плакаться наши DBA.
Как вы думаете – о чём
Примерно каждое формирование ACL выглядит так
Как мы это решили?
Правильно, темпорари андо
Как мы это решили? Undo мигрировало во временное пространство. В общем то dba счастливы,
Очень интересно VPD ведёт себя с result cache, который как вы помните по моим прошлым презентациям мы любим и умеем готовить. Итак, давайте вспомним, что у нас есть.
Давайте отфильтруем данные по пользователю PERSO
Как мы видим сформировался код результата
Про sql что пашет и картинку с планом и разным юзером
Выберем данные для пользователя Петров, по которому данных нет
И о чудо – наблюдаем такую же картину как и при вызове без пользователя, т.е. резалт кэш как-то учитывает впд.
Вернёмся теперь к начальному состоянию и посмотрим не происходит ли какой-либо хаос
Всё по нулям – резалт кэш работает
За счёт чего же это происходит
Глянем в ядро
Мы увидим два одинаковых запроса, но с разными кэш айди.
Требуется рыть глубже!
Оттрассируем сессию с событием дебага резалт кэша и увидим, что в формирование кэша входит отдельно впд предикат, что и даёт разные айди кэшей, поэтому всё замечательно и работает
Посмотрим теперь на пл скул
Создадим функцию резалт кэш, которая возвращает количество записей в нашей таблице
Итак, угадайте сколько у нас будет записей
Ничего не меняется
Почему?
А по документации!
Несмотря на то, что он у меня всегда работает я бы не рисковал с RC и VPD
А теперь предлагаю секцию ответов и вопросов, чтобы вы всё не забыли и перерыв на чай.
Кэш прав
Тут стрелками нарисовать, где2-10 запиисей
Соответственно, эти значения мы не захардкоживаем понятно дело, а собираем на основе полей из security context или ad ролей. И, кстати, как я ранее говорил, это идеальный претендент на то, чтобы стать context depended кандидатом для кэширования
Итого мы сделали наш ACL инлайн, но иногда стали выскакивать уже знакомые ошибки. Если посмотреть на предикаты, то они выглядели обрезано
Мы посмотрели в мануал и решили включить long policy, хотя понимали, что у нас нету 4000 символов.
Как и ожидалось это не помогло.
Как вы думаете, в чём же причина?
Ответ на этот вопрос кроется как по-настоящему выглядит функция для получения предиката. А выглядит она так
Т.е. получаем мы данные из контекста, в котором по-умолчанию не указано сколько символов надо возвращать, а исходная длина – 256.
В чём смысл этого я не знаю. Если кто знает – расскажите. Дима, тут ты можешь ответить первым
Поэтому мы указываем 4000 и радуемся
Но как вы думаете какая боль у этого решения?
Следующая беда, которая нас постигла это инвалидация курсоров по причине роу левел секьюрити
Запомните количество версий курсоров – нам оно ещё пригодится
обратите внимание, что количество предикатов во вью впд полиси совпало с количеством курсоров
В общем то, это известная ситуация, отражённая в соответствующей ноте, что впд политики не меняют sql id, хотя из-за предикатов sql разный, что мы уже подтвердили через вью впд полиси.
Один из вариантов, которые мы так же решили попробовать это денормализовать права. Лучше всего этот случай подходил тогда, когда пользователи позволяют свои документы смотреть другим.
Ключевой вопрос – как делать фильтрацию. Тут есть 2 варианта. Like и contains. Однако первый всегда приводит к фулскану, а второй требует создания полнотекстовых индексов, которые не лучшим образом реализованы в оракле.
Кэш коннектов
Кэш впд
советы
datadriven
кэши
кэши вкл выкл
кэши с настройкой времени
Упомянуть про три политики
Где юзернейм
Где in
Где сложные джоины
Вопрос к аудитории про сложность security
Если честно, я не знаю ещё как мы это будем делать, на стороне БД или всё же на стороне сервера приложений, но мы точно знаем, что Oracle VPD это позволяет
Sga – full sql, LC – static policies, DF – all data
Ну что ж, давайте подводить выводы
Пример открытой времянки таблицы
Предикаты VPD могут быть найдены на основе следующих эвентов трассировки
Вы же не хотите, чтобы пользователь увидел, какие таблицы у него фильтруются
Если честно, я не знаю ещё как мы это будем делать, на стороне БД или всё же на стороне сервера приложений, но мы точно знаем, что Oracle VPD это позволяет
Ну что ж, давайте подводить выводы
Один и тот же хэщ – спросить в чём риск
Хранение хэша
Можно добыть хэш
Один и тот же хэщ – спросить в чём риск
Хранение хэша
Можно добыть хэш
Один и тот же хэщ – спросить в чём риск
Хранение хэша
Можно добыть хэш
Один и тот же хэщ – спросить в чём риск
Хранение хэша
Можно добыть хэш
И злоумышленник даже не понимает, что данных нет, так как мы не генерим исключение, а просто имитируем пустой логин
Один и тот же хэщ – спросить в чём риск
Хранение хэша
Можно добыть хэш
Если честно, я не знаю ещё как мы это будем делать, на стороне БД или всё же на стороне сервера приложений, но мы точно знаем, что Oracle VPD это позволяет
Ну что ж, давайте подводить выводы
Дата за вчера с украденным хэшем
В данном варианте мы убеждаемся, что текущая дата сервера находится в диапазоне даты, пришедшей как входной параметр плюс время, в течении которого она может существовать. Таким образом, если злоумышленник похитил срочку с вызовом, у него есть только 1 секунда, чтобы ей воспользоваться.
Если честно, я не знаю ещё как мы это будем делать, на стороне БД или всё же на стороне сервера приложений, но мы точно знаем, что Oracle VPD это позволяет
Ну что ж, давайте подводить выводы
Если честно, я не знаю ещё как мы это будем делать, на стороне БД или всё же на стороне сервера приложений, но мы точно знаем, что Oracle VPD это позволяет
Ну что ж, давайте подводить выводы
С ораклом такие штуки не проходят, потому что там другой механизм работы RLS, но я смог и тут кое-что проделать. Во-первых, можно использовать pl-sql с result cache как мы смотрели ранее или ещё более забавный способ.
Я собрал статистику по таблице
А потом декодировал минимальные и максимальные значения по одной из скрытых колонок и получил их возможный диапазон. Не так много, но в опытных руках этого может быть уже достаточно.
Тем не менее у меня получилось взломать другую часть VPD, которая называется column data masking. Создадим другую политику
Итак, создадим такую же как и политику безопасности политику скрывания. Если security предикат верен, то запись будет показываться, если нет – то не будет. В нашем случае мы будем видеть поля только тогда, когда залогиненный пользователь совпадает с создателем.
Свяжем политику с таблицей и полями, которые должны находиться под защитой и указываем, что не удовлетворяющие контролю строки не должны исчезать.
Свяжем политику с таблицей и полями, которые должны находиться под защитой и указываем, что не удовлетворяющие контролю строки не должны исчезать.
Меняем пользователя на Персо и видим, что его имена показались, а остальное скрылось
А теперь начнём взлом! Используем типовую технику, а именно через возврат данных, которые скрыты.
Плохие новости, не правда ли? Как можно решить эту проблему?
Посмотреть версию и
А теперь начнём взлом! Используем типовую технику, а именно через возврат данных, которые скрыты.
Плохие новости, не правда ли? Как можно решить эту проблему?
Посмотреть версию и
И перейти на другую, где и запустить наш скрипт. Да, сообщение конечно же, меня не радует, ибо мы долго и упорно стараемся скрыть факт наличия безопасности в приложении, а тут о нём нам явно говорят, но других вариантов я для себя не вижу.
Давайте попробуем более сложную атаку, а именно уже известную Iterative inference attack
Вопрос к аудитории про сложность security
Кстати, хотел показать, что в самом дефолтном Оракле VPD используется, но политики завраплены, я, конечно же, смотрел их, но уже забыл о чём они.
Их довольно много в OEBS, но у меня не было под рукой его инсталляции, чтобы вам показать.
В вопросу о Row Level Security работает не только в MsSql, но и в современно Azure SQL Data Warehouse, само собой Постгрес и amazon insight. Наверняка, ещё и в других СУБД, но дальше я не рыл.
Итак, давайте повторим в постгресе ряд политик. Например, политику по имени пользователя.
Включаем факт работы RLS на таблице, потом создаём вполне очевидную таблицу
Самое главное как оказалось включить режим игнорирования факта незаполнения контекста, иначе без него получалась ошибка, которая не позволяла имитировать тут ситуацию, что если контекст не заполнен, то данные показывать не надо.
Установим в контекст имя пользователям ии проверим как всё работает. Всё прекрасно фильтруется и предикат безопасности наблюдается в плане выполнения
Создадим нашу денормализованную таблицу в постгресе, только вместо типа varchar используем более родной для Postgres тип Массив и созданим по полю полнотекстовый индекс
А далее создадим политику, которая проверяет вхождение в данный массив пользователя из контекста.
Проверим работу РЛС с денормализованными данными – в целом всё великолепно
Как мы видим, постгрес весьма разумно использует полнотекстовые индексы и как показал наш опыт они более стабильны в нём, однако в силу более слабого оптимизатора деградация производительности не менее 15%, а в некоторых случаях была и больше.
Ну что ж, давайте подводить выводы
Ну что же
Давайте подводить выводы, которых понятно будет много
Bad performance = unpredictable perforomance – mention pictures from PG, MS and Oracle and put picture Possible
Итак, к чему же мы пришли с мифами?
Плохая производительность трансформируется в непредсказуемую
Сложная реализация сводится к непростой отладке
Да, никакого взаимодействия с UI
Что касается того, что рлс есть в старых СУБД, его легко взломать, да и то, что он применим только для 2-х звенных приложений это конечно же не верно
Для быстрого закрытия техдолга
В случае если к БД ходит напрямую множество приложений
Недавно созданые приложения, в которых можно что-то подфиксить, если они начнут ломаться
Требования соответствия различным законам
Когда не стоит использовать безопасность в базах данных?
Когда доступ гарантировано проходит только через сервер приложений
В сложной микро сервисной архитектуре
Для очень старых приложений, в которых добавление слоя фильтрации на стороне БД поломает приложение
Высоконагруженные OLTP приложения, в которых добавление чего-либо неконтролируемого может сильно изменить время отклика
Наши основные уроки таковы
Думайте о безопасности заранее
Используйте data-driven кэши
Если есть возможность денормализовать права по безопасности, то это не помешает
Упрощайте политики – тут проговорить, что если политика работает на таблице, на которой есть политика, то ничего не взлетит
Не забывайте о взломе
Главное, что row level security прекрасно работает в бд
И даже в Postgres
Всем спасибо за внимание, я готов ответить на ваши вопросы