Comment réaliser un encodage sécurisé d'URL Base64 en C #?


105

Je souhaite obtenir un encodage sécurisé d'URL Base64 en C #. En Java, nous avons la Codecbibliothèque commune qui me donne une chaîne codée URL sécurisée. Comment puis-je réaliser la même chose en utilisant C #?

byte[] toEncodeAsBytes = System.Text.ASCIIEncoding.ASCII.GetBytes("StringToEncode");
string returnValue = System.Convert.ToBase64String(toEncodeAsBytes);

Le code ci-dessus le convertit en Base64, mais il complète ==. Existe-t-il un moyen d'obtenir un encodage sécurisé des URL?


Ne pouvez-vous pas simplement utiliser une Url.Encodechaîne BASE64?

Dans quelle classe d'URL d'espace de noms est-elle présente dans c #?
Vishvesh Phadnis

Jetez un œil: msdn.microsoft.com/en-us/library/… Vous devez référencer l' System.Webassembly.

C'est la conversion = en% 3D. Je ne veux pas ça.
Vishvesh Phadnis

3
Alors qu'est-ce que tu veux dire url safe? %3Dest une url sûre.

Réponses:


182

Il est courant d' échanger simplement l'alphabet pour une utilisation dans les URL, de sorte qu'aucun% -encoding n'est nécessaire; seuls 3 des 65 caractères sont problématiques - +, /et =. les remplacements les plus courants sont -à la place +et _à la place de /. Quant au rembourrage: il suffit de le retirer (le =); vous pouvez déduire la quantité de rembourrage nécessaire. À l'autre extrémité: inversez simplement le processus:

string returnValue = System.Convert.ToBase64String(toEncodeAsBytes)
        .TrimEnd(padding).Replace('+', '-').Replace('/', '_');

avec:

static readonly char[] padding = { '=' };

et inverser:

string incoming = returnValue
    .Replace('_', '/').Replace('-', '+');
switch(returnValue.Length % 4) {
    case 2: incoming += "=="; break;
    case 3: incoming += "="; break;
}
byte[] bytes = Convert.FromBase64String(incoming);
string originalText = Encoding.ASCII.GetString(bytes);

La question intéressante, cependant, est: est-ce la même approche que la "bibliothèque de codecs communs" utilise? Ce serait certainement une première chose raisonnable à tester - c'est une approche assez courante.


1
Dans Common Codec, ils utilisent le caractère [0-9a-zA-Z_-] pour le mode sans échec de l'URL.
Vishvesh Phadnis

ceci est également mentionné dans la page wiki pour Base64 sous les applications URL. en.wikipedia.org/wiki/Base64
wonster

2
Vous disposez également de cette fonction « stackoverflow.com/questions/1886686/… » qui fait tout le travail pour vous.
toy4fun

1
Pourquoi n'avons-nous pas besoin de: cas 1: entrant + = "==="; Pause; ?
alex da franca

5
@alexdafranca car il n'aura jamais une longueur mod 4 de 1. 3x8 bits deviennent 4x6 bits (et chaque 6 bits est l'un des 64 caractères de l'alphabet choisi), 0x8 bits est codé comme 0x6 bits sans remplissage, 1x8 bits est codé comme 2x6 bits avec ==padding, 2x8 est encodé en 3x6 avec =padding, 3x8 est encodé en 4x6 sans padding, puis il est aligné pour qu'il se répète. Rien n'est jamais encodé en 1x6 bits, vous n'avez donc jamais besoin de ===remplissage.
George Helyar

83

Vous pouvez utiliser la classe Base64UrlEncoderde l'espace de noms Microsoft.IdentityModel.Tokens.

const string StringToEncode = "He=llo+Wo/rld";

var encodedStr = Base64UrlEncoder.Encode(StringToEncode);
var decodedStr = Base64UrlEncoder.Decode(encodedStr);

if (decodedStr == StringToEncode)
    Console.WriteLine("It works!");
else
    Console.WriteLine("Dangit!");

1
C'est beaucoup plus propre que la réponse acceptée. Un inconvénient?
taktak004

18
Juste une note: Microsoft.IdentityModel.Tokens est un package NuGet qui doit être téléchargé.
Uber Schnoz

Je suppose par son nom que ce n'est pas multiplateforme. Est-ce le cas?
Brandon S.


8

Sur la base des réponses ici avec quelques améliorations de performances, nous avons publié une implémentation base64 sécurisée pour les URL très facile à utiliser dans NuGet avec le code source disponible sur GitHub (licence MIT).

L'utilisation est aussi simple que

var bytes = Encoding.UTF8.GetBytes("Foo");
var encoded = UrlBase64.Encode(bytes);
var decoded = UrlBase64.Decode(encoded);

Merci incroyable. Par intérêt, pourquoi avez-vous opté pour "string".Replacela encodeméthode, mais une boucle avec manuel remplace le decode?
ᴍᴀᴛᴛ ʙᴀᴋᴇʀ

@ ᴍᴀᴛᴛʙᴀᴋᴇʀ J'ai besoin de le revoir et d'exécuter quelques benchmarks, mais c'est parce que nous ajoutons à ce dernier afin qu'il soit représenté par une liste de caractères extensible au lieu d'une chaîne immuable.
Mahmoud Al-Qudsi

Une autre classe avec return type = string à la place: github.com/vndevpro/architecture-common/blob/master/…
hazjack

8

Pour obtenir un encodage de type base64 sécurisé pour les URL, mais pas "base64url" selon RFC4648, utilisez System.Web.HttpServerUtility.UrlTokenEncode(bytes)pour encoder et System.Web.HttpServerUtility.UrlTokenDecode(bytes)pour décoder.


6
Cela ne fournit pas un codage Base64 sécurisé pour les URL conforme aux normes selon RFC4648. Voir également ce Q&R . Utiliser avec précaution.
Artjom B.

1

Solution la plus simple: (sans rembourrage)

private static string Base64UrlEncode(string input) {
    var inputBytes = System.Text.Encoding.UTF8.GetBytes(input);
    // Special "url-safe" base64 encode.
    return Convert.ToBase64String(inputBytes)
      .Replace('+', '-') // replace URL unsafe characters with safe ones
      .Replace('/', '_') // replace URL unsafe characters with safe ones
      .Replace("=", ""); // no padding
  }

Le mérite revient à: Tholle


0

Voici une autre méthode pour décoder une url-safe base64 qui a été encodée de la même manière avec Marc. Je ne comprends juste pas pourquoi4-length%4 travaillé (c'est le cas).

Comme suit, seules les longueurs en bits de l'origine sont des multiples communs de 6 et 8, base64 n'ajoute pas "=" au résultat.

1 2 3 4 5 6 7 8|1 2 3 4 5 6 7 8|1 2 3 4 5 6 7 8 
1 2 3 4 5 6|1 2 3 4 5 6|1 2 3 4 5 6|1 2 3 4 5 6
                "=="            "="

Nous pouvons donc le faire à l'inverse, si la longueur en bits du résultat ne peut pas être divisible par 8, elle a été ajoutée:

base64String = base64String.Replace("-", "+").Replace("_", "/");
var base64 = Encoding.ASCII.GetBytes(base64String);
var padding = base64.Length * 3 % 4;//(base64.Length*6 % 8)/2
if (padding != 0)
{
    base64String = base64String.PadRight(base64String.Length + padding, '=');
}
return Convert.FromBase64String(base64String);

0

Utilisation du moteur cryptographique Microsoft dans UWP.

uint length = 32;

IBuffer buffer = CryptographicBuffer.GenerateRandom(length);
string base64Str = CryptographicBuffer.EncodeToBase64String(buffer)
                   // ensure url safe
                   .TrimEnd('=').Replace('+', '-').Replace('/', '_');

return base64Str;

0

La réponse de Karanvir Kang est bonne et j'ai voté pour. Cependant, il laisse un caractère impair à la fin de la chaîne (indiquant le nombre de caractères de remplissage supprimés). Voici ma solution.

var bytesToEncode = System.Text.Encoding.UTF8.GetBytes("StringToEncode"); 
var bytesEncodedPadded = HttpServerUtility.UrlTokenEncode(bytesToEncode);
var objectIdBase64 = bytesEncodedPadded.Substring(0, bytesEncodedPadded.Length - 1);
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.