3. Uso de la función Elasticsearch

Capítulo 4 Uso de funciones
4.1 Operaciones de la API de Java
Con la llegada de la nueva versión de Elasticsearch 8.x, el concepto de Tipo ha sido abolido. Para adaptarse a este cambio en la estructura de datos
, los funcionarios de Elasticsearch recomiendan utilizar el nuevo Cliente Java de Elasticsearch a partir de desde la versión 7.15.
4.1.1 Agregar dependencias

<properties>
 <maven.compiler.source>8</maven.compiler.source>
 <maven.compiler.target>8</maven.compiler.target>
 <elastic.version>8.1.0</elastic.version>
</properties>
<dependencies>
 <dependency>
 <groupId>org.elasticsearch.plugin</groupId>
 <artifactId>x-pack-sql-jdbc</artifactId>
 <version>8.1.0</version>
 </dependency>
 <dependency>
 <groupId>co.elastic.clients</groupId>
 <artifactId>elasticsearch-java</artifactId>
 <version>${
    
    elastic.version}</version>
 </dependency>
 <dependency>
 <groupId>com.fasterxml.jackson.core</groupId>
 <artifactId>jackson-databind</artifactId>
 <version>2.12.3</version>
 </dependency>
 <dependency>
 <groupId>jakarta.json</groupId>
 <artifactId>jakarta.json-api</artifactId>
 <version>2.0.1</version>
 </dependency>
</dependencies>

4.1.2 Obtener el objeto del cliente
Al igual que conectarse a la base de datos MySQL, Java puede operar Elasticsearch a través del cliente solo después de obtener la conexión
.
Ahora estamos usando un servicio Elasticsearch seguro basado en https, por lo que primero debemos convertir el certificado anterior a
openssl pkcs12 -in elastic-stack-ca.p12 -clcerts -nokeys -out java-ca.crt
Insertar descripción de la imagen aquí
Después de configurar el certificado, Puede utilizar https para obtener el objeto de conexión.

# 导入的类
import co.elastic.clients.elasticsearch.*;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import org.apache.http.HttpHost;
import org.apache.http.auth.*;
import org.apache.http.client.*;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.impl.client.*;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.apache.http.ssl.*;
import org.elasticsearch.client.*;
import javax.net.ssl.SSLContext;
import java.io.InputStream;
import java.nio.file.*;
import java.security.KeyStore;
import java.security.cert.*;
# 获取客户端对象
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
 new UsernamePasswordCredentials("elastic", "O3x0hfu7i=ZbQvlktCnd"));
Path caCertificatePath = Paths.get("ca.crt");
CertificateFactory factory =
 CertificateFactory.getInstance("X.509");
Certificate trustedCa;
try (InputStream is = Files.newInputStream(caCertificatePath)) {
    
    
 trustedCa = factory.generateCertificate(is);
}
KeyStore trustStore = KeyStore.getInstance("pkcs12");
trustStore.load(null, null);
trustStore.setCertificateEntry("ca", trustedCa);
SSLContextBuilder sslContextBuilder = SSLContexts.custom()
 .loadTrustMaterial(trustStore, null);
final SSLContext sslContext = sslContextBuilder.build();
RestClientBuilder builder = RestClient.builder(
 new HttpHost("linux1", 9200, "https"))
 .setHttpClientConfigCallback(new 
RestClientBuilder.HttpClientConfigCallback() {
    
    
 @Override
 public HttpAsyncClientBuilder customizeHttpClient(
 HttpAsyncClientBuilder httpClientBuilder) {
    
    
 return httpClientBuilder.setSSLContext(sslContext)
 .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
 .setDefaultCredentialsProvider(credentialsProvider);
 }
 });
RestClient restClient = builder.build();
ElasticsearchTransport transport = new RestClientTransport(
 restClient, new JacksonJsonpMapper());
ElasticsearchClient client = new ElasticsearchClient(transport);
ElasticsearchAsyncClient asyncClient = new ElasticsearchAsyncClient(transport);
...
transport.close();

