B-Arts DocumentationIndice generale

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 con SetCryptPassword.

  • 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 Unauthorized quando 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.