es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Cómo consultar correctamente el campo JSONB de Postgres en Vapor/Fluent.

Tengo una tabla con algunas columnas jsonb creadas por una migración como esta:

    public func prepare(on database: Database) -> EventLoopFuture<void> {
        return database.schema(MyTable.schema)
            .id()
            .field(.metadata, .custom("JSONB"), .required)
            .create()
    }

Estoy tratando de filtrar una consulta en el campo jsonb. Lo siguiente es una interpolación de cadena simple que funciona.

//jsonFilters es un diccionario de pares clave-valor para los cuales queremos filtrar en el campo jsonb

        var query = MyTable.query(on: db)
        var filterString  = ""
        var cycleCount = 0;
        jsonFilters.forEach({
            (key, value) in
            filterString +=
            "metadata->>'\(key)' = '\(value)' "
            cycleCount+=1
            if(cycleCount < filter.metadata!.count) {
                filterString += " AND "
            }
        })
        query = query.filter(.custom(metadataString))
        // También filtrar en algo más.
        query = query.filter(....)

Sin embargo, esto no es seguro y es vulnerable a la inyección de SQL. ¿Hay alguna manera de unir los argumentos de filtro utilizando SQLQueryString, por ejemplo? Debería funcionar junto con el resto del filtro regular. (Última línea en el código)

Tags:  ,

Answer

  1. Avatar for davy.ai

    Sí, es posible vincular los argumentos del filtro utilizando SQLQueryString para evitar vulnerabilidades de inyección SQL. Puede modificar su código de la siguiente manera:

    //jsonFilters es un diccionario de pares de clave y valor para los cuales deseamos filtrar en un campo jsonb
    var query = MyTable.query(on: db)
    var filterString  = ""
    var cycleCount = 0
    var bindings: [Encodable] = []
    jsonFilters.forEach { (key, value) in
        filterString += "metadata->>:key\(cycleCount) = :value\(cycleCount)"
        bindings.append(key)
        bindings.append(value)
        cycleCount += 1
        if cycleCount < filter.metadata!.count {
            filterString += " AND "
        }
    }
    let sqlQueryString = SQLQueryString(filterString, bindables: bindings)
    query = query.filter(sqlQueryString)
    // También se filtra en algo más.
    query = query.filter(....)
    

    En este código actualizado, se crea una matriz bindings para almacenar los valores que deben ser vinculados a la consulta. La cadena de filtro se modifica para utilizar marcadores de posición :key y :value que corresponden a la posición del valor en la matriz de vinculación. Finalmente, se utiliza SQLQueryString para crear una consulta correctamente formada con los vinculables. Esto garantiza que los valores estén saneados y seguros contra ataques de inyección SQL.

Comments are closed.