Socket
Book a DemoInstallSign in
Socket

CloakId.AspNetCore

Package Overview
Dependencies
Maintainers
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

CloakId.AspNetCore

ASP.NET Core integration for CloakId - includes model binding, OpenAPI/Swagger support, and metrics for obfuscated IDs.

Source
nugetNuGet
Version
0.2.0
Version published
Maintainers
1
Created
Source

CloakId logo

CloakId

A .NET library that provides automatic encoding/decoding of numeric properties to obfuscated strings during JSON serialization using attributes. This helps prevent exposing internal numeric IDs in APIs while maintaining clean, readable code.

Features

  • Attribute-based: Simply mark properties with [Cloak] to enable encoding
  • Automatic JSON conversion: Properties are automatically encoded to strings during serialization and decoded back during deserialization
  • Pluggable encoding: Support for different encoding strategies (Sqids provided out of the box)
  • Dependency injection: Full integration with Microsoft.Extensions.DependencyInjection
  • Type safety: Compile-time type checking with support for all numeric types
  • Nullable support: Full support for nullable numeric types

Why This Library is Useful

While CloakId is not a substitute for proper security measures like authentication, authorization, and access control, it provides valuable protection against information disclosure and business intelligence gathering.

Business Intelligence Protection

The German Tank Problem: During WWII, Allied forces estimated German tank production by analyzing captured tank serial numbers. By observing the highest serial number and using statistical analysis, they could accurately determine total production numbers and manufacturing rates. This same principle applies to modern web applications.

Real-World Scenarios

Competitor Analysis:

  • A competitor signs up for your service and receives user ID 12345
  • One month later, they create another account and receive user ID 15678
  • Without obfuscation: They now know you gained ~3,333 users that month
  • With CloakId: They see IDs like A6das1 and xnF9Hu - no business intelligence can be extracted

Resource Enumeration:

  • Attackers often probe sequential IDs to map your system: /api/users/1, /api/users/2, etc.
  • Without obfuscation: Reveals total user count, active vs. deleted accounts, growth patterns
  • With CloakId: Each ID appears random, preventing systematic enumeration

Remember: CloakId adds a defense-in-depth layer to make unauthorized reconnaissance significantly more difficult - it does not replace fundamental security practices.

How It Works

CloakId provides a completely unintrusive solution by working transparently at the serialization boundary:

The Magic Happens at the Boundary:

  • JSON Serialization: Automatic conversion from numbers → encoded strings
  • JSON Deserialization: Automatic conversion from encoded strings → numbers
  • Model Binding: Route parameters automatically decoded (/users/A6das1id: 12345)

This boundary-based approach provides clean separation between your client and server code:

On the Server Side:

  • Your business logic works with native numeric types (int, long, etc.)
  • No wrapper types, no special handling required
  • Code remains clean and type-safe

On the Client Side:

  • APIs receive and send encoded strings ("A6das1", "xnF9Hu")
  • No knowledge of internal numeric values
  • Consistent string-based interface

Quick Start

1. Install the NuGet packages

Install the packages using Package Manager Console:

Install-Package CloakId
Install-Package CloakId.Sqids

Alternatively, using the .NET CLI:

dotnet add package CloakId
dotnet add package CloakId.Sqids

2. Configure services

using CloakId;
using CloakId.Sqids;
using Microsoft.Extensions.DependencyInjection;

var services = new ServiceCollection();
services.AddCloakId().WithSqids(options => 
{
    options.MinLength = 6; // Configure minimum length
    // options.Alphabet = "custom123456789abcdefghijk"; // Custom alphabet (optional)
});

var serviceProvider = services.BuildServiceProvider();

3. Use the attribute in your DTOs

public class UserDto
{
    [Cloak]
    public int UserId { get; set; }

    [Cloak]
    public long AccountId { get; set; }    // Regular properties without the attribute remain unchanged
    public int RegularId { get; set; }
    
    public string Name { get; set; }
    
    [Cloak]
    public int? OptionalId { get; set; }
}

4. Configure JSON serialization

var typeInfoResolver = serviceProvider.GetRequiredService<CloakIdTypeInfoResolver>();

var jsonOptions = new JsonSerializerOptions
{
    TypeInfoResolver = typeInfoResolver
};

5. Serialize/Deserialize

var user = new UserDto
{
    UserId = 12345,
    AccountId = 98765432109876,
    RegularId = 999, // This remains as a number
    Name = "John Doe",
    OptionalId = 42
};

// Serialize - only [Cloak] properties become encoded strings
var json = JsonSerializer.Serialize(user, jsonOptions);
// Result: {"UserId":"A6das1","AccountId":"xnF9HulfM","RegularId":999,"Name":"John Doe","OptionalId":"JgaEBg"}

// Deserialize - strings decode back to original values
var deserializedUser = JsonSerializer.Deserialize<UserDto>(json, jsonOptions);
// deserializedUser.UserId == 12345
// deserializedUser.AccountId == 98765432109876
// deserializedUser.RegularId == 999 (unchanged)

Supported Types

The [Cloak] attribute can be applied to the following numeric property types:

  • int and int?
  • uint and uint?
  • long and long?
  • ulong and ulong?
  • short and short?
  • ushort and ushort?

Direct Codec Usage

You can also use the codec directly for manual encoding/decoding:

var codec = serviceProvider.GetRequiredService<ICloakIdCodec>();

var originalValue = 12345;
var encoded = codec.Encode(originalValue, typeof(int)); // "A6das1"
var decoded = (int)codec.Decode(encoded, typeof(int)); // 12345

ASP.NET Core Model Binding