4.1.3 Datos de operación (operaciones normales)
4.1.3.1 Operación de índice

// 创建索引
CreateIndexRequest request = new 
CreateIndexRequest.Builder().index("myindex").build();
final CreateIndexResponse createIndexResponse = 
client.indices().create(request);
System.out.println("创建索引成功:" + createIndexResponse.acknowledged());
// 查询索引
GetIndexRequest getIndexRequest = new 
GetIndexRequest.Builder().index("myindex").build();
final GetIndexResponse getIndexResponse = 
client.indices().get(getIndexRequest);
System.out.println("索引查询成功:" + getIndexResponse.result());
// 删除索引
DeleteIndexRequest deleteIndexRequest = new 
DeleteIndexRequest.Builder().index("myindex").build();
final DeleteIndexResponse delete = client.indices().delete(deleteIndexRequest);
final boolean acknowledged = delete.acknowledged();
System.out.println("删除索引成功:" + acknowledged)

4.1.3.2 Operaciones con documentos

// 创建文档
IndexRequest indexRequest = new IndexRequest.Builder()
 .index("myindex")
 .id(user.getId().toString())
 .document(user)
 .build();
final IndexResponse index = client.index(indexRequest);
System.out.println("文档操作结果:" + index.result());
// 批量创建文档
final List<BulkOperation> operations = new ArrayList<BulkOperation>();
for ( int i= 1;i <= 5; i++ ) {
    
    
 final CreateOperation.Builder builder = new CreateOperation.Builder();
 builder.index("myindex");
 builder.id("200" + i);
 builder.document(new User(2000 + i, 30 + i * 10, "zhangsan" + i, "beijing", 
1000 + i*1000));
 final CreateOperation<Object> objectCreateOperation = builder.build();
 final BulkOperation bulk = new 
BulkOperation.Builder().create(objectCreateOperation).build();
 operations.add(bulk);
}
BulkRequest bulkRequest = new 
BulkRequest.Builder().operations(operations).build();
final BulkResponse bulkResponse = client.bulk(bulkRequest);
System.out.println("数据操作成功:" + bulkResponse);
// 删除文档
DeleteRequest deleteRequest = new 
DeleteRequest.Builder().index("myindex").id("1001").build();
client.delete(deleteRequest);

4.1.3.3 Consulta de documentos

final SearchRequest.Builder searchRequestBuilder = new 
SearchRequest.Builder().index("myindex1");
MatchQuery matchQuery = new 
MatchQuery.Builder().field("city").query(FieldValue.of("beijing")).build();
Query query = new Query.Builder().match(matchQuery).build();
searchRequestBuilder.query(query);
SearchRequest searchRequest = searchRequestBuilder.build();
final SearchResponse<Object> search = client.search(searchRequest, 
Object.class);
System.out.println(search);

4.1.4 Datos de operación (operación de función)
4.1.4.1 Operación de índice


// 创建索引
final Boolean acknowledged = client.indices().create(p -> 
p.index("")).acknowledged();
System.out.println("创建索引成功");
// 获取索引
System.out.println(
 client.indices().get(
 req -> req.index("myindex1")
).result());
// 删除索引
client.indices().delete(
 reqbuilder -> reqbuilder.index("myindex")
).acknowledged();


4.1.4.2 Operaciones con documentos

// 创建文档
System.out.println(
 client.index(
 req ->
 req.index("myindex")
 .id(user.getId().toString())
 .document(user)
 ).result()
);
// 批量创建文档
client.bulk(
 req -> {
    
    
 users.forEach(
 u -> {
    
    
 req.operations(
 b -> {
    
    
 b.create(
 d -> 
d.id(u.getId().toString()).index("myindex").document(u)
 );
 return b;
 }
 );
 }
 );
 return req;
 }
);
// 删除文档
client.delete(
 req -> req.index("myindex").id("1001")
);

4.1.4.3 Consulta de documentos

client.search(
 req -> {
    
    
 req.query(
 q ->
 q.match(
 m -> m.field("city").query("beijing")
 )
 );
 return req;
 }
 , Object.class
);

