1. etiqueta de enlace
- La etiqueta de vinculación puede usar una expresión OGNL para crear una variable y vincularla al contexto.
gramática:
<bind name = "variable a vincular" value = "valor final de vinculación" />
- nombre: una variable de contexto, como la variable #{userName} en SQL, donde el nombre se completa con el nombre de usuario
- valor: el valor final de la variable de vinculación, como nombre="nombre de usuario", luego el valor es el valor real final de #{nombre de usuario}, que puede procesar los parámetros pasados, como: valor = " '%' + nombre de usuario + '%' ", para unir los símbolos % antes y después del nombre de usuario entrante.
2. Función
1>Compatible con las diferencias de sintaxis SQL entre diferentes bases de datos, amigable con la migración de bases de datos
Debido a las diferencias en algunas escrituras de SQL en diferentes bases de datos, el uso de bind puede adaptarse a las diferencias entre diferentes bases de datos.
Por ejemplo: en una consulta difusa, use la función de empalme de cadenas concat para admitir múltiples parámetros en MySQL, pero solo se pueden escribir dos parámetros en Oracle, de la siguiente manera:
Método de escritura MySQL:
select id,serial from payment
where
serial like concat("%",#{serial},"%")
Método de escritura de Oracle:
select id,serial from payment
where
serial like concat("%",concat(#{serial},"%"))
Por lo tanto, cuando Oracle se migre a MySQL, hará que mybatis informe un error.Podemos usar la etiqueta de vinculación para ser directamente compatible, de la siguiente manera:
select id,name from payment
where
<bind name="name" value="'%'+name+'%'" />
name like #{name} --name实际是bind标签中的value
2> Prevenir la inyección de SQL
Tome la consulta difusa como ejemplo, cuando usamos directamente la concatenación de cadenas SQL sin usar la función concat, de la siguiente manera:
select id,serial from payment
where
serial like "%${serial}%"
--注意:Oracle写法为:"%"||${serial}||"%"
Nota: Esto solo puede ser: "%${serial}%", no "%#{serial}%"
- "%${serial}%": ${serial} se considerará como un marcador de posición de cadena, y esta parte se reemplazará directamente cuando se ejecute SQL
- "%#{serial}%": #{serial} no tendrá efecto cuando la cadena se concatena, es directamente una cadena "%#{serial}%"
Probamos la declaración de consulta difusa de SQL anterior, caso de inyección de SQL:
<1>MySQL tiene datos de la tabla de pagos
<2> XML de asignación de mybatis
<select id="getBySerial" resultMap="payMap">
select id,serial from payment where
serial like "%${serial}%"
</select>
<3>interfaz del controlador
Los códigos de capa de servicio y dao se omiten directamente sin ningún procesamiento, y el SQL en el xml se llamará directamente
@RequestMapping("/payment/getBySerial")
public R<List<PaymentDTO>> getBySerial(PaymentDTO dto){
return R.ok(paymentService.getBySerial(dto));
}
<4> prueba
Prueba de solicitud normal: http://127.0.0.1:6061/payment/getBySerial?serial=O
La instrucción SQL ejecutada en este momento es:
select id,serial from payment where
serial like "%O%"
Pruebe la solicitud de inyección SQL: http://127.0.0.1:6061/payment/getBySerial?serial=O" o 1=1 o "serial=O
La instrucción SQL ejecutada en este momento es:
select id,serial from payment where
serial like "%O" or 1=1 or "serial=O%"
! ! ! o 1 = 1: ¡La condición del filtro es directamente inválida y se pueden obtener todos los datos de la tabla! ,como sigue:
<5> enlace para evitar la modificación de inyección de SQL
Por lo tanto, no podemos usar #{} para evitar la inyección SQL en el método de escritura mencionado anteriormente. En el caso de no usar funciones SQL y códigos Java sin empalmar %, queremos evitar la inyección SQL. Podemos usar la etiqueta de enlace + #{ } para reemplazar $ { } forma de empalme , el caso es el siguiente:
- Cambie el SQL en xml y otros códigos no se mueven:
select id,serial from payment where
<bind name="serial" value="'%'+serial+'%'" />
serial like #{serial}
Continuar probando:
Prueba de solicitud normal: http://127.0.0.1:6061/payment/getBySerial?serial=O
La instrucción SQL ejecutada en este momento es:
Resultado de la solicitud:
Pruebe la solicitud de inyección SQL: http://127.0.0.1:6061/payment/getBySerial?serial=O" o 1=1 o "serial=O
La instrucción SQL ejecutada en este momento es:
El resultado es el siguiente: