To ensure application security, we use mechanisms such as authentication and authorization. I think many of you are familiar with these concepts and in this article we will focus on the concept of authorization and related access control models.
Definitions of terms used in this article
It is important to understand the differences between authorization and authentication:
– , ( , ).
– , .
– , .
– , , .
(Crate) – Rust.
The authorization process includes the concept of an access control policy , in accordance with which a set of permissible actions of a specific user ( access subject ) over the system resources ( access object ) is determined .
And also the access control model - a general scheme for delimiting access through a user policy, which we choose depending on various factors and system requirements.
Let's take a look at the basic access control models:
DAC ( Discretionary access-control ) - selective (discretionary) access control
- , (ACL).
, .
, .
MAC (Mandatory access-control) –
(, ), .
( ), . .
, MAC , ( , ).
RBAC (Role-Based access-control) –
, - . DAC, .
, .
, RBAC PBAC (Permission-Based access-control) , (: READ_DOCUMENT
, WRITE_DOCUMENT
, DELETE_DOCUMENT
) , – .
ABAC (Attribute-Based access-control) –
, , .
, , , , .., .
ABAC , ( ) ( ).
OWASP (Open Web Application Security Project) IBM.
, , .
- Rust?
, - (, actix-web, Rocket tide), Middleware, FromRequest Guard (Filter warp).
, . , .
, . , , .
casbin-rs
Casbin – production-ready , , ( ACL, RBAC, ABAC) .
casbin - PERM (Policy, Effect, Request, Matchers) , , .
# Request definition
[request_definition]
r = sub, obj, act
# Policy definition
[policy_definition]
p = sub, obj, act
# Policy effect
[policy_effect]
e = some(where (p.eft == allow))
# Matchers
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
, -
( ), PERM .
p, alice, data1, read p, bob, data2, write
, .
use casbin::prelude::*;
#[tokio::main]
async fn main() -> () {
let mut e = Enforcer::new("examples/acl_model.conf", "examples/acl_policy.csv").await?;
e.enable_log(true);
let sub = "alice"; // the user that wants to access a resource.
let obj = "data1"; // the resource that is going to be accessed.
let act = "read"; // the operation that the user performs on the resource.
if let Ok(authorized) = e.enforce((sub, obj, act)) {
if authorized {
// permit alice to read data1
} else {
// deny the request
}
} else {
// error occurs
}
}
. , !
, , , , , , , .
, backend Rust. PBAC -, ACL/RBAC.
actix-web-grants
, , , : (ACL), (RBAC/PBAC).
, :
// Sample application with grant protection based on extracting by your custom function
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
let auth = GrantsMiddleware::with_extractor(extract);
App::new()
.wrap(auth)
.service(index)
})
.bind("localhost:8081")?
.run()
.await
}
async fn extract(_req: &ServiceRequest) -> Result<Vec<String>, Error> {
// Here is a place for your code to get user permissions/grants/permissions from a request
// For example from a token or database
// Stub example
Ok(vec![ROLE_ADMIN.to_string()])
}
: JWT-, , .
:
use actix_web_grants::proc_macro::{has_roles};
#[get("/secure")]
#[has_roles("ROLE_ADMIN")]
async fn macro_secured() -> HttpResponse {
HttpResponse::Ok().body("ADMIN_RESPONSE")
}
actix-web-grants, .
, ( wrk) .
RBAC - : , . . GitHub: actix-web-authz-benchmark ( ).
:
|
casbin-rs |
actix-web-grants |
||
Latency |
Req/Sec |
Latency |
Req/Sec |
|
Allowed Endpoint |
6.18 ms |
16.27k |
4.41 ms |
22.69k |
Denied Endpoint |
6.70 ms |
14.98k |
4.94 ms |
20.23k |
rustc: v1.52.0 (stable); CPU: 2,6 GHz 6-Core Intel Core i7; RAM: 16 GB
, , actix-web-grants (endpoints), casbin-rs.
Post Scriptum
This library does not yet have integrations with many web frameworks in its arsenal, but I have plans to introduce some abstractions and write modules for other frameworks, make some improvements (for example, the ability to inherit roles and support custom types). Any suggestions and contributions will be welcome!