Выбрать главу

Рис. 3.6. Оператор MATCH

Наша задача – создать правильный шаблон с добавлением условий. Неверно составленный запрос выдаст неверную информацию.

Рассмотрим простой запрос Cypher, где будут выбираться пользователи, у которых есть права локального администратора на компьютеры:

MATCH (u: User)-[r: AdminTo]->(c: Computer) RETURN u,r,c

Здесь переменным u, r и c будут передаваться результаты выборки, это не обязательно, если не нужно выделять какие-то особые условия, но для возврата данных все равно нужно определить переменную. Такой запрос нельзя профилировать и оптимизировать, а если добавить еще несколько узлов и связей, то перечисление будет требовать дополнительных затрат.

Выходом из этой ситуации будет назначить общую переменную для всего запроса. Запрос приобретет следующий вид.

Рис. 3.7. Добавление общей переменной в запрос

Если выполнить измененный запрос, то результат будет аналогичным:

MATCH p=(:User)-[: AdminTo]->(:Computer) RETURN p

Различные варианты использования оператора RETURN мы рассмотрим позже.

Указание метки будет влиять на скорость выполнения запроса, но и результат может быть другим. Например, в запросе выше упускается тот факт, что группы тоже могут иметь связь CanRDP. Таким образом, в запросе можно опустить указание метки User, и он будет выглядеть следующим образом:

MATCH p=(u)-[r: AdminTo]->(c: Computer) RETURN p

Варианты запросов

Cypher – достаточно свободный язык запросов, одинаковых результатов можно добиться разными путями. Рассмотрим выполнение запроса выше другими способами. Мы можем отдельно определить начальный и конечный узлы и затем запросить, есть ли между ними связь.

MATCH (u: User)

MATCH (c: Computer)

MATCH p=(u)-[r: AdminTo]->(c) RETURN p

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

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

MATCH (u: User),

(c: Computer),

p=(u)-[r: AdminTo]->(c) RETURN p

Браузер neo4j пометит, что данный запрос не очень удачный и его обработка может потребовать больше времени и ресурсов, тем не менее задача будет выполнена.

Объединение связей

Запрос может быть сложным: первым шагом мы можем запросить один шаблон, вторым – уже другой. Самый обычный пример для BloodHound – это поиск различных прав через членство в группах.

Рис. 3.8. Двухэтапный запрос

Возьмем все тот же пример с правами локального администратора. Посмотрим, какие группы имеют права локального администратора и какие пользователи входят в эти группы.

Информация

В сложных запросах стоит идти от конечной цели (последнего запроса) к начальному узлу.

MATCH p=(u: User)-[: MemberOf]-(g: Group)-[: AdminTo]->(c: Computer) RETURN p

Внимание

Данный запрос не вернет информацию, если пользователь имеет права локального администратора напрямую.

Мы можем объединить связи в этом запросе, используя логический оператор ИЛИ (представлен как |).

MATCH p=(u: User)-[: MemberOf|AdminTo]->(c: Computer) RETURN p

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

Рис. 3.9. Объединение связей

И тогда наш запрос примет вид

MATCH p=(u: User)-[: MemberOf|AdminTo*1..]->(c: Computer) RETURN p

В предыдущем примере мы использовали запись *1.. – указание количества промежуточных узлов, к которым может применяться шаблон, в данном случае – от одного перехода до бесконечности. Число переходов здесь – это количество различных промежуточных узлов от начального узла до конечного.

Ниже приведены две таблицы, в которых описаны различные варианты синтаксиса.

Без указания типа связи:

Приведу несколько примеров. Все прямые связи между узлами:

MATCH p=(u: User)->(c: Group) RETURN p

MATCH p=(u: User)-[]->(c: Group) RETURN p

Все непрямые связи между узлами с указанием ограничений от одного до двух переходов:

MATCH p=(u: User)-[*1..2]->(c: Group) RETURN p

С указанием типа связей:

Пример – получить всех пользователей и их членство в группах: