URLでbase64エンコードされた文字列を渡す


回答:


206

いいえ、base64文字列には「+」、「=」、「/」の文字を含めることができるため、URLエンコードする必要があります。これは、データの意味を変える可能性があるため、サブフォルダーのように見えます。

有効なbase64文字は以下のとおりです。

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=

4
特にbase64自体が多くの文字を未使用のままにするため、URLエンコードはスペースの無駄になります。
のMichałGórny

21
あなたの言っていることがよくわかりません-URLエンコードでは、上記のリストの最後の3文字以外の文字は変更されません。これは、URLで他の意味があるため、誤って解釈されないようにするためです。同じことはbase64にも当てはまります。元のデータはバイナリなどですが、単純なプロトコルを使用して簡単に送信できる形式でエンコードされています。
Thiyagaraj

3
まず、スペースに変換される可能性があるため、「+」もエスケープする必要があります。次に、URLで安全に使用でき、「標準」文字セットでは使用されない文字が少なくともいくつかあります。この方法では、特定の状況で転送データのサイズを3倍に増やすこともできます。それらの文字を他の文字で置き換える間、同じ長さを維持しながらトリックを行います。そして、それも非常に標準的なソリューションです。
のMichałGórny

8
en.wikipedia.org/wiki/Base64#URL_applications —エスケープすると、「文字列が不必要に長くなる」ことが明確に示され、代替の文字セットバリアントが言及されます。
のMichałGórny

1
この答えのため、私は自分の問題をまさにそれが述べたものであると診断しました。ベースの64文字(+、/、=)の一部は、URL処理のために変更されていました。ベース64文字列をURLエンコードすると、問題は解決しました。
Chuck Krutsinger、2015年

272

追加のbase64仕様があります。(詳細については、こちらの表をご覧ください)。ただし、基本的に、エンコードするには65文字が必要です(26小文字+ 26大文字+ 10桁= 62)。

さらに2つの['+'、 '/']とパディング文字 '='が必要です。しかし、それらはどれもURLフレンドリーではありません。したがって、それらに異なる文字を使用するだけで、設定は完了です。上記のチャートの標準的な文字は['-'、 '_']ですが、同じようにデコードし、他の文字と共有する必要がない限り、他の文字を使用できます。

独自のヘルパーを作成することをお勧めします。base64_encodeのphpマニュアルページのコメントからこれらのように:

function base64_url_encode($input) {
 return strtr(base64_encode($input), '+/=', '._-');
}

function base64_url_decode($input) {
 return base64_decode(strtr($input, '._-', '+/='));
}

53
URLでコンマが予約されていないことを除いて、優れたソリューションです。「〜」(チルド)または「。」の使用をお勧めします。(ドット)代わりに。
Kralyk 2013

11
@kralyk:私はurlencoderodrigo-silveiraの回答で示唆されているように使用することをお勧めします。urlの長さで数文字を節約する2つの新しい関数を作成することは、ドアを使用するだけでなく、窓を通過して家に入るようなものです。
Marco Demaio 2014

5
@MarcoDemaio、それがどのように使用されるかを知らなければ、それがほんの数文字であると言うことは不可能です。エンコードされたすべての文字の長さは3倍になり、なぜ「+++ ...」が有効なbase64文字列にならないのですか?URLにはブラウザの制限があり、URLを3倍にすると、それらの制限に達する可能性があります。
leewz

10
@RandalSchwartzチルド URLセーフです。RFC3986から:unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
Kralyk

3
,にurlencodeする必要があるため、末尾を保持するen.wikipedia.org/wiki/Base64#Variants_summary_tableの唯一のバリアントの 代わりに%2C使用._-することをお勧めします=-_,
PaulH

75

@joeshmoまたは、ヘルパー関数を作成する代わりに、base64エンコードされた文字列をurlencodeすることもできます。これはヘルパー関数とまったく同じことを行いますが、2つの追加関数は必要ありません。

$str = 'Some String';

$encoded = urlencode( base64_encode( $str ) );
$decoded = base64_decode( urldecode( $encoded ) );

2
結果はまったく同じではありません。urlencodeは3文字を使用して無効な文字をエンコードし、joeshmoのソリューションは1を使用します。これは大きな違いではありませんが、それでも無駄です。
Josef Borkovec 2013年

1
@JosefBorkovecほんと?次に、これは、base64-> url-> encodedの同じバイト数がさまざまな結果の長さになる可能性があることも意味しますが、他の解決策は予測可能な長さを与えますよね?
humanityANDpeace

@humanityANDpeaceはい、urlencodeは特定のbase64文字列のサイズを3倍にするため、おかしな解決策です。また、出力が入力よりも大きいため、バッファを再利用することもできません。
Navin

