Skip to content

Latest commit

 

History

12 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ProtectedNumbers

ProtectedNumbers

Coverage GitHub Repo stars GitHub contributors GitHub last commit GitHub commit activity open issues .NET PRs Welcome

A .NET library for safe, opaque numeric identifiers you can pass through URLs, JSON, and model binding

What problem it solved

When working with a legacy database, most often primary keys are sequential numbers like this:

{
  "id": "4018378694012108869",
  "name": "some data row"
}

And if you expose the data as is on a public endpoint, an attacker can guess easily other identifiers:

{
  "id": "4018378694012108868",
  "name": "oops some other row"
}

There are ways to mitigate this problem. One of them is to make identifiers unguessable:

{
  "id": "CfDJ8K3W-Fa_koRAlAI935b9MJjgVrkgEMGZ5bvAPECdKZvgMpUPsvhVru9een2MVC0P8e4N4ehwgKgueAGjZlEP4s7gu3AsBLRoQrnUZr8hw4qZYAr-StAlQWCfx2FHTs1EGgEpB3T9YPSGxAxm0XVP7Mc",
  "name": "some data row"
}

What is ProtectedNumbers

  • ProtectedNumbers provides a lightweight struct, ProtectedNumber, that carries either a raw numeric value (long) or a protected string representation (for example for URLs or JSON), and can safely round-trip between the two with application-provided protection.
  • First-class ASP.NET Core integration is included:
    • Dependency injection helpers via services.AddProtectedNumbers().
    • MVC model binding for ProtectedNumber and ProtectedNumber? parameters.
    • System.Text.Json support.
  • Supported target frameworks: net6.0, net8.0, net9.0.

Key semantics of ProtectedNumber:

  • Dual representation: Value (long) and ProtectedValue (string). Either side can be present independently.
  • Empty sentinel: ProtectedNumber.Empty is initialized but HasValue == false and HasProtectedValue == false. Accessing Value or ProtectedValue on an empty instance throws InvalidOperationException.
  • Utility helpers: ProtectedNumber.IsNullOrEmpty(ProtectedNumber?) and initialization helpers to ensure safe usage.

Where can I get it?

First, install NuGet. Then, install ProtectedNumbers from the package manager console:

PM> Install-Package ProtectedNumbers

Or from the .NET CLI as:

dotnet add package ProtectedNumbers

How do I get started?

  • Add ProtectedNumbers services:
// ...
IServiceCollection services;
// ...

services.AddProtectedNumbers();
  • Replace the property type from int/long to ProtectedNumber:
// Before
public class SomeViewModel
{
  // ...
  public long? Id { get; set; }
  // ...
}

// After
public class SomeViewModel
{
  // ...
  public ProtectedNumbers? Id { get;set; }
  // ...
}
  • Example of json output from an api endpoint:

Before:

GET http://localhost:5000/minimal-api/samples-objects/4018378694012108869
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "id": "4018378694012108869",
  "name": "some data row"
}

After:

GET http://localhost:5000/minimal-api/samples-objects/CfDJ8K3W-Fa_koRAlAI935b9MJiwgpOlgJ5oj2hPOyJZZFqlHZB7JZKF5ccvazbH8_u4rtp1Ek-orXITi05_0MFOGj0Erm77rxFfpBQcfHVk04M-eaTiWkTNm54PwtmSdEZY5Iy9pGCCo_fYsFj2K54T89c
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "id": "CfDJ8K3W-Fa_koRAlAI935b9MJjgVrkgEMGZ5bvAPECdKZvgMpUPsvhVru9een2MVC0P8e4N4ehwgKgueAGjZlEP4s7gu3AsBLRoQrnUZr8hw4qZYAr-StAlQWCfx2FHTs1EGgEpB3T9YPSGxAxm0XVP7Mc",
  "name": "some data row"
}

Do you have an issue?

If you're still running into problems, file an issue above.

License, etc.

ProtectedNumbers is Copyright © 2025 Grégory Célet under the MIT license.

About

A .NET library for safe, opaque numeric identifiers you can pass through URLs, JSON, and model binding

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages