ON CREATE SET
, которая добавляет свойства узла при его создании. Однако при этом придется передать индивидуальный идентификатор.MERGE (m: User {sid: "U-003"})
ON CREATE SET
m.name='TEST'
В BloodHound уникальный идентификатор – свойство
sid
, и neo4j будет проверять его на совпадение, если такого узла нет, то создаст его, а после создания добавит переданные свойства.Если мы сейчас выполним запрос пользователей, у которых есть свойство
sid
, из базы, то получим три узла с одинаковым именем, но с разными идентификаторами.MATCH(u: User) WHERE u.sid IS NOT NULL RETURN u.name,
u.sid
Рис. 3.44. Проверка создания узлов
Добавление свойств при совпадении
Кроме
ON CREATE SET
в MERGE
есть функция ON MATCH SET
, которая добавляет свойства к ранее созданному узлу, попадающему под определенные условия. Если узла не существует, то он будет создан, с указанным идентификатором, но без свойств.MERGE(m: User {sid: "U-004"})
ON MATCH SET
m.name='TEST'
RETURN m.name, m.sid
Рис. 3.45. Результат выполнения запроса
Но стоит повторить этот запрос, и появится свойство
name
.
Рис. 3.46. Результат повторного выполнения запроса
С функцией
ON MATCH SET
нужно быть аккуратным, в случае неверно созданного запроса данные изменятся необратимо. Вот пример неправильного запроса:MERGE(m: User)
ON MATCH SET
m.sid='U-005'
RETURN m.name, m.sid
При выполнении этого запроса у всех узлов с меткой
User
свойство sid
станет одинаковым.Оператор DELETEУзел можно удалить с помощью оператора
DELETE
.
Рис. 3.47. Оператор DELETE
Запрос выполняется в два этапа: сначала поиск узлов по условиям, затем удаление. Метка и свойства – необязательные параметры, они дают более точный критерий удаления.
Внимание
Нельзя удалить узлы, которые имеют связи с другими узлами. Сначала нужно удалить связь, а потом узел.
Создадим элементы, отличные от созданных ранее. В качестве метки будем использовать
Computer
.MERGE (m: Computer {name: "COMP1", sid:'C-001'})
MERGE (n: Computer {name: "COMP2", sid:'C-002'})
MERGE (s: Computer {name: "COMP2", sid:'C-003'})
MERGE (s: Computer {name: "COMP3", sid:'C-004'})
MERGE (s: Computer {name: "COMP4", sid:'C-005'})
Внимание
Мы создали два узла с одинаковым именем, и это не опечатка.
Теперь начнем выполнять удаление по разным критериям. Сначала удалим узел, который имеет определенный идентификатор:
MATCH (m: Computer {sid:'C-001'}) DELETE m
Удаление узлов по общему свойству:
MATCH (m: Computer {name:'COMP2'}) DELETE m
Удаление узлов по общей метке:
MATCH (m: Computer) DELETE m
Удаление всех узлов:
MATCH (m) DELETE m
Можно удалить узел и все связи, которые он имеет. В этом случае запрос Cypher будет выглядеть следующим образом:
MATCH (n: User {name: "USER@DOMIAN.LOCAL"})
DETACH DELETE n
Создание связейВ предыдущем разделе мы удалили все узлы, и теперь нам нужно создать несколько новых узлов:
MERGE (u1:User {name: "USER"})
MERGE (u2:User {na
me: "ADMIN"})
MERGE (g: Group {name: "GROUP"})
MERGE (c1:Computer {name: "COMP"})
MERGE (c2:Computer {name: "SERVER"})
Проверим, что все узлы создались корректно:
MATCH (n) RETURN n
В результате у нас есть два пользователя, одна группа и два компьютера.
Связь между узлами создается с помощью оператора
MERGE
. Данный оператор будет проверять существование связи, и в случае ее отсутствия она будет создана. Можно использовать CREATE
, но все с тем же условием, что связь должна быть уникальной. Общая схема создания связи будет следующей:
Рис. 3.48. Схема создания связи
Для начала мы определяем начальный и конечный узлы с помощью оператора
MATCH
. После этого уже создаем связь, определяя направление. Также можно указать свойства связи при необходимости.Если выполнить только
MERGE
, то сначала будут созданы узлы, а затем установлена связь. Такой вариант можно использовать, но с соблюдением всех условий.Сейчас будем создавать связи между созданными узлами. Будем использовать принятые в BloodHound типы связей.
Пользователь
USER
имеет членство в группе GROUP
. Запрос Cypher будет следующим:MATCH (u: User {name: "USER"})
MATCH (g: Group {name: "GROUP"})
MERGE (u)-[r: MemberOf]->(g)
Группа
GROUP
имеет привилегии локального администратора на компьютере COMP
:MATCH (g: Group {name: "GROUP"})
MATCH (c: Computer {name: "COMP"})
MERGE (g)-[r: AdminTo]->(c)
Пользователь
ADMIN
имеет права GenericAll
на пользователя USER
и права локального администратора на компьютере SERVER
. Также добавим связи GenericAll
свойство isacl
в значении TRUE
:MATCH (u1:User {name: "ADMIN"})
MATCH (u2:User {name: "USER"})
MATCH (c: Computer {name: "SERVER"})
MERGE (u1)-[r1:GenericAll]->(u2) SET r1.isacl = TRUE
MERGE (u1)-[r2:AdminTo]->(c)
Теперь можно выполнить проверку всего, что у нас получилось. Если в настройках браузера neo4j установлен флаг Connect result nodes, то будет достаточно выполнить следующий запрос:
MATCH (n) RETURN n
Или создать полный запрос:
MATCH p=(n)-[r: AdminTo|MemberOf|GenericAll]->(m) RETURN p
Рис. 3.49. Результат добавления связей между узлами
Как можно увидеть, задача не очень сложная, но при наличии большого количества объектов и связей она будет кропотливой. Любая ошибка приведет к неверному толкованию.
Удаление связейКак и узлы, связи удаляются с помощью оператора
DELETE
.
Рис. 3.50. Схема удаления связей
Для начала выбирается шаблон поиска, а затем выполняется удаление связи между узлами.
Совет
Для корректного удаления связи между узлами сначала можно выполнить
RETURN
, а затем уже DELETE
.Рассмотрим несколько примеров. Удаление одной связи по ее наименованию:
MATCH (m)-[r: MemberOf]->(n) DELETE r
Удаление двух и более связей по их наименованию:
MATCH (m)-[r: MemberOf|GenericAll]->(n) DELETE r
Удаление связи по ее свойству:
MATCH (m)-[r]->(n) WHERE r.isacl = TRUE DELETE r
Удаление любых связей между двумя узлами:
MATCH (m)-[r]->(n) DELETE r
Удаление цепочки узлов и связейВ моей практике не требовалось удалять целую цепочку узлов и связей, но возможность такая существует. Достаточно передать запрос в переменную, а затем удалить ее:
MATCH p=(n)-[*1..]-(m: Computer {name: "COMP"}) DELETE p
Очистка базыТеперь, когда появилось понимание, как создавать и удалять узлы и связи, можно завершить эту часть очисткой базы от всех узлов с их связями. Запрос Cypher достаточно простой:
MATCH (n)
DETACH DELETE n
Загрузка информации в базу данных
Перед использованием информации ее необходимо загрузить в базу данных. BloodHound использует результаты работы SharpHound, которые формируются в виде JSON определенного типа, поэтому разные версии BloodHound не принимают результаты от других версий SharpHound.