Bagaimana cara mencapai pengkodean aman URL Base64 di C #?


105

Saya ingin mencapai pengkodean aman URL Base64 di C #. Di Jawa, kami memiliki kesamaanCodec perpustakaan yang memberi saya string yang dikodekan URL yang aman. Bagaimana saya bisa mencapai hal yang sama menggunakan C #?

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

Kode di atas mengubahnya menjadi Base64, tetapi itu pad ==. Apakah ada cara untuk mencapai pengkodean aman URL?


Tidak bisakah kamu menggunakan Url.Encodestring in BASE64?

Di namespace mana kelas Url ada di c #?
Vishvesh Phadnis

Coba lihat: msdn.microsoft.com/en-us/library/… Anda perlu referensi System.Webperakitan.

Ini mengubah = menjadi% 3D. Saya tidak menginginkan itu.
Vishvesh Phadnis

3
Jadi apa yang kamu maksud dengan url safe? %3Dapakah url aman.

Jawaban:


182

Biasanya hanya menukar alfabet untuk digunakan di url, jadi tidak perlu% -encoding; hanya 3 dari 65 karakter yang bermasalah - +, /dan =. penggantian yang paling umum adalah -di tempat +dan _di tempat /. Adapun padding: hapus saja (the =); Anda dapat menyimpulkan jumlah padding yang dibutuhkan. Di ujung lain: balikkan saja prosesnya:

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

dengan:

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

dan untuk membalikkan:

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);

Pertanyaan yang menarik, bagaimanapun, adalah: apakah ini pendekatan yang sama yang digunakan "pustaka codec umum"? Ini tentu akan menjadi hal pertama yang masuk akal untuk diuji - ini adalah pendekatan yang cukup umum.


1
Dalam Codec Umum mereka menggunakan Karakter [0-9a-zA-Z_-] untuk mode aman url.
Vishvesh Phadnis

ini juga disebutkan di halaman wiki untuk Base64 di bawah aplikasi URL. en.wikipedia.org/wiki/Base64
wonster

2
Anda juga memiliki fungsi ' stackoverflow.com/questions/1886686/… ' yang melakukan semua kerja keras untuk Anda.
toy4fun

1
Mengapa kita tidak membutuhkan: case 1: incoming + = "==="; istirahat; ?
alex da franca

5
@alexdafranca karena tidak akan pernah memiliki mod panjang 4 dari 1. 3x8 bit menjadi 4x6 bit (dan masing-masing 6 bit adalah salah satu dari 64 karakter dalam alfabet yang dipilih), 0x8 bit dikodekan sebagai 0x6 bit tanpa padding, 1x8 bit dikodekan sebagai 2x6 bit dengan ==padding, 2x8 dikodekan sebagai 3x6 dengan =padding, 3x8 dikodekan sebagai 4x6 tanpa padding lalu disejajarkan sehingga berulang. Tidak ada yang pernah dikodekan menjadi 1x6 bit, jadi Anda tidak perlu ===padding.
George Helyar

83

Anda dapat menggunakan kelas Base64UrlEncoderdari namespace 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
Ini jauh lebih bersih daripada jawaban yang diterima. Ada kerugian?
taktak004

18
Sekadar catatan: Microsoft.IdentityModel.Tokens adalah paket NuGet yang harus diunduh.
Uber Schnoz

Saya berasumsi dengan namanya bahwa ini bukan lintas platform. Apakah itu masalahnya?
Brandon S.


8

Berdasarkan jawaban di sini dengan beberapa peningkatan kinerja, kami telah menerbitkan implementasi base64 aman-url yang sangat mudah digunakan ke NuGet dengan kode sumber yang tersedia di GitHub (berlisensi MIT).

Penggunaannya semudah

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

Luar biasa terima kasih. Dari bunga mengapa Anda memilih untuk "string".Replaceuntuk encodemetode, tetapi loop dengan Menggantikan panduan untuk decode?
ᴍᴀᴛᴛ ʙᴀᴋᴇʀ

@ ᴍᴀᴛᴛʙᴀᴋᴇʀ Saya perlu mengunjunginya kembali dan menjalankan beberapa tolok ukur, tetapi itu karena kita menambahkan yang terakhir sehingga itu diwakili oleh daftar karakter yang dapat bertambah alih-alih string yang tidak dapat diubah.
Mahmoud Al-Qudsi

Kelas lain dengan mengembalikan type = string sebagai gantinya: github.com/vndevpro/architecture-common/blob/master/…
hazjack

8

Untuk mendapatkan pengkodean seperti base64 yang aman untuk URL, tetapi bukan "base64url" menurut RFC4648, gunakan System.Web.HttpServerUtility.UrlTokenEncode(bytes)untuk mengenkode, dan System.Web.HttpServerUtility.UrlTokenDecode(bytes)untuk mendekode.


6
Ini tidak memberikan standar yang sesuai dengan pengkodean Base64 aman URL menurut RFC4648. Lihat juga Tanya Jawab ini . Gunakan dengan hati-hati.
Artjom B.

1

Solusi paling sederhana: (tanpa bantalan)

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
  }

Penghargaan diberikan kepada: Tholle


0

Berikut adalah metode lain untuk memecahkan kode base64 aman-url yang dikodekan dengan cara yang sama dengan Marc. Saya hanya tidak mengerti mengapa4-length%4 berhasil (berhasil).

Sebagai berikut, hanya panjang bit asal yang merupakan kelipatan persekutuan dari 6 dan 8, base64 tidak menambahkan "=" ke hasil.

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

Jadi kita bisa melakukan sebaliknya, jika panjang bit hasil tidak habis dibagi 8, maka ditambahkan:

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

Menggunakan mesin kriptografi Microsoft di UWP.

uint length = 32;

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

return base64Str;

0

Jawaban Karanvir Kang bagus dan saya memilihnya. Namun, itu meninggalkan karakter ganjil di akhir string (menunjukkan jumlah karakter padding yang dihapus). Inilah solusi saya.

var bytesToEncode = System.Text.Encoding.UTF8.GetBytes("StringToEncode"); 
var bytesEncodedPadded = HttpServerUtility.UrlTokenEncode(bytesToEncode);
var objectIdBase64 = bytesEncodedPadded.Substring(0, bytesEncodedPadded.Length - 1);
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.