4.1.5 Operación asíncrona del lado del cliente
La API Java de ES proporciona dos tipos de procesamiento del lado del cliente, síncrono y asíncrono. Todas las demostraciones anteriores fueron procesamiento sincrónico.
Los principios básicos del procesamiento de cliente asincrónico y el procesamiento de cliente sincrónico son los mismos, la diferencia es que los resultados devueltos deben procesarse
de forma asincrónica.

// 创建索引
asyncClient.indices().create(
 req -> {
    
    
 req.index("newindex");
 return req;
 }
).whenComplete(
 (resp, error) -> {
    
    
 System.out.println("回调函数");
 if ( resp != null ) {
    
    
 System.out.println(resp.acknowledged());
 } else {
    
    
 error.printStackTrace();
 }
 }
);
System.out.println("主线程操作...");
asyncClient.indices().create(
 req -> {
    
    
 req.index("newindex");
 return req;
 }
)
.thenApply(
 resp -> {
    
    
 return resp.acknowledged();
 }
)
.whenComplete(
 (resp, error) -> {
    
    
 System.out.println("回调函数");
 if ( !resp ) {
    
    
 System.out.println();
 } else {
    
    
 error.printStackTrace();
 }
 }
);

4.2 Operación EQL
El nombre completo de EQL es Lenguaje de consulta de eventos (EQL). Event Query Language (EQL) es un
lenguaje de consulta para datos de series temporales basados ​​en eventos, como registros, métricas y seguimientos. En la plataforma Elastic Security, cuando
se ingresa un EQL válido, la consulta se compila en el nodo de datos, ejecuta la consulta y devuelve los resultados. Todo esto
sucede rápidamente y en paralelo, lo que permite a los usuarios ver los resultados de inmediato.
Ventajas de EQL:
➢ EQL le permite expresar relaciones entre eventos.
Muchos lenguajes de consulta le permiten hacer coincidir eventos individuales. EQL le permite hacer coincidir una
serie de eventos en diferentes categorías de eventos y períodos de tiempo.
➢ EQL tiene una curva de aprendizaje baja.
La sintaxis de EQL se parece a la de otros lenguajes de consulta comunes, como SQL. EQL le permite escribir y leer consultas de forma intuitiva
, lo que permite realizar búsquedas rápidas e iterativas.
➢ EQL diseñado para casos de uso de seguridad.
Aunque puede usarlo con cualquier dato basado en eventos, creamos EQL para la búsqueda de amenazas. EQL
no solo admite búsquedas de Indicadores de Compromiso (IOC), sino que también puede describir actividades más allá del alcance de los IOC.
Insertar descripción de la imagen aquí
4.2.1 Sintaxis básica
4.2.1.1 Preparación de datos
Para ejecutar una búsqueda EQL, el flujo o índice de datos buscado debe contener campos de marca de tiempo y categoría de evento. De forma predeterminada,
EQL utiliza los campos @timestamp y event.category en Elastic Common Schema (ECS).
@timestamp representa la marca de tiempo y event.category representa la categoría del evento.
Preparemos algunos datos simples para representar los saltos de página del sitio web de comercio electrónico.