CloakId includes built-in support for ASP.NET Core model binding, allowing automatic conversion of encoded route parameters:

// Enable model binding in Program.cs
builder.Services.AddCloakId().WithSqids();
builder.Services.AddControllers().AddCloakIdModelBinding();

// Use in controllers
[HttpGet("{id}")]
public IActionResult GetUser([Cloak] int id) // Automatically converts "A6das1" → 12345
{
    return Ok(new { UserId = id });
}

Routes like GET /api/users/A6das1 will automatically convert the encoded string to the numeric ID before reaching your controller method. See Model Binding Documentation for complete details.

Security Configuration

CloakId provides configurable security options for model binding:

// Configure fallback behavior for enhanced security
builder.Services.AddControllers().AddCloakIdModelBinding(options =>
{
    // Disable numeric fallback for better security (default: false)
    // When false: only accepts encoded strings, rejects numeric IDs
    // When true: accepts both encoded strings and numeric IDs (backwards compatibility)
    options.AllowNumericFallback = false;
});

Security Note: Setting AllowNumericFallback = false provides better security by rejecting any non-encoded values, but may break existing clients that send numeric IDs. The fallback behavior could potentially expose alphabet patterns through systematic testing.

Metrics and Monitoring

CloakId includes built-in metrics using System.Diagnostics.Metrics for monitoring security-related behavior:

Available Metrics

  • cloakid_model_binding_decoding_success_total - Successful decodings
  • cloakid_model_binding_decoding_failure_total - Failed decodings
  • cloakid_model_binding_numeric_fallback_total - Security-relevant: Fallback usage
  • cloakid_model_binding_fallback_rejection_total - Rejected requests when fallback disabled
  • cloakid_model_binding_decoding_duration_ms - Decoding performance

The numeric fallback metric is particularly important for security monitoring as it can indicate potential attempts to probe the encoding alphabet through systematic testing.

Configuration Options

Fluent Configuration

// With Sqids
services.AddCloakId().WithSqids(options =>
{
    options.Alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; // Custom alphabet
    options.MinLength = 8; // Minimum length of encoded strings
});

// With custom codec
services.AddCloakId().WithCustomCodec<MyCustomCodec>();

// With pre-registered Sqids
services.AddCloakId().WithRegisteredSqids();

Using Pre-registered Sqids

If you already have Sqids encoders registered in your DI container:

// First register your Sqids encoders
services.AddSingleton(new SqidsEncoder<int>(new SqidsOptions { /* your config */ }));
// ... register other encoders

// Then use the registered encoders
services.AddCloakId().WithRegisteredSqids();

Important: You cannot call both WithSqids() and WithRegisteredSqids() on the same builder. The second call will throw an InvalidOperationException to prevent conflicting codec registrations.

Custom Codecs

You can implement your own encoding strategy by implementing ICloakIdCodec:

public class MyCustomCodec : ICloakIdCodec
{
    public string Encode(object value, Type valueType) { /* ... */ }
    public object Decode(string encodedValue, Type targetType) { /* ... */ }
}

Using a Custom Codec

// Register custom codec by type
services.AddCloakId().WithCustomCodec<MyCustomCodec>();

// Register custom codec by instance
var myCodec = new MyCustomCodec();
services.AddCloakId().WithCustomCodec(myCodec);

// Register custom codec with factory
services.AddCloakId().WithCustomCodec(provider => 
{
    var someService = provider.GetRequiredService<ISomeService>();
    return new MyCustomCodec(someService);
});

Example Output

When serialized to JSON, your attributed properties will look like this:

{
  "UserId": "A6das1",
  "AccountId": "xnF9HulfM",
  "RegularId": 999,
  "Name": "John Doe",
  "OptionalId": "JgaEBg"
}

Instead of exposing the raw numeric values:

{
  "UserId": 12345,
  "AccountId": 98765432109876,
  "RegularId": 999,
  "Name": "John Doe", 
  "OptionalId": 42
}

Notice how only the properties marked with [Cloak] are encoded, while RegularId remains as a number.

Performance

CloakId is designed for performance with minimal overhead. You can run comprehensive benchmarks to see the performance characteristics:

Running Benchmarks

# Run all benchmarks
./run-benchmarks.ps1

# Run only encoding/decoding benchmarks
./run-benchmarks.ps1 "*Encode*"

# Run only JSON serialization benchmarks  
./run-benchmarks.ps1 "*Json*"

# Run only happy path tests
./run-benchmarks.ps1 "*HappyPath*"

# Run only error handling tests
./run-benchmarks.ps1 "*SadPath*"

# Quick validation run
./run-benchmarks.ps1 "*" --dry

Sample Results

Based on benchmarks, typical performance characteristics:

  • Encoding: ~4 microseconds per int32 value
  • JSON Serialization: ~40 microseconds for small models
  • Memory allocation: ~21KB allocated per serialization of typical models
  • Error handling: Fast exception handling for invalid data

See /benchmarks/README.md for detailed benchmark information.

Benefits

  • Security: Internal numeric IDs are not exposed in API responses
  • Clean Code: Simple attribute-based approach, no wrapper types needed
  • Selective: Choose exactly which properties to encode
  • Type Safety: Full support for nullable types and type checking
  • Performance: Efficient encoding/decoding with minimal overhead
  • Flexibility: Easy to swap encoding strategies without changing business logic

License

This project is licensed under the MIT License - see the LICENSE file for details.

Keywords

id-obfuscation

FAQs

Package last updated on 07 Aug 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

About

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.

  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc

U.S. Patent No. 12,346,443 & 12,314,394. Other pending.