4
1文字から3文字への拡張は、平均で64文字のうち3文字で発生するため、9%のオーバーヘッド(2 *
3/64

/GETパラメーターとしてではなく、URL内のパスとして渡す場合は、文字に注意してください。/両側で何かを置き換えないと、パスが変更されます。
NeverEndingQueue

41

序論ここでの回答のいくつかは少し誤解を招くものだったので(不正確でないとしても)、私はいくつかの説明を投稿する傾向があります。

正解は $ _GETグローバル配列内のSPACEに変換されるため、答えはNOです。URLクエリ文字列内でbase64エンコードされたパラメーターを単純に渡すことはできません。つまり、test.php?myVar = stringwith + sign

//test.php
print $_GET['myVar'];

結果は次のようになります。
stringwith sign

これを解決する簡単な方法はurlencode()、base64文字列をクエリ文字列に追加する前に単純に、+、=、および/文字を%##コードにエスケープすることです。例えば、urlencode("stringwith+sign")リターンstringwith%2Bsign

アクションを処理するとき、PHPは$ _GETグローバルに入力するときにクエリ文字列を自動的にデコードします。たとえば、test.php?myVar = stringwith%2Bsign

//test.php
print $_GET['myVar'];

結果は次のようになります。
stringwith+sign

+はスペースに変換されるため、返される$ _GET文字列必要ありませurldecode()
つまり、同じtest.php?myVar = stringwith%2Bsign

//test.php
$string = urldecode($_GET['myVar']);
print $string;

結果は予想外です:
stringwith sign

rawurldecode()入力に対しては安全ですが、冗長であるため不要です。


1
素敵な答え。質問にphpがタグ付けされている場合は、このサイトで開始タグと終了タグなしでPHPコードを使用できます(ほとんどの場合、質問のコンテキストからも明らかです)。行の終わりに2つのスペースを追加すると、が表示されるため<br>、多くのHTMLを入力する必要はありません。これがお役に立てば幸いです。さらに改善するために、あなたの回答を少し編集しました。
hakre 2012

PHPがURLをデコードすることに言及していただきありがとうございます。それは私がウサギの穴の中に落ちるのを防ぎます。
Cocest

すばらしい回答-> +はスペースに変換されるため、返された$ _GET文字列をurldecode()したくない。ただし、入力をrawurldecode()しても安全です
MarcoZen

14

はいといいえ。

base64の基本的な文字セットは、URLで使用される従来の規約と衝突する場合があります。しかし、base64実装の多くでは、URLに一致するように文字セットを変更したり、URLに(Pythonのようにurlsafe_b64encode())文字セットを追加したりできます。

直面している可能性のあるもう1つの問題は、URLの長さの制限、またはそのような制限の欠如です。標準では最大長が指定されていないため、ブラウザ、サーバー、ライブラリ、およびHTTPプロトコルで動作するその他のソフトウェアが独自の制限を定義する場合があります。次の記事をご覧ください。WWWFAQ:URLの最大長は?


8

あなたが試すことができるそのbase64urlエンコード、それは上記のjoeshmoのコードのちょうど拡張です。

function base64url_encode($data) {
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}

function base64url_decode($data) {
return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT));
}

これは、Javaでエンコードされたデータで機能しますBase64.getUrlEncoder().withoutPadding().encodeToString()

4

たとえば、「=」文字はrawベース64で使用され、パラメータをHTTP GETの値と区別するためにも使用されるため、これは安全ではないと思います。


1

理論的には、はい、クライアントまたはサーバーのURLやクエリ文字列の最大長を超えない限り可能です。

実際には、物事は少しトリッキーになる可能性があります。たとえば、値に "on"が含まれている場合、ASP.NETでHttpRequestValidationExceptionをトリガーし、最後に "=="を残すことができます。


特定の場合にURLを無効にする+、/、または=文字については言及しません。
ビックフォード

0

base64.urlsafe_b64encode(...)PythonのようなURLセーフエンコードの場合、以下のコードは100%機能します

function base64UrlSafeEncode(string $input)
{
   return str_replace(['+', '/'], ['-', '_'], base64_encode($input));
}

-10

はい、常に安全です。もちろん、base64には以下 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/= が含まれます。 ただし、base64でエンコードされた文字列には通常はありません++空白に変換され、誤った文字列がデコードされます。/getパラメータのペアでは安全です。=常にbase64エンコードされた文字列の最後にあり、サーバー側は=直接解決できます。


これは正しいと思います。base64エンコーディング(URLエンコーディングなし)で行った実験は成功したのですが、これをバックアップするために提供できるドキュメントがあるかどうか疑問に思いますか?
Sean the Bean

1
「常に安全」と言っても、「通常は+がない」と言います。だからあなた自身の矛盾。+記号は、base64文字列にある場合、問題を引き起こすように継ぎ合わせます。
Nick Humrich
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.