feat(backend): built basic sql connection infrastructure and added sql injection protection

This commit is contained in:
antifallobst 2023-08-12 16:55:13 +02:00
parent 64d3f29931
commit 45c46d19db
Signed by: antifallobst
GPG Key ID: 2B4F402172791BAF
8 changed files with 306 additions and 18 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
/target /target
test.sqlite

242
Cargo.lock generated
View File

@ -284,10 +284,34 @@ version = "0.1.0"
dependencies = [ dependencies = [
"actix-web", "actix-web",
"anyhow", "anyhow",
"libinjection",
"serde", "serde",
"sqlite",
"tokio", "tokio",
] ]
[[package]]
name = "bindgen"
version = "0.63.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36d860121800b2a9a94f9b5604b332d5cffb234ce17609ea479d723dbc9d3885"
dependencies = [
"bitflags",
"cexpr",
"clang-sys",
"lazy_static",
"lazycell",
"log",
"peeking_take_while",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"syn 1.0.109",
"which",
]
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.3.2" version = "1.3.2"
@ -349,12 +373,32 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "cexpr"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom",
]
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.0" version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clang-sys"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f"
dependencies = [
"glob",
"libc",
"libloading",
]
[[package]] [[package]]
name = "convert_case" name = "convert_case"
version = "0.4.0" version = "0.4.0"
@ -429,6 +473,12 @@ dependencies = [
"crypto-common", "crypto-common",
] ]
[[package]]
name = "either"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]] [[package]]
name = "encoding_rs" name = "encoding_rs"
version = "0.8.32" version = "0.8.32"
@ -520,6 +570,27 @@ version = "0.27.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
[[package]]
name = "git2"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2994bee4a3a6a51eb90c218523be382fd7ea09b16380b9312e9dbe955ff7c7d1"
dependencies = [
"bitflags",
"libc",
"libgit2-sys",
"log",
"openssl-probe",
"openssl-sys",
"url",
]
[[package]]
name = "glob"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]] [[package]]
name = "h2" name = "h2"
version = "0.3.20" version = "0.3.20"
@ -615,12 +686,84 @@ version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "lazycell"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.147" version = "0.2.147"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
[[package]]
name = "libgit2-sys"
version = "0.14.2+1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f3d95f6b51075fe9810a7ae22c7095f12b98005ab364d8544797a825ce946a4"
dependencies = [
"cc",
"libc",
"libssh2-sys",
"libz-sys",
"openssl-sys",
"pkg-config",
]
[[package]]
name = "libinjection"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6a9a90ce65224c87515f603d1eed413909886dec98f2e9985044f0b88e26039"
dependencies = [
"bindgen",
"git2",
]
[[package]]
name = "libloading"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
dependencies = [
"cfg-if",
"winapi",
]
[[package]]
name = "libssh2-sys"
version = "0.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b094a36eb4b8b8c8a7b4b8ae43b2944502be3e59cd87687595cf6b0a71b3f4ca"
dependencies = [
"cc",
"libc",
"libz-sys",
"openssl-sys",
"pkg-config",
"vcpkg",
]
[[package]]
name = "libz-sys"
version = "1.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]] [[package]]
name = "local-channel" name = "local-channel"
version = "0.1.3" version = "0.1.3"
@ -667,6 +810,12 @@ version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.7.1" version = "0.7.1"
@ -688,6 +837,16 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]] [[package]]
name = "num_cpus" name = "num_cpus"
version = "1.16.0" version = "1.16.0"
@ -713,6 +872,24 @@ version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "openssl-probe"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-sys"
version = "0.9.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "866b5f16f90776b9bb8dc1e1802ac6f0513de3a7a7465867bfbc563dc737faac"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.12.1" version = "0.12.1"
@ -742,6 +919,12 @@ version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
[[package]]
name = "peeking_take_while"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
[[package]] [[package]]
name = "percent-encoding" name = "percent-encoding"
version = "2.3.0" version = "2.3.0"
@ -864,6 +1047,12 @@ version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]] [[package]]
name = "rustc_version" name = "rustc_version"
version = "0.4.0" version = "0.4.0"
@ -945,6 +1134,12 @@ dependencies = [
"digest", "digest",
] ]
[[package]]
name = "shlex"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
[[package]] [[package]]
name = "signal-hook-registry" name = "signal-hook-registry"
version = "1.4.1" version = "1.4.1"
@ -989,6 +1184,36 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "sqlite"
version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3ddda64c469a257a3b31298805427784d992c226c94b81003f96e8b122286ad"
dependencies = [
"libc",
"sqlite3-sys",
]
[[package]]
name = "sqlite3-src"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfc95a51a1ee38839599371685b9d4a926abb51791f0bc3bf8c3bb7867e6e454"
dependencies = [
"cc",
"pkg-config",
]
[[package]]
name = "sqlite3-sys"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2752c669433e40ebb08fde824146f50d9628aa0b66a3b7fc6be34db82a8063b"
dependencies = [
"libc",
"sqlite3-src",
]
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.109" version = "1.0.109"
@ -1157,6 +1382,12 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.4" version = "0.9.4"
@ -1169,6 +1400,17 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "which"
version = "4.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269"
dependencies = [
"either",
"libc",
"once_cell",
]
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"

View File

@ -11,3 +11,5 @@ tokio = { version = "1.29", features = ["macros", "rt-multi-thread", "sync"] }
anyhow = "1.0" anyhow = "1.0"
actix-web = "4" actix-web = "4"
serde = { version = "1.0.183", features = ["derive"] } serde = { version = "1.0.183", features = ["derive"] }
sqlite = "0.31.0"
libinjection = "0.3.2"

View File

@ -22,9 +22,10 @@ Registers a new account.
#### Responses #### Responses
| Response | Description | | Response | Description |
|----------|------------------------------------------| |----------|----------------------------------------------------------|
| 200 | User created successfully | | 200 | User created successfully |
| 400 | Formal error in the request | | 400 | Formal error in the request |
| 403 | Rejected for security reasons (sql injection protection) |
| 409 | The requested username is already in use | | 409 | The requested username is already in use |
| 500 | Internal server error | | 500 | Internal server error |
@ -32,7 +33,7 @@ Registers a new account.
### `/authenticate` ### `/authenticate`
Authenticates using an existing account. Authenticates using an existing account.
#### Payload #### Content / Payload
| Field | Description | | Field | Description |
|------------|-----------------------------------| |------------|-----------------------------------|
@ -42,10 +43,11 @@ Authenticates using an existing account.
#### Responses #### Responses
| Response | Description | | Response | Description |
|----------|----------------------------------------------------| |----------|----------------------------------------------------------|
| 200 | Authenticated successfully | | 200 | Authenticated successfully |
| 400 | Formal error in the request | | 400 | Formal error in the request |
| 401 | Authentication failure (wrong password) | | 401 | Authentication failure (wrong password) |
| 403 | Rejected for security reasons (sql injection production) |
| 404 | There was no account found with the specified name | | 404 | There was no account found with the specified name |
| 500 | Internal server error | | 500 | Internal server error |

View File

@ -18,6 +18,7 @@ struct AuthenticateData {
/// Possible Responses: /// Possible Responses:
/// * 200 -> Authentication was successfull /// * 200 -> Authentication was successfull
/// * 401 -> Authentication failed (wrong password) /// * 401 -> Authentication failed (wrong password)
/// * 403 -> The request was rejected due to security reasons
/// * 404 -> User not found /// * 404 -> User not found
/// * 500 -> Internal Server Error /// * 500 -> Internal Server Error
#[post("/authenticate")] #[post("/authenticate")]
@ -44,6 +45,7 @@ async fn authenticate(
ResponseAuthenticate::Success => HttpResponse::Ok().finish(), ResponseAuthenticate::Success => HttpResponse::Ok().finish(),
ResponseAuthenticate::UserNotFound => HttpResponse::NotFound().finish(), ResponseAuthenticate::UserNotFound => HttpResponse::NotFound().finish(),
ResponseAuthenticate::WrongPassword => HttpResponse::Unauthorized().finish(), ResponseAuthenticate::WrongPassword => HttpResponse::Unauthorized().finish(),
ResponseAuthenticate::Rejected => HttpResponse::Forbidden().finish(),
}, },
_ => HttpResponse::InternalServerError().finish(), _ => HttpResponse::InternalServerError().finish(),
}, },
@ -59,6 +61,7 @@ struct RegisterData {
/// Possible Responses: /// Possible Responses:
/// * 200 -> User created successfully /// * 200 -> User created successfully
/// * 403 -> The request was rejected due to security reasons
/// * 409 -> The requested username is already in use /// * 409 -> The requested username is already in use
/// * 500 -> Internal Server Error /// * 500 -> Internal Server Error
#[post("/register")] #[post("/register")]
@ -81,6 +84,7 @@ async fn register(data: web::Data<ApiState>, body: web::Json<RegisterData>) -> i
Response::Register(r) => match r { Response::Register(r) => match r {
ResponseRegister::Success => HttpResponse::Ok().finish(), ResponseRegister::Success => HttpResponse::Ok().finish(),
ResponseRegister::NameAlreadyInUse => HttpResponse::Conflict().finish(), ResponseRegister::NameAlreadyInUse => HttpResponse::Conflict().finish(),
ResponseRegister::Rejected => HttpResponse::Forbidden().finish(),
}, },
_ => HttpResponse::InternalServerError().finish(), _ => HttpResponse::InternalServerError().finish(),
}, },

View File

@ -1,11 +1,25 @@
use anyhow::Result; use anyhow::Result;
use libinjection::sqli;
use crate::call::{Response, ResponseAuthenticate, ResponseDelete, ResponseRegister}; use crate::call::{Response, ResponseAuthenticate, ResponseDelete, ResponseRegister};
pub struct Backend {} pub struct Backend {
db: sqlite::Connection,
}
fn is_sql_injection(string: &String) -> bool {
match sqli(string) {
Some((is_injection, _)) => is_injection,
None => true, // this could be a false positive, but that would be better than an SQLi
}
}
impl Backend { impl Backend {
pub fn register(&mut self, username: &String, password: &String) -> Result<Response> { pub fn register(&mut self, username: &String, password: &String) -> Result<Response> {
if is_sql_injection(username) {
return Ok(Response::Register(ResponseRegister::Rejected));
}
println!( println!(
"<Dummy> Registered Account: (Username: '{}' | Password: '{}')", "<Dummy> Registered Account: (Username: '{}' | Password: '{}')",
username, password username, password
@ -14,6 +28,10 @@ impl Backend {
} }
pub fn authenticate(&mut self, username: &String, password: &String) -> Result<Response> { pub fn authenticate(&mut self, username: &String, password: &String) -> Result<Response> {
if is_sql_injection(username) {
return Ok(Response::Authenticate(ResponseAuthenticate::Rejected));
}
println!( println!(
"<Dummy> Authentication Request: (Username: '{}' | Password: '{}')", "<Dummy> Authentication Request: (Username: '{}' | Password: '{}')",
username, password username, password
@ -23,12 +41,28 @@ impl Backend {
} }
pub fn delete(&mut self, username: &String) -> Result<Response> { pub fn delete(&mut self, username: &String) -> Result<Response> {
if is_sql_injection(username) {
return Ok(Response::Delete(ResponseDelete::Rejected));
}
println!("<Dummy> Deletion Request: (Username: '{}')", username); println!("<Dummy> Deletion Request: (Username: '{}')", username);
println!(" -> Accepted"); println!(" -> Accepted");
Ok(Response::Delete(ResponseDelete::Success)) Ok(Response::Delete(ResponseDelete::Success))
} }
pub fn new() -> Result<Self> { pub fn new(database: &std::path::Path) -> Result<Self> {
Ok(Self {}) let conn = sqlite::open(database)?;
conn.execute(
"CREATE TABLE IF NOT EXISTS BaseAuth (
id INTEGER,
username TEXT,
salt TEXT,
password TEXT,
PRIMARY KEY(id)
);",
)?;
Ok(Self { db: conn })
} }
} }

View File

@ -14,6 +14,7 @@ pub enum Call {
pub enum ResponseRegister { pub enum ResponseRegister {
Success, Success,
NameAlreadyInUse, NameAlreadyInUse,
Rejected,
} }
#[derive(Debug)] #[derive(Debug)]
@ -21,12 +22,14 @@ pub enum ResponseAuthenticate {
Success, Success,
UserNotFound, UserNotFound,
WrongPassword, WrongPassword,
Rejected,
} }
#[derive(Debug)] #[derive(Debug)]
pub enum ResponseDelete { pub enum ResponseDelete {
Success, Success,
UserNotFound, UserNotFound,
Rejected,
} }
#[derive(Debug)] #[derive(Debug)]

View File

@ -8,7 +8,7 @@ use anyhow::Result;
async fn main() -> Result<()> { async fn main() -> Result<()> {
println!("Starting BaseAuth server v0.1"); println!("Starting BaseAuth server v0.1");
let backend = backend::Backend::new()?; let backend = backend::Backend::new(&std::path::Path::new("test.sqlite"))?;
let tx = call::start_worker(backend).await?; let tx = call::start_worker(backend).await?;
api::start_worker(8080, tx).await?; api::start_worker(8080, tx).await?;