fix: resolve sql injection while building dynamic query for filters
This commit is contained in:
@@ -4,7 +4,8 @@ use rusqlite::*;
|
|||||||
pub fn run<'a>(filter: &'a Filter) -> Result<Vec<Box<dyn ToSql + 'a>>, FailedTo> {
|
pub fn run<'a>(filter: &'a Filter) -> Result<Vec<Box<dyn ToSql + 'a>>, FailedTo> {
|
||||||
let mut params: Vec<Box<dyn ToSql>> = Vec::new();
|
let mut params: Vec<Box<dyn ToSql>> = Vec::new();
|
||||||
for condition in filter.conditions() {
|
for condition in filter.conditions() {
|
||||||
let (_, comparison, condition) = condition;
|
let (name, comparison, condition) = condition;
|
||||||
|
params.push(Box::new(name));
|
||||||
match (comparison, condition) {
|
match (comparison, condition) {
|
||||||
// BOOL
|
// BOOL
|
||||||
(Comparison::Equal, Condition::Bool(value)) => params.push(Box::new(value)),
|
(Comparison::Equal, Condition::Bool(value)) => params.push(Box::new(value)),
|
||||||
|
|||||||
@@ -1,83 +1,82 @@
|
|||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
// TODO: possible sql injection for attribute_id!!!
|
|
||||||
|
|
||||||
const BASE_SELECT: &str = r#"SELECT * FROM entity"#;
|
const BASE_SELECT: &str = r#"SELECT * FROM entity"#;
|
||||||
const INNER_JOIN_FRAGMENT: &str = r#"
|
const INNER_JOIN_FRAGMENT: &str = r#"
|
||||||
INNER JOIN attribute as attribute_{index}
|
INNER JOIN attribute as attribute_{index}
|
||||||
ON entity.id = attribute_{index}.entity_id
|
ON entity.id = attribute_{index}.entity_id
|
||||||
AND attribute_{index}.id = '{attribute_id}'
|
AND attribute_{index}.id = ?{attribute_id_index}
|
||||||
AND attribute_{index}.{field} {op} ?{index}
|
AND attribute_{index}.{field} {op} ?{index}
|
||||||
"#;
|
"#;
|
||||||
const WHERE: &str = r#" WHERE 1=1"#;
|
const WHERE: &str = r#" WHERE 1=1"#;
|
||||||
|
|
||||||
fn compose_fragment(name: &str, field: &str, op: &str, index: usize) -> String {
|
fn compose_fragment(field: &str, op: &str, index: usize) -> String {
|
||||||
|
let attribute_index = index * 2 - 1;
|
||||||
|
let field_index = index * 2;
|
||||||
INNER_JOIN_FRAGMENT
|
INNER_JOIN_FRAGMENT
|
||||||
.replace("{attribute_id}", name)
|
|
||||||
.replace("{field}", field)
|
.replace("{field}", field)
|
||||||
.replace("{op}", op)
|
.replace("{op}", op)
|
||||||
.replace("{index}", &index.to_string())
|
.replace("{attribute_id_index}", &attribute_index.to_string())
|
||||||
|
.replace("{index}", &field_index.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_condition(
|
fn from_condition(
|
||||||
i: usize,
|
i: usize,
|
||||||
name: &str,
|
|
||||||
comparison: &Comparison,
|
comparison: &Comparison,
|
||||||
condition: &Condition,
|
condition: &Condition,
|
||||||
) -> Result<String, FailedTo> {
|
) -> Result<String, FailedTo> {
|
||||||
let fragment = match (comparison, condition) {
|
let fragment = match (comparison, condition) {
|
||||||
// BOOL
|
// BOOL
|
||||||
(Comparison::Equal, Condition::Bool(_)) => compose_fragment(name, "value_bool", "=", i),
|
(Comparison::Equal, Condition::Bool(_)) => compose_fragment("value_bool", "=", i),
|
||||||
(_, Condition::Bool(_)) => return Err(FailedTo::ComposeFilter),
|
(_, Condition::Bool(_)) => return Err(FailedTo::ComposeFilter),
|
||||||
// SIGNED INT
|
// SIGNED INT
|
||||||
(Comparison::Equal, Condition::SignedInt(_)) => compose_fragment(name, "value_int", "=", i),
|
(Comparison::Equal, Condition::SignedInt(_)) => compose_fragment("value_int", "=", i),
|
||||||
(Comparison::Greater, Condition::SignedInt(_)) => {
|
(Comparison::Greater, Condition::SignedInt(_)) => {
|
||||||
compose_fragment(name, "value_int", ">", i)
|
compose_fragment("value_int", ">", i)
|
||||||
}
|
}
|
||||||
(Comparison::Lesser, Condition::SignedInt(_)) => {
|
(Comparison::Lesser, Condition::SignedInt(_)) => {
|
||||||
compose_fragment(name, "value_int", "<", i)
|
compose_fragment("value_int", "<", i)
|
||||||
}
|
}
|
||||||
(Comparison::GreaterOrEqual, Condition::SignedInt(_)) => {
|
(Comparison::GreaterOrEqual, Condition::SignedInt(_)) => {
|
||||||
compose_fragment(name, "value_int", ">=", i)
|
compose_fragment("value_int", ">=", i)
|
||||||
}
|
}
|
||||||
(Comparison::LesserOrEqual, Condition::SignedInt(_)) => {
|
(Comparison::LesserOrEqual, Condition::SignedInt(_)) => {
|
||||||
compose_fragment(name, "value_int", "<=", i)
|
compose_fragment("value_int", "<=", i)
|
||||||
}
|
}
|
||||||
(_, Condition::SignedInt(_)) => return Err(FailedTo::ComposeFilter),
|
(_, Condition::SignedInt(_)) => return Err(FailedTo::ComposeFilter),
|
||||||
// UNSIGNED INT
|
// UNSIGNED INT
|
||||||
(Comparison::Equal, Condition::UnsignedInt(_)) => {
|
(Comparison::Equal, Condition::UnsignedInt(_)) => {
|
||||||
compose_fragment(name, "value_uint", "=", i)
|
compose_fragment("value_uint", "=", i)
|
||||||
}
|
}
|
||||||
(Comparison::Greater, Condition::UnsignedInt(_)) => {
|
(Comparison::Greater, Condition::UnsignedInt(_)) => {
|
||||||
compose_fragment(name, "value_uint", ">", i)
|
compose_fragment("value_uint", ">", i)
|
||||||
}
|
}
|
||||||
(Comparison::Lesser, Condition::UnsignedInt(_)) => {
|
(Comparison::Lesser, Condition::UnsignedInt(_)) => {
|
||||||
compose_fragment(name, "value_uint", "<", i)
|
compose_fragment("value_uint", "<", i)
|
||||||
}
|
}
|
||||||
(Comparison::GreaterOrEqual, Condition::UnsignedInt(_)) => {
|
(Comparison::GreaterOrEqual, Condition::UnsignedInt(_)) => {
|
||||||
compose_fragment(name, "value_uint", ">=", i)
|
compose_fragment("value_uint", ">=", i)
|
||||||
}
|
}
|
||||||
(Comparison::LesserOrEqual, Condition::UnsignedInt(_)) => {
|
(Comparison::LesserOrEqual, Condition::UnsignedInt(_)) => {
|
||||||
compose_fragment(name, "value_uint", "<=", i)
|
compose_fragment("value_uint", "<=", i)
|
||||||
}
|
}
|
||||||
(_, Condition::UnsignedInt(_)) => return Err(FailedTo::ComposeFilter),
|
(_, Condition::UnsignedInt(_)) => return Err(FailedTo::ComposeFilter),
|
||||||
// REAL
|
// REAL
|
||||||
(Comparison::Equal, Condition::Real(_)) => compose_fragment(name, "value_real", "=", i),
|
(Comparison::Equal, Condition::Real(_)) => compose_fragment("value_real", "=", i),
|
||||||
(Comparison::Greater, Condition::Real(_)) => compose_fragment(name, "value_real", ">", i),
|
(Comparison::Greater, Condition::Real(_)) => compose_fragment("value_real", ">", i),
|
||||||
(Comparison::Lesser, Condition::Real(_)) => compose_fragment(name, "value_real", "<", i),
|
(Comparison::Lesser, Condition::Real(_)) => compose_fragment("value_real", "<", i),
|
||||||
(Comparison::GreaterOrEqual, Condition::Real(_)) => {
|
(Comparison::GreaterOrEqual, Condition::Real(_)) => {
|
||||||
compose_fragment(name, "value_real", ">=", i)
|
compose_fragment("value_real", ">=", i)
|
||||||
}
|
}
|
||||||
(Comparison::LesserOrEqual, Condition::Real(_)) => {
|
(Comparison::LesserOrEqual, Condition::Real(_)) => {
|
||||||
compose_fragment(name, "value_real", "<=", i)
|
compose_fragment("value_real", "<=", i)
|
||||||
}
|
}
|
||||||
(_, Condition::Real(_)) => return Err(FailedTo::ComposeFilter),
|
(_, Condition::Real(_)) => return Err(FailedTo::ComposeFilter),
|
||||||
// TEXT
|
// TEXT
|
||||||
(Comparison::IsExactly, Condition::Text(_)) => compose_fragment(name, "value_text", "=", i),
|
(Comparison::IsExactly, Condition::Text(_)) => compose_fragment("value_text", "=", i),
|
||||||
(
|
(
|
||||||
Comparison::StartsWith | Comparison::EndsWith | Comparison::Contains,
|
Comparison::StartsWith | Comparison::EndsWith | Comparison::Contains,
|
||||||
Condition::Text(_),
|
Condition::Text(_),
|
||||||
) => compose_fragment(name, "value_text", "LIKE", i),
|
) => compose_fragment("value_text", "LIKE", i),
|
||||||
(_, Condition::Text(_)) => return Err(FailedTo::ComposeFilter),
|
(_, Condition::Text(_)) => return Err(FailedTo::ComposeFilter),
|
||||||
};
|
};
|
||||||
Ok(fragment)
|
Ok(fragment)
|
||||||
@@ -88,9 +87,9 @@ pub fn run(filter: &Filter) -> Result<String, FailedTo> {
|
|||||||
let mut statement = String::from(BASE_SELECT);
|
let mut statement = String::from(BASE_SELECT);
|
||||||
let mut idx = 0;
|
let mut idx = 0;
|
||||||
// for each condition add an inner join fragment
|
// for each condition add an inner join fragment
|
||||||
for (i, (name, comparison, condition)) in filter.conditions().enumerate() {
|
for (i, (_, comparison, condition)) in filter.conditions().enumerate() {
|
||||||
idx = i + 1;
|
idx = i + 1;
|
||||||
let fragment = from_condition(idx, name, comparison, condition)?;
|
let fragment = from_condition(idx, comparison, condition)?;
|
||||||
statement.push_str(&fragment);
|
statement.push_str(&fragment);
|
||||||
}
|
}
|
||||||
// add a neutral where condition
|
// add a neutral where condition
|
||||||
|
|||||||
Reference in New Issue
Block a user