BApiServiceSecureKey - esempi
Registrazione nel servizio Web API
using B.BWebApi;
builder.Services.AddHttpContextAccessor();
builder.Services.AddScoped<BApiServiceSecureKey>();
Per impostazione predefinita BApiServiceSecureKey legge il primo valore dell'header B-SECURE-KEY. Il nome può essere personalizzato tramite KeyHeaderSecureKey, ma client e server devono usare lo stesso valore.
Validazione server con BCrypter
using B.BSecurity;
using B.BWebApi;
public sealed class SecureKeyValidator
{
private readonly BApiServiceSecureKey secureKeyReader;
private readonly IConfiguration configuration;
public SecureKeyValidator(
BApiServiceSecureKey secureKeyReader,
IConfiguration configuration)
{
this.secureKeyReader = secureKeyReader;
this.configuration = configuration;
}
public bool IsAuthorized()
{
string? suppliedSecureKey = secureKeyReader.GetSecureKey();
string encryptedSharedKey =
configuration["BArts:EncryptedSharedKey"] ?? "";
string expectedSecureKey =
BCrypter.GetSecurePassword(encryptedSharedKey);
return BCrypter.CheckSecurePassword(
expectedSecureKey,
suppliedSecureKey ?? "",
TimeExpired: 5);
}
}
La configurazione contiene la chiave condivisa già cifrata con BCrypter.Encrypt. GetSecurePassword la decifra, aggiunge data e ora UTC con precisione al minuto e cifra nuovamente il risultato. Il server genera lo stesso tipo di valore temporale e CheckSecurePassword verifica sia la chiave originaria sia la distanza temporale.
Endpoint protetto
[ApiController]
[Route("api/[controller]")]
public sealed class CustomersController : ControllerBase
{
private readonly SecureKeyValidator validator;
public CustomersController(SecureKeyValidator validator)
{
this.validator = validator;
}
[HttpGet]
public IActionResult GetCustomers()
{
if (!validator.IsAuthorized())
return Unauthorized();
return Ok(CaricaClienti());
}
}
Chiamata client con HttpClient
using B.BSecurity;
using System.Net.Http.Headers;
string encryptedSharedKey = configurazione.EncryptedSharedKey;
string secureKey = BCrypter.GetSecurePassword(encryptedSharedKey);
using HttpRequestMessage request = new(
HttpMethod.Get,
"https://api.example.it/api/customers");
request.Headers.Add("B-SECURE-KEY", secureKey);
using HttpResponseMessage response = await httpClient.SendAsync(request);
if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
GestisciAccessoNegato();
return;
}
response.EnsureSuccessStatusCode();
string json = await response.Content.ReadAsStringAsync();
Generare secureKey immediatamente prima della chiamata. Non riutilizzare intenzionalmente lo stesso valore oltre la finestra temporale configurata.
Chiamata JSON POST
string secureKey = BCrypter.GetSecurePassword(encryptedSharedKey);
using HttpRequestMessage request = new(
HttpMethod.Post,
"https://api.example.it/api/customers");
request.Headers.Add("B-SECURE-KEY", secureKey);
request.Content = JsonContent.Create(customer);
using HttpResponseMessage response = await httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
La secure key può essere inviata anche in una proprietà SecureKey di un oggetto derivato da BBaseObject, come avviene in alcuni progetti storici. Per le nuove API è preferibile l'header, perché mantiene la credenziale separata dal contenuto applicativo.
Regole operative
Usare sempre HTTPS: la cifratura della secure key non sostituisce la protezione TLS dell'intera richiesta.
Client e server devono usare la stessa chiave cifrata e la stessa password globale di
BCrypter, se personalizzata conSetCryptPassword.Gli orologi devono essere sincronizzati; il confronto usa UTC e una tolleranza predefinita di 5 minuti.
Non registrare nei log la chiave condivisa, la secure key ricevuta o quella generata dal server.
Restituire
401 Unauthorizedquando l'header è assente, scaduto, malformato o deriva da una chiave diversa.Non disabilitare il controllo automaticamente negli ambienti di debug esposti in rete.
BApiServiceSecureKey estrae soltanto l'header. La validazione del protocollo viene effettuata da BCrypter.CheckSecurePassword.
