Esto le ocurrió a un cliente el otro día. Estaban realizando una auditoría de seguridad de las reglas de negocio de OneStream escritas en su aplicación. La auditoría fallaba debido a una inyección SQL. Entonces, ¿qué es la inyección SQL y cómo se escribe código para evitarla (y superar la auditoría de seguridad)?
La inyección SQL es una vulnerabilidad de seguridad que permite a un atacante modificar las consultas SQL inyectando código malicioso en las secciones de entrada del usuario de una consulta SQL. Incluir la entrada del usuario concatenada en la consulta SQL permite la inyección SQL.
El siguiente ejemplo de código proviene de una regla de negocio de OneStream. Muestra un ejemplo de una consulta de base de datos SQL susceptible a la inyección SQL. La consulta se basa en la entrada del usuario de dos variables: nombre y apellido del vendedor.
Dim dt as New DataTable
Dim strSalesPersonFirstName As String = "John"
Dim strSalesPersonLastName As String = "Doe"
Dim strCity As String = Nothing
using dbconn As DbConnInfo = BRApi.Database.CreateApplicationDbConnInfo(si)
Dim Sql As String = String.Empty
sql = $"SELECT City from XFC_TableView_SalesPerson WHERE SalesPersonFirstName = '{strSalesPersonFirstName}' AND SalesPersonLastName = '{strSalesPersonLastName}';"
dt = BRApi.Database.ExecuteSqlUsingReader(dbConn,sql.ToString,False)
If Not dt is Nothing Then
For Each RowNotInTableException As DataRow In dt.Rows
strCity = RowNotInTableException.Item("City")
Next
End If
brapi.ErroLog.LogMessage(si,"City=" & strCity.ToString)
End Using
La consulta SQL es interpretada por VB.Net, que reemplazaría las dos variables de cadena en la consulta SQL y pasaría la consulta completa a la base de datos. Se vería así: "SELECT City from XFC_TableView_SalesPerson WHERE SalesPersonFirstName = ‘John’ AND SalesPersonLastName = ‘Doe’;". Esto abre la posibilidad de que un atacante reemplace las dos variables introducidas por el usuario con otro código SQL que se pasaría, se concatenaría en la consulta por VB.Net y se ejecutaría en la base de datos.
¿Cómo evitar esto? Una forma es separar la entrada del usuario de la consulta SQL mediante consultas parametrizadas.
Las consultas parametrizadas mantienen la entrada del usuario separada de la consulta SQL en el código. Luego, la entrada del usuario parametrizada se pasa por separado de la consulta SQL a la base de datos.
En la práctica, funciona de la siguiente manera: Seguirá usando BRApi.Database.ExecuteSql o BRApi.Database.ExecuteSqlUsingReader. Lo que hará de forma diferente es usar la versión que toma un objeto dbParamInfo como parámetro.
Syntax
Public Function ExecuteSqlUsingReader(ByVal dbConn As DbConnInfo, ByVal sqlStatement As String, ByVal dbParaminfos As List(Of DbParaminfo),
ByVal useCommandTimeoutLarge As Boolean) As DataTable
dbParamInfo es una lista de DbParamInfo. Básicamente, se carga esta lista con los parámetros y sus valores para la consulta SQL parametrizada y se pasa a BRApi.Database.ExecuteSql o BRApi.Database.ExecuteSqlUsingReader.
1. En su regla de negocio, cree un objeto DbParamInfo y luego agregue sus variables y sus valores usando “.Add”.
Dim dt as New DataTable
Dim strSalesPersonFirstName As String = "John"
Dim strSalesPersonLastName As String = "Doe"
Dim strCity As String = Nothing
Dim dbParamInfos As New List(Of DbParamInfo)
dbParamInfos.Add(New DbParamInfo("strSalesPersonFirstName", strSalesPersonFirstName))
dbParamInfos.Add(New DbParamInfo("strSalesPersonLastName", strSalesPersonLastName))
2. Luego parametriza tu consulta SQL.
Using dbConn As DbConnInfo = BRApi.Database.CreateApplicationDBConnInfo(si)
Dim Sql As String = String.Empty
sql = $"SELECT City from XFC_TableView_SalesPerson WHERE SalesPersonFirstName = @strSalesPersonFirstName AND SalesPersonLastName = @strSalesPersonLastName;"
3. Finalmente, pasa la consulta SQL y el objeto DbParamInfo a la llamada BRApi.Database.ExecuteSql o BRApi.Database.ExecuteSqlUsingReader. Manteniendo los parámetros separados de la consulta SQL. De esta forma, se evita la inyección SQL.
La consulta en su totalidad.
Dim dt as New DataTable
Dim strSalesPersonFirstName As String = "John"
Dim strSalesPersonLastName As String = "Doe"
Dim strCity As String = Nothing
Dim dbParamInfos As New List(Of DbParamInfo)
dbParamInfos.Add(New DbParamInfo("strSalesPersonFirstName", strSalesPersonFirstName))
dbParamInfos.Add(New DbParamInfo("strSalesPersonLastName", strSalesPersonLastName))
using dbconn As DbConnInfo = BRApi.Database.CreateApplicationDbConnInfo(si)
Dim Sql As String = String.Empty
sql = $"SELECT City from XFC_TableView_SalesPerson WHERE SalesPersonFirstName = @strSalesPersonFirstName AND SalesPersonLastName = @strSalesPersonLastName;"
dt = BRApi.Database.ExecuteSqlUsingReader(dbConn,sql.ToString,dbParamInfors,False)
If Not dt is Nothing Then
For Each RowNotInTableException As DataRow In dt.Rows
strCity = RowNotInTableException.Item("City")
Next
End If
brapi.ErroLog.LogMessage(si,"City=" & strCity.ToString)
End Using
No supone un gran cambio respecto a la forma habitual de escribir consultas SQL en OneStream y ayudará a evitar inyecciones SQL (y a superar las auditorías de seguridad).
Para obtener más información sobre OneStream y cómo MindStream Analytics puede ayudarlo a mejorar su planificación, informes y análisis, complete el formulario a continuación.
Descubra el futuro de la gestión financiera con nuestro seminario web informativo y la demostración de SheetsTM para OneStream, una solución pionera de MindStream Software que integra las potentes funciones financieras de OneStream directamente en Google SheetsTM.
Transform your Financial Management in Google Sheets with Sheets for OneStream
OneStream CPM
OneStream se adapta a las necesidades y cambios de su negocio con mayor rapidez y facilidad que cualquier otro producto, ofreciendo una plataforma y un modelo para todas las soluciones de CPM financieras. OneStream emplea flujos de trabajo guiados, validaciones y mapeo flexible para garantizar la calidad de los datos en todas las recopilaciones y análisis, a la vez que reduce el riesgo en todo el proceso financiero auditable.