web-dev-qa-db-ja.com

Pythonでbase64URLをデコードする方法は?

Facebook fbml Appsの場合、Facebookはここで説明されているsigned_requestパラメーターを送信しています。

http://developers.facebook.com/docs/authentication/canvas

彼らはこの署名された要求をデコードするphpバージョンを与えました:

http://pastie.org/1054154

Pythonで同じことをする方法は?

Base64モジュールを試しましたが、誤ったパディングエラーが発生します:

>>> base64.urlsafe_b64decode("eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImV4cGlyZXMiOjEyNzk3NDYwMDAsIm9hdXRoX3Rva2VuIjoiMjk1NjY2Njk1MDY0fDIuRXpwem5IRVhZWkJVZmhGQ2l4ZzYzUV9fLjM2MDAuMTI3OTc0NjAwMC0xMDAwMDA0ODMyNzI5MjN8LXJ6U1pnRVBJTktaYnJnX1VNUUNhRzlNdEY4LiIsInVzZXJfaWQiOiIxMDAwMDA0ODMyNzI5MjMifQ")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/base64.py", line 112, in urlsafe_b64decode
    return b64decode(s, '-_')
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/base64.py", line 76, in b64decode
    raise TypeError(msg)
TypeError: Incorrect padding
22
kevin

元のbase64エンコードされた文字列をコピーするときに、最後の2文字を逃したようです。入力文字列に2つの等号(=)を付けると、正しくデコードされます。

20
Geert

試してみてください

s = 'iEPX-SQWIR3p67lj_0zigSWTKHg'
base64.urlsafe_b64decode(s + '=' * (4 - len(s) % 4))

書かれている通り ここ

25
dae.eklen

pythonベースのFacebookキャンバスアプリケーションでsigned_requestパラメーターを解析するためのコードスニペットを http://sunilarora.org/parsing-signedrequest-parameter-in-python-bas)で共有しました

import base64
import hashlib
import hmac
import simplejson as json

def base64_url_decode(inp):
    padding_factor = (4 - len(inp) % 4) % 4
    inp += "="*padding_factor 
    return base64.b64decode(unicode(inp).translate(dict(Zip(map(ord, u'-_'), u'+/'))))

def parse_signed_request(signed_request, secret):

    l = signed_request.split('.', 2)
    encoded_sig = l[0]
    payload = l[1]

    sig = base64_url_decode(encoded_sig)
    data = json.loads(base64_url_decode(payload))

    if data.get('algorithm').upper() != 'HMAC-SHA256':
        log.error('Unknown algorithm')
        return None
    else:
        expected_sig = hmac.new(secret, msg=payload, digestmod=hashlib.sha256).digest()

    if sig != expected_sig:
        return None
    else:
        log.debug('valid signed request received..')
return data
25
sunil

@ dae.eklenのソリューションの代わりに、===を追加できます。

s = 'iEPX-SQWIR3p67lj_0zigSWTKHg'
base64.urlsafe_b64decode(s + '===')

これは、Pythonがパディングの欠落についてのみ文句を言い、余分なパディングについては文句を言わないために機能します。

5
png
import base64
import simplejson as json

def parse_signed_request( signed_request ):
    encoded_sig, payload = signed_request.split('.',2)
    data = json.loads(base64.b64decode( payload.replace('-_', '+/') ))
    return data
2
FazalSap

驚くべきですが、現在受け入れられている答えは正確ではありません。他のいくつかの回答が述べたように、それはbase64urlエンコーディングと呼ばれるものであり、 RFC7515 の一部です。

基本的に、それらは「+」と「/」の文字をそれぞれ「-」と「_」に置き換えました。さらに、末尾の「=」文字を削除しました。これは、エンコードされた文字列の長さを調べるだけで、不足している文字数をいつでも確認できるためです。

以下は、C#でのRFC7515の例です。

 static string base64urlencode(byte [] arg)
 {
   string s = Convert.ToBase64String(arg); // Regular base64 encoder
   s = s.Split('=')[0]; // Remove any trailing '='s
   s = s.Replace('+', '-'); // 62nd char of encoding
   s = s.Replace('/', '_'); // 63rd char of encoding
   return s;
 }

 static byte [] base64urldecode(string arg)
 {
   string s = arg;
   s = s.Replace('-', '+'); // 62nd char of encoding
   s = s.Replace('_', '/'); // 63rd char of encoding
   switch (s.Length % 4) // Pad with trailing '='s
   {
     case 0: break; // No pad chars in this case
     case 2: s += "=="; break; // Two pad chars
     case 3: s += "="; break; // One pad char
     default: throw new System.Exception(
       "Illegal base64url string!");
   }
   return Convert.FromBase64String(s); // Standard base64 decoder
 }
1

これが正しい解決策です。 pythonにはbase64.b64encodeがありますが、base64エンコードのみであり、base64urlエンコードとは異なります。base64encoded形式をbase64urlencoded文字列に変換する手順の正しいセットは次のとおりです。
1。結果の文字列から、「/」を「_」に、「+」を「-」に置き換えます
2。末尾の「==」を削除します。

出来上がり!これにより、base64 url​​デコードの有効な文字列になります。ところで、上記の@ dae.eklenの回答のリンクは現在壊れています。

0
arunsudhir

base64から.net文字列をパラメータとして送信する場合、URIで特別な意味を持つ文字、つまり+または/" "スペースに置き換えられているようです。

したがって、.netで文字列を送信する前に、おそらく次のようなことを行う必要があります。

base64img.Replace("+", "-").Replace("/", "_"))

次に、pythonで文字列をデコードします(長さが4で割り切れるまで '='も追加します)

def decode_base64(data):
    data += '=' * (len(data) % 4)
    return base64.urlsafe_b64decode(data)

さらに、openCVで画像を使用したい場合

def get_cv2_img_from_base64(base_64_string):
    data = decode_base64(base_64_string)
    np_data = np.frombuffer(data, dtype=np.uint8)
    return cv2.imdecode(np_data, cv2.IMREAD_UNCHANGED)
0
Gabriel P.