# 创建索引
PUT /gmall
# 批量增加数据
PUT _bulk
{
    
    "index":{
    
    "_index":"gmall"}}
{
    
    "@timestamp":"2022-06-01T12:00:00.00+08:00", 
"event":{
    
    "category":"page"},"page" : {
    
    "session_id" : 
"42FC7E13-CB3E-5C05-0000-0010A0125101","last_page_id" : "","page_id" : 
"login","user_id" : ""}}
{
    
    "index":{
    
    "_index":"gmall"}}
{
    
    "@timestamp":"2022-06-01T12:01:00.00+08:00", 
"event":{
    
    "category":"page"},"page" : {
    
    "session_id" : 
"42FC7E13-CB3E-5C05-0000-0010A0125101","last_page_id" : "login","page_id" : 
"good_list","user_id" : "1"}}
{
    
    "index":{
    
    "_index":"gmall"}}
{
    
    "@timestamp":"2022-06-01T12:05:00.00+08:00", 
"event":{
    
    "category":"page"},"page" : {
    
    "session_id" : 
"42FC7E13-CB3E-5C05-0000-0010A0125101","last_page_id" : "good_list","page_id" : 
"good_detail","user_id" : "1"}}
{
    
    "index":{
    
    "_index":"gmall"}}
{
    
    "@timestamp":"2022-06-01T12:07:00.00+08:00", 
"event":{
    
    "category":"page"},"page" : {
    
    "session_id" : 
"42FC7E13-CB3E-5C05-0000-0010A0125101","last_page_id" : 
"good_detail","page_id" : "order","user_id" : "1"}}
{
    
    "index":{
    
    "_index":"gmall"}}
{
    
    "@timestamp":"2022-06-01T12:08:00.00+08:00", 
"event":{
    
    "category":"page"},"page" : {
    
    "session_id" : 
"42FC7E13-CB3E-5C05-0000-0010A0125101","last_page_id" : "order","page_id" : 
"payment","user_id" : "1"}}
{
    
    "index":{
    
    "_index":"gmall"}}
{
    
    "@timestamp":"2022-06-01T12:08:00.00+08:00", 
"event":{
    
    "category":"page"},"page" : {
    
    "session_id" : 
"42FC7E13-CB3E-5C05-0000-0010A0125102","last_page_id" : "","page_id" : 
"login","user_id" : "2"}}
{
    
    "index":{
    
    "_index":"gmall"}}
{
    
    "@timestamp":"2022-06-01T12:08:00.00+08:00", 
"event":{
    
    "category":"page"},"page" : {
    
    "session_id" : 
"42FC7E13-CB3E-5C05-0000-0010A0125102","last_page_id" : "login","page_id" : 
"payment","user_id" : "2"}}

4.2.1.2 Búsqueda en la ventana de datos
Durante el proceso de respuesta a incidentes, hay muchas ocasiones en las que es útil conocer todos los eventos que ocurrieron en un momento específico. Utilice un
tipo de evento especial llamado cualquiera para que coincida con todos los eventos. Si desea hacer coincidir un evento específico, debe especificar el
nombre de clasificación del evento.

# 
GET /gmall/_eql/search
{
    
    
 "query" : """
 any where page.user_id == "1"
 """
}

4.2.1.3 Estadísticas de eventos clasificatorios

# 
GET /gmall/_eql/search
{
    
    
 "query" : """
 any where true
 """,
  "filter": {
    
    
 "range": {
    
    
 "@timestamp": {
    
    
 "gte": "1654056000000",
 "lt": "1654056005000"
 }
 }
 }
}

4.2.1.4 Secuencia de eventos

# 页面先访问 login,后面又访问了 good_detail 的页面
GET /gmall/_eql/search
{
    
    
 "query" : """
 sequence by page.session_id
 [page where page.page_id=="login"]
 [page where page.page_id=="good_detail"]
 """
}

4.2.2 Detección de seguridad
EQL se utiliza ampliamente en Elastic Securit. En aplicaciones prácticas, podemos utilizar el lenguaje EQL para detectar
amenazas a la seguridad y otros comportamientos sospechosos.
4.2.2.1 Preparación de datos
regsvr32.exe es una utilidad de línea de comandos incorporada para registrar bibliotecas .dll en Windows. Como
herramienta nativa, regsvr32.exe tiene un estado de confianza, lo que le permite eludir la mayoría de los bloqueadores de secuencias de comandos y programas permitidos
. Un atacante con acceso a la línea de comando del usuario podría usar regsvr32.exe para ejecutar scripts maliciosos a través de una biblioteca .dll, incluso si
de otro modo no se permitiría ejecutar los scripts.
Una variante común del abuso de regsvr32 es el ataque Squfullydoo. En el ataque Squfullydoo, el
comando regsvr32.exe utiliza la biblioteca scrobj.dll para registrar y ejecutar scripts remotos.
Los datos de prueba provienen del conjunto de datos de prueba del Atomic Red Team, que incluye eventos que imitan el ataque de Squibledoo.
Los datos se han asignado al campo Elastic Common Schema (ECS): normalized-T1117-AtomicRed-regsvr32.json.
Importe el contenido del archivo al software ES:

# 创建索引
PUT my-eql-index
# 导入数据
POST my-eql-index/_bulk?pretty&refresh

Insertar descripción de la imagen aquí
Verificar el estado de importación de datos

# 导入数据
GET /_cat/indices/my-eql-index?v=true&h=health,status,index,docs.count

Insertar descripción de la imagen aquí
4.2.2 Obtener el recuento de eventos regsvr32
Obtener el número de eventos asociados con el proceso regsvr32.exe

# 查询数据
# ?filter_path=-hits.events 从响应中排除 hits.events 属性。 此搜索仅用于获取事件计数,
而不是匹配事件的列表
# query : 匹配任何进程名称为 regsvr32.exe 的事件
# size : 最多返回 200 个匹配事件的匹配,实际查询结果为 143GET my-eql-index/_eql/search?filter_path=-hits.events
{
    
    
 "query": """
 any where process.name == "regsvr32.exe" 
 """,
 "size": 200 
}

Insertar descripción de la imagen aquí
4.2.3 Comprobación de los parámetros de la línea de comandos
El proceso regsvr32.exe está asociado con 143 eventos. Pero, ¿cómo llamo a regsvr32.exe en primer lugar? ¿Quién lo llamó?
regsvr32.exe es una utilidad de línea de comandos. Limitar los resultados a los procesos que utilizan la línea de comando

# 增加过滤条件查询数据
GET my-eql-index/_eql/search
{
    
    
 "query": """
 process where process.name == "regsvr32.exe" and 
process.command_line.keyword != null 
 """
 }

Insertar descripción de la imagen aquí
Esta consulta hace coincidir un evento con el tipo de evento creado que indica el inicio del proceso regsvr32.exe. Según
el valor de Process.command_line del evento, regsvr32.exe usa scrobj.dll para registrar el script RegSvr32.sct, lo que es consistente con
el comportamiento del ataque Squibledoo
4.2.4 Verificar si se están cargando scripts maliciosos
Verificar si se carga regsvr32.exe la biblioteca scrobj.dll en el futuro

# 增加过滤条件查询数据
GET my-eql-index/_eql/search
{
    
    
 "query": """
 library where process.name == "regsvr32.exe" and dll.name == "scrobj.dll" 
 """ 
}

Insertar descripción de la imagen aquí
4.2.5 Comprobación de la probabilidad de un ataque exitoso
En muchos casos, los atacantes utilizan scripts maliciosos para conectarse a servidores remotos o descargar archivos adicionales. Utilice una consulta de secuencia EQL
para examinar la siguiente serie de eventos:
➢ proceso regsvr32.exe
➢ Carga de la biblioteca scrobj.dll a través del mismo proceso
➢ Cualquier evento de red en el mismo proceso
Basado en los valores de la línea de comando vistos en la sección anterior respuesta, puede esperar Se encontró una coincidencia. Sin embargo, esta consulta no está
diseñada para este comando específico. En cambio, busca un patrón de comportamiento sospechoso que sea suficiente para detectar
amenazas similares.

# 增加过滤条件查询数据
GET my-eql-index/_eql/search
{
    
    
 "query": """
 sequence by process.pid
 [process where process.name == "regsvr32.exe"]
 [library where dll.name == "scrobj.dll"]
 [network where true] 
 """ 
}

4.3 operaciones SQL

Generalmente, cuando se usa Elasticsearch, Query DSL se usa para consultar datos. A partir de la versión Elasticsearch6.3
, Elasticsearch ya admite consultas SQL.
Elasticsearch SQL es un componente X-Pack que permite la ejecución en tiempo real de consultas similares a SQL
contra Elasticsearch. Ya sea que utilice la interfaz REST, la línea de comandos o JDBC, cualquier cliente puede usar SQL para
buscar y agregar datos de forma nativa en Elasticsearch. Piense en Elasticsearch SQL como un traductor que traduce
SQL a Query DSL.
Elasticsearch SQL tiene las siguientes características:
➢ Soporte nativo: Elasticsearch SQL está especialmente diseñado para Elasticsearch.
➢ Sin piezas adicionales: No se requieren otros hardware, procesadores, entornos operativos o bibliotecas dependientes para consultar Elasticsearch.
Elasticsearch SQL se ejecuta directamente dentro de Elasticsearch.
➢ Ligero y eficiente: Elasticsearch SQL no abstrae su función de búsqueda, por el contrario, adopta y acepta SQL para
implementar la búsqueda de texto completo y ejecutar la búsqueda de texto completo en tiempo real de manera concisa.
4.3.1 Correspondencia entre SQL y Elasticsearch
Aunque SQL y Elasticsearch tienen diferentes términos para la forma en que se organizan los datos (y diferente semántica), sus
propósitos son esencialmente los mismos

Insertar descripción de la imagen aquí
Aunque el mapeo entre conceptos no es completamente uno a uno y la semántica es diferente, existen más similitudes que diferencias. De hecho,
muchos conceptos de SQL pueden encontrar correspondencias en Elasticsearch, y los términos de los dos también son muy similares.4.3.2
Preparación de datos

# 创建索引并增加数据,等同于创建表和数据
PUT my-sql-index/_bulk?refresh
{
    
    "index":{
    
    "_id": "JAVA"}}
{
    
    "name": "JAVA", "author": "zhangsan", "release_date": "2022-05-01", 
"page_count": 561}
{
    
    "index":{
    
    "_id": "BIGDATA"}}
{
    
    "name": "BIGDATA", "author": "lisi", "release_date": "2022-05-02", "page_count": 
482}
{
    
    "index":{
    
    "_id": "SCALA"}}
{
    
    "name": "SCALA", "author": "wangwu", "release_date": "2022-05-03", "page_count": 
604}

Insertar descripción de la imagen aquí

4.3.3 第一个 SQL 查询
现在可以使用 SQL 对数据进行查询了。
# SQL
# 这里的表就是索引
# 可以通过 format 参数控制返回结果的格式,默认为 json 格式
# txt:表示文本格式,看起来更直观点.
# csv:使用逗号隔开的数据
# json:JSON 格式数据
# tsv: 使用 tab 键隔开数据
# yaml:属性配置格式
POST _sql?format=txt
{
    
    
 "query": """
 SELECT * FROM "my-sql-index"
 """
}
# 条件查询
POST _sql?format=txt
{
    
    
 "query": """
 SELECT * FROM "my-sql-index" where page_count > 500
 """
}

Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí
De hecho, encontrará que la sintaxis SQL para las operaciones JDBC es básicamente la misma.

4.3.3 Conversión de SQL a DSL
Cuando necesitamos usar Query DSL, también podemos usar SQL para consultar primero y luego convertirlo a través de Translate API.Los
resultados de la consulta son resultados de DSL.

# 转换 SQLDSL 进行操作
POST _sql/translate
{
    
    
 "query": """
 SELECT * FROM "my-sql-index" where page_count > 500
 """
}

Insertar descripción de la imagen aquí
4.3.4 Uso mixto de SQL y DSL
Si aún no podemos cumplir con los requisitos de consulta después de optimizar la declaración SQL, podemos mezclar SQL y DSL. ES primero realizará
una consulta basada en SQL y luego realizará una consulta secundaria sobre los resultados de la ejecución de SQL según en la declaración DSL.

# SQLDSL 混合使用
# 由于索引中含有横线,所以作为表名时需要采用双引号,且外层需要三个引号包含
POST _sql?format=txt
{
    
    
 "query": """SELECT * FROM "my-sql-index" """,
 "filter" : {
    
    
 "range": {
    
    
 "page_count": {
    
    
 "gte": 400,
 "lte": 600
 }
 }
 },
 "fetch_size": 2
}

Insertar descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/weixin_45817985/article/details/133171914
Recomendado
Clasificación