Come ottenere la codifica sicura dell'URL Base64 in C #?


105

Voglio ottenere la codifica sicura dell'URL Base64 in C #. In Java, abbiamo la Codeclibreria comune che mi fornisce una stringa codificata sicura per l'URL. Come posso ottenere lo stesso risultato usando C #?

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

Il codice sopra lo converte in Base64, ma si riempie ==. C'è un modo per ottenere la codifica sicura degli URL?


Non puoi usare solo Url.Encodesu stringa BASE64?

In quale spazio dei nomi Url classe è presente in c #?
Vishvesh Phadnis

Dai un'occhiata: msdn.microsoft.com/en-us/library/… Devi fare riferimento System.Weball'assembly.

Sta convertendo = in% 3D. Non lo voglio.
Vishvesh Phadnis

3
Allora cosa intendi con url safe? %3Dè sicuro per l'URL.

Risposte:


182

È comune scambiare semplicemente l'alfabeto per l'uso negli URL, in modo che non sia necessaria la codifica%; solo 3 dei 65 caratteri sono problematici - +, /e =. le sostituzioni più comuni sono -al posto di +e _al posto di /. Per quanto riguarda l'imbottitura: basta rimuoverla (la =); puoi dedurre la quantità di imbottitura necessaria. All'altra estremità: basta invertire il processo:

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

con:

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

e per invertire:

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 domanda interessante, tuttavia, è: è questo lo stesso approccio utilizzato dalla "libreria di codec comuni"? Sarebbe certamente una prima cosa ragionevole da testare: questo è un approccio piuttosto comune.


1
In Common Codec stanno usando [0-9a-zA-Z_-] Character per la modalità provvisoria dell'URL.
Vishvesh Phadnis

questo è anche menzionato nella pagina wiki per Base64 sotto le applicazioni URL. en.wikipedia.org/wiki/Base64
wonster

2
Hai anche questa funzione ' stackoverflow.com/questions/1886686/… ' che fa tutto il duro lavoro per te.
toy4fun

1
Perché non abbiamo bisogno di: caso 1: in arrivo + = "==="; rompere; ?
alex da franca

5
@alexdafranca perché non avrà mai una lunghezza mod 4 di 1. 3x8 bit diventano 4x6 bit (e ogni 6 bit è uno dei 64 caratteri dell'alfabeto scelto), 0x8 bit è codificato come 0x6 bit senza riempimento, 1x8 bit è codificato come 2x6 bit con ==riempimento, 2x8 è codificato come 3x6 con =riempimento, 3x8 è codificato come 4x6 senza riempimento e quindi è allineato in modo da ripetersi. Niente è mai codificato in 1x6 bit, quindi non hai mai bisogno di ===imbottitura.
George Helyar

83

Puoi usare class Base64UrlEncoderdallo spazio dei nomi 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
Questo è molto più pulito della risposta accettata. Qualche svantaggio?
taktak004

18
Solo una nota: Microsoft.IdentityModel.Tokens è un pacchetto NuGet che deve essere scaricato.
Uber Schnoz

Dal nome presumo che questo non sia multipiattaforma. È così?
Brandon S.


8

Sulla base delle risposte qui con alcuni miglioramenti delle prestazioni, abbiamo pubblicato un molto facile da usare un'implementazione base64 e sicura per l'URL in NuGet con il codice sorgente disponibile su GitHub (con licenza MIT).

L'utilizzo è facile quanto

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

Incredibile grazie. Per interesse perché hai optato per "string".Replaceil encodemetodo, ma un ciclo con il manuale sostituisce il decode?
ᴍᴀᴛᴛ ʙᴀᴋᴇʀ

@ ᴍᴀᴛᴛʙᴀᴋᴇʀ Ho bisogno di rivisitarlo ed eseguire alcuni benchmark, ma è perché aggiungiamo a quest'ultimo quindi è rappresentato da un elenco di caratteri espandibile invece di una stringa immutabile.
Mahmoud Al-Qudsi

Un'altra classe con tipo di ritorno = stringa invece: github.com/vndevpro/architecture-common/blob/master/…
hazjack

8

Per ottenere una codifica simile a base64 sicura per gli URL, ma non "base64url" secondo RFC4648, utilizzare System.Web.HttpServerUtility.UrlTokenEncode(bytes)per codificare e System.Web.HttpServerUtility.UrlTokenDecode(bytes)decodificare.


6
Ciò non fornisce una codifica Base64 sicura per gli URL conforme a RFC4648. Vedi anche questa domanda e risposta . Usare con cautela.
Artjom B.

1

Soluzione più semplice: (senza imbottitura)

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
  }

Il merito va a: Tholle


0

Ecco un altro metodo per decodificare un base64 sicuro per l'URL che è stato codificato allo stesso modo con Marc. Semplicemente non capisco perché4-length%4 funzionato (lo fa).

Come segue, solo la lunghezza in bit dell'origine è un multiplo comune di 6 e 8, base64 non aggiunge "=" al risultato.

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
                "=="            "="

Quindi possiamo farlo al contrario, se la lunghezza del bit del risultato non può essere divisibile per 8, è stato aggiunto:

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

Utilizzo del motore crittografico Microsoft in UWP.

uint length = 32;

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

return base64Str;

0

La risposta di Karanvir Kang è buona e ho votato a favore. Tuttavia, lascia un carattere dispari alla fine della stringa (che indica il numero di caratteri di riempimento rimossi). Ecco la mia soluzione.

var bytesToEncode = System.Text.Encoding.UTF8.GetBytes("StringToEncode"); 
var bytesEncodedPadded = HttpServerUtility.UrlTokenEncode(bytesToEncode);
var objectIdBase64 = bytesEncodedPadded.Substring(0, bytesEncodedPadded.Length - 1);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.