Làm cách nào để đạt được mã hóa an toàn URL Base64 trong C #?


104

Tôi muốn đạt được mã hóa an toàn URL Base64 trong C #. Trong Java, chúng tôi có Codecthư viện chung cung cấp cho tôi một chuỗi mã hóa an toàn URL. Làm cách nào để đạt được điều tương tự khi sử dụng C #?

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

Đoạn mã trên chuyển đổi nó thành Base64, nhưng nó bị hỏng ==. Có cách nào để đạt được mã hóa URL an toàn không?


Bạn không thể chỉ sử dụng Url.Encodetrên chuỗi trong BASE64?

Lớp Url không gian tên nào hiện diện trong c #?
Vishvesh Phadnis

Hãy xem: msdn.microsoft.com/en-us/library/… Bạn cần tham chiếu System.Webassembly.

Nó đang chuyển đổi = thành% 3D. Tôi không muốn điều đó.
Vishvesh Phadnis

3
Vậy ý bạn là url safegì? %3Durl có an toàn không.

Câu trả lời:


181

Thông thường, chỉ cần hoán đổi bảng chữ cái để sử dụng trong url, vì vậy không cần mã% -encoding; chỉ có 3 trong số 65 nhân vật có vấn đề - +, /=. các thay thế phổ biến nhất là -ở vị trí của +_thay /. Đối với phần đệm: chỉ cần loại bỏ nó (the =); bạn có thể suy ra số lượng đệm cần thiết. Ở đầu kia: chỉ cần đảo ngược quy trình:

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

với:

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

và để đảo ngược:

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

Tuy nhiên, câu hỏi thú vị là: đây có phải là cách tiếp cận mà "thư viện codec chung" sử dụng không? Đó chắc chắn sẽ là một điều hợp lý đầu tiên để kiểm tra - đây là một cách tiếp cận khá phổ biến.


1
Trong Common Codec, họ đang sử dụng Ký tự [0-9a-zA-Z_-] cho chế độ an toàn url.
Vishvesh Phadnis

điều này cũng được đề cập trong trang wiki cho Base64 trong các ứng dụng URL. vi.wikipedia.org/wiki/Base64
wonster

2
Bạn cũng có chức năng này ' stackoverflow.com/questions/1886686/… ', thực hiện tất cả công việc khó khăn cho bạn.
toy4fun

1
Tại sao chúng ta không cần: case 1: incoming + = "==="; phá vỡ; ?
alex da franca

5
@alexdafranca vì nó sẽ không bao giờ có mod độ dài 4 trên 1. Các bit 3x8 trở thành các bit 4x6 (và mỗi 6 bit là một trong 64 ký tự trong bảng chữ cái đã chọn), các bit 0x8 được mã hóa thành các bit 0x6 mà không có phần đệm, các bit 1x8 được mã hóa thành Các bit ==2x6 có đệm, 2x8 được mã hóa là 3x6 có =đệm, 3x8 được mã hóa thành 4x6 không có đệm và sau đó nó được căn chỉnh để nó lặp lại. Không có gì từng được mã hóa thành 1x6 bit, vì vậy bạn không bao giờ cần ===đệm.
George Helyar

83

Bạn có thể sử dụng lớp Base64UrlEncodertừ không gian tên 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
Điều này rõ ràng hơn nhiều so với câu trả lời được chấp nhận. Bất kỳ nhược điểm?
taktak004

18
Chỉ cần lưu ý: Microsoft.IdentityModel.Tokens là một gói NuGet phải được tải xuống.
Uber Schnoz

Tôi giả định rằng đây không phải là nền tảng chéo. Đó là trường hợp?
Brandon S.


8

Dựa trên các câu trả lời ở đây với một số cải tiến về hiệu suất, chúng tôi đã xuất bản một triển khai base64 an toàn cho url rất dễ sử dụng cho NuGet với mã nguồn có sẵn trên GitHub (được MIT cấp phép).

Cách sử dụng dễ dàng như

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

Cảm ơn bạn tuyệt vời. Ra quan tâm tại sao bạn đã chọn cho "string".Replacecho các encodephương pháp, nhưng một vòng lặp với Thay thế tay cho decode?
ᴍᴀᴛᴛ ʙᴀᴋᴇʀ

@ ᴍᴀᴛᴛʙᴀᴋᴇʀ Tôi cần xem lại nó và chạy một số điểm chuẩn, nhưng do chúng tôi thêm vào điểm chuẩn nên nó được biểu thị bằng một danh sách các ký tự có thể phát triển thay vì một chuỗi bất biến.
Mahmoud Al-Qudsi

Một lớp khác có kiểu trả về = string thay thế: github.com/vndevpro/architecture-common/blob/master/…
hazjack 13/1218

8

Để có được mã hóa giống base64 an toàn cho URL, nhưng không phải "base64url" theo RFC4648, hãy sử dụng System.Web.HttpServerUtility.UrlTokenEncode(bytes)để mã hóa và System.Web.HttpServerUtility.UrlTokenDecode(bytes)giải mã.


6
Điều này không cung cấp tiêu chuẩn mã hóa Base64 an toàn cho URL theo RFC4648. Xem thêm Q&A này . Sử dụng cẩn thận.
Artjom B.

1

Giải pháp đơn giản nhất: (không có đệm)

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
  }

Tín dụng chuyển đến: Tholle


0

Đây là một phương pháp khác để giải mã một base64 an toàn cho url đã được mã hóa theo cách tương tự với Marc. Tôi chỉ không hiểu tại sao4-length%4 hoạt động (nó có).

Như sau, chỉ độ dài bit của điểm gốc là bội số chung của 6 và 8, base64 không thêm "=" vào kết quả.

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

Vì vậy, chúng ta có thể làm điều đó ngược lại, nếu độ dài bit của kết quả không thể chia hết cho 8, nó đã được thêm vào:

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

Sử dụng công cụ mật mã của Microsoft trong UWP.

uint length = 32;

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

return base64Str;

0

Câu trả lời của Karanvir Kang là một câu trả lời hay và tôi đã bình chọn cho nó. Tuy nhiên, nó để lại một ký tự lẻ ở cuối chuỗi (cho biết số ký tự đệm bị loại bỏ). Đây là giải pháp của tôi.

var bytesToEncode = System.Text.Encoding.UTF8.GetBytes("StringToEncode"); 
var bytesEncodedPadded = HttpServerUtility.UrlTokenEncode(bytesToEncode);
var objectIdBase64 = bytesEncodedPadded.Substring(0, bytesEncodedPadded.Length - 1);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.