Як досягти безпечного кодування URL-адреси Base64 в C #?


105

Я хочу досягти безпечного кодування URL-адреси Base64 у C #. У Java у нас є спільна Codecбібліотека, яка дає мені кодований рядок, захищений URL-адресою. Як я можу досягти того ж за допомогою C #?

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

Вищевказаний код перетворює його в Base64, але він прокладає ==. Чи є спосіб досягти безпечного кодування URL?


Ви не можете просто використовувати Url.Encodeна рядку в BASE64?

У якому просторі імен клас Url присутній у c #?
Вішвеш Фадніс

Погляньте: msdn.microsoft.com/en-us/library/… Вам потрібно посилатися на System.Webзбірку.

Це перетворюється = у% 3D. Я не хочу цього.
Вішвеш Фадніс

3
Отже, що ти маєш на увазі url safe? %3DURL-адреса безпечна.

Відповіді:


182

Як правило, просто поміняти алфавіт для використання в URL-адресах, щоб не було необхідного кодування% -в; лише 3 з 65 символів є проблематичними - +, /і =. найчастіші заміни відбуваються -замість +та _на місці /. Що стосується прокладки: просто вийміть її (the =); Ви можете зробити висновок про необхідну кількість прокладки. З іншого боку: просто поверніть процес:

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

з:

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

і повернути назад:

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

Однак цікаве питання: чи це той самий підхід, який використовує "загальна бібліотека кодеків"? Це, безумовно, було б розумно спочатку перевірити - це досить поширений підхід.


1
У звичайному кодеку вони використовують [0-9a-zA-Z_-] символ для безпечного режиму URL.
Vishvesh Phadnis

про це також згадується на сторінці вікі для Base64 у додатках URL. en.wikipedia.org/wiki/Base64
wonster

2
У вас також є ця функція " stackoverflow.com/questions/1886686/… ", яка робить всю важку роботу за вас.
toy4fun

1
Чому нам не потрібно: випадок 1: вхід + = "==="; перерва; ?
alex da franca

5
@alexdafranca, оскільки він ніколи не матиме довжину моду 4 з 1. 3x8 біт стає 4x6 бітами (і кожен 6 біт є одним із 64 символів у вибраному алфавіті), 0x8 біт кодується як 0x6 біт без прокладки, 1x8 біт кодується як 2x6 біт з ==прокладкою, 2x8 кодується як 3x6 з =підкладкою, 3x8 кодується як 4x6 без прокладки, а потім вирівнюється, щоб він повторювався. Ніколи ніколи не кодується до 1x6 біт, тому вам ніколи не потрібні ===прокладки.
Джордж

83

Ви можете використовувати клас Base64UrlEncoderз простору імен 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
Це набагато чіткіше, ніж прийнята відповідь. Будь-який недолік?
taktak004

18
Лише зауваження: Microsoft.IdentityModel.Tokens - це пакет NuGet, який потрібно завантажити.
Uber Schnoz

Я припускаю по імені, що це не кросова платформа. Це так?
Брендон С.


8

Виходячи з відповідей тут із деякими покращеннями продуктивності, ми опублікували дуже просту у використанні безпечну для url реалізацію base64 для NuGet із вихідним кодом, доступним на GitHub (ліцензія MIT).

Використання так само просто

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

Дивовижне дякую. З інтересу чому ви вибрали для "string".Replaceдля encodeметоду, але петлі з ручним Замінює для decode?
ᴍᴀᴛᴛ ʙᴀᴋᴇʀ

@ ᴍᴀᴛᴛʙᴀᴋᴇʀ Мені потрібно переглянути його та запустити деякі орієнтири, але це тому, що ми додаємо до останнього, щоб він був представлений розширюваним списком символів замість незмінного рядка.
Махмуд Аль-Кудсі

Ще один клас із типом return = string замість цього: github.com/vndevpro/architecture-common/blob/master/…
hazjack

8

Щоб отримати URL-безпечне кодування, схоже на base64, але не "base64url" відповідно до RFC4648, використовуйте System.Web.HttpServerUtility.UrlTokenEncode(bytes)для кодування та System.Web.HttpServerUtility.UrlTokenDecode(bytes)декодування.


6
Це не забезпечує стандартних кодування Base64, захищених URL-адресами відповідно до RFC4648. Дивіться також це питання . Використовуйте обережно.
Artjom B.

1

Найпростіше рішення: (без прокладки)

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
  }

Кредит належить: Tholle


0

Ось ще один метод декодування захищеної від URL-адреси base64 був кодований аналогічно Марку. Я просто не розумію, чому 4-length%4працюю (це робить).

Як слід, лише довжина бітів джерела є загальною кратною 6 і 8, base64 не додає "=" до результату.

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

Таким чином, ми можемо це зробити навпаки, якщо довжина біта результату не може ділитися на 8, він додається:

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

Використання криптографічного двигуна Microsoft в UWP.

uint length = 32;

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

return base64Str;

0

Відповідь Каранвір Канга - хороша, і я проголосував за неї. Однак він залишає непарний символ на кінці рядка (із зазначенням кількості видалених символів прокладки). Ось моє рішення.

var bytesToEncode = System.Text.Encoding.UTF8.GetBytes("StringToEncode"); 
var bytesEncodedPadded = HttpServerUtility.UrlTokenEncode(bytesToEncode);
var objectIdBase64 = bytesEncodedPadded.Substring(0, bytesEncodedPadded.Length - 1);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.