Python: ละเว้นข้อผิดพลาด 'ช่องว่างที่ไม่ถูกต้อง' เมื่อถอดรหัส base64


112

ฉันมีข้อมูลบางอย่างที่เข้ารหัส base64 ซึ่งฉันต้องการแปลงกลับเป็นไบนารีแม้ว่าจะมีข้อผิดพลาดในการเติม ถ้าฉันใช้

base64.decodestring(b64_string)

ทำให้เกิดข้อผิดพลาด 'ช่องว่างภายในไม่ถูกต้อง' มีวิธีอื่นอีกไหม

UPDATE: ขอบคุณสำหรับทุกคำติชม บอกตามตรงว่าวิธีการทั้งหมดที่กล่าวมาฟังดูไม่ค่อยดีและพลาดดังนั้นฉันจึงตัดสินใจลอง openssl คำสั่งต่อไปนี้ใช้งานได้:

openssl enc -d -base64 -in b64string -out binary_data

5
คุณลองใช้จริงbase64.b64decode(strg, '-_')หรือไม่? นั่นเป็นพื้นฐานโดยที่คุณไม่ต้องกังวลในการจัดหาข้อมูลตัวอย่างซึ่งเป็นวิธีแก้ปัญหาของ Python ที่น่าจะเป็นไปได้มากที่สุด "วิธีการ" ที่เสนอคือข้อเสนอแนะในการแก้ปัญหาโดยเฉพาะอย่างยิ่ง "ตีแล้วพลาด" เนื่องจากความไม่เพียงพอของข้อมูลที่ให้มา
John Machin

2
@ John Machin: ใช่ฉันลองวิธีของคุณแล้ว แต่มันไม่ได้ผล ข้อมูลเป็นความลับของ บริษัท
FunLovinCoder

3
ลองbase64.urlsafe_b64decode(s)
Daniel F

คุณช่วยให้ผลลัพธ์ของสิ่งนี้: ได้sorted(list(set(b64_string)))โปรด? หากไม่มีการเปิดเผยข้อมูลใด ๆ ที่เป็นความลับของ บริษัท ควรเปิดเผยว่าอักขระใดที่ใช้ในการเข้ารหัสข้อมูลดั้งเดิมซึ่งอาจให้ข้อมูลเพียงพอที่จะให้โซลูชันที่ไม่ตีหรือพลาด
Brian Carcich

ใช่ฉันรู้ว่ามันได้รับการแก้ไขแล้ว แต่ตามจริงแล้วโซลูชัน openssl ก็ฟังดูน่าสนใจสำหรับฉันเช่นกัน
Brian Carcich

คำตอบ:


79

ดังที่กล่าวไว้ในคำตอบอื่น ๆ มีหลายวิธีที่ข้อมูล base64 อาจเสียหายได้

อย่างไรก็ตามตามที่Wikipediaกล่าวการลบช่องว่างภายใน (อักขระ '=' ที่ส่วนท้ายของข้อมูลที่เข้ารหัส base64) คือ "lossless":

จากมุมมองทางทฤษฎีไม่จำเป็นต้องใช้อักขระช่องว่างเนื่องจากจำนวนไบต์ที่หายไปสามารถคำนวณได้จากจำนวนฐาน 64 หลัก

ดังนั้นหากนี่เป็นเพียงสิ่งเดียวที่ "ผิด" กับข้อมูล base64 ของคุณช่องว่างภายในสามารถเพิ่มกลับได้ ฉันคิดสิ่งนี้ขึ้นมาเพื่อให้สามารถแยกวิเคราะห์ URL "data" ใน WeasyPrint ซึ่งบางส่วนเป็น base64 โดยไม่มีช่องว่างภายใน:

import base64
import re

def decode_base64(data, altchars=b'+/'):
    """Decode base64, padding being optional.

    :param data: Base64 data as an ASCII byte string
    :returns: The decoded byte string.

    """
    data = re.sub(rb'[^a-zA-Z0-9%s]+' % altchars, b'', data)  # normalize
    missing_padding = len(data) % 4
    if missing_padding:
        data += b'='* (4 - missing_padding)
    return base64.b64decode(data, altchars)

การทดสอบฟังก์ชันนี้: weasyprint / testing / test_css.py # L68


2
หมายเหตุ: ASCII ไม่ใช่ Unicode ดังนั้นเพื่อความปลอดภัยคุณอาจต้องการstr(data)
MarkHu

4
นี่เป็นสิ่งที่ดีโดยมีข้อแม้เดียว base64.decodestring เลิกใช้แล้วให้ใช้ base64.b64_decode
ariddell

2
ชี้แจงในวันที่ความคิดเห็น @ariddell base64.decodestringได้เลิกใช้สำหรับbase64.decodebytesใน Py3 base64.b64decodeแต่สำหรับความเข้ากันได้รุ่นที่ดีกว่ากับการใช้งาน
Cas

เนื่องจากbase64โมดูลไม่สนใจอักขระที่ไม่ใช่ base64 ที่ไม่ถูกต้องในอินพุตก่อนอื่นคุณต้องทำให้ ข้อมูลเป็นปกติ ลบสิ่งที่ไม่ได้เป็นตัวอักษรหลัก/หรือ+และแล้วเพิ่มช่องว่างภายใน
Martijn Pieters

39

เพียงเพิ่มช่องว่างภายในตามต้องการ อย่างไรก็ตามระวังคำเตือนของ Michael

b64_string += "=" * ((4 - len(b64_string) % 4) % 4) #ugh

2
มีบางอย่างที่ง่ายกว่านั้นอย่างแน่นอนที่จะจับคู่ 0 ถึง 0, 2 ถึง 1 และ 1 ถึง 2
badp

2
เหตุใดคุณจึงขยายเป็นผลคูณของ 3 แทนที่จะเป็น 4
Michael Mrozek

นั่นคือสิ่งที่บทความวิกิพีเดียบน base64 ดูเหมือนจะบอกเป็นนัยว่า
badp

1
@bp: ในการเข้ารหัส base64 แต่ละอินพุตไบนารี 24 บิต (3 ไบต์) จะถูกเข้ารหัสเป็นเอาต์พุต 4 ไบต์ output_len% 3 ไม่สมเหตุสมผล
John Machin

8
เพียงแค่ต่อท้าย===ก็ใช้ได้ผลเสมอ =ตัวอักษรพิเศษใด ๆจะถูกทิ้งอย่างปลอดภัยโดย Python
Acumenus

33

ดูเหมือนว่าคุณต้องเพิ่มช่องว่างภายในไบต์ของคุณก่อนที่จะถอดรหัส มีคำตอบอื่น ๆ อีกมากมายสำหรับคำถามนี้ แต่ฉันต้องการชี้ให้เห็นว่า (อย่างน้อยใน Python 3.x) base64.b64decodeจะตัดทอนช่องว่างเพิ่มเติมใด ๆ หากมีเพียงพอตั้งแต่แรก

ดังนั้นสิ่งที่ชอบ: ใช้b'abc='งานได้ดีเช่นเดียวกับb'abc=='(เช่นเดียวกับb'abc=====')

สิ่งนี้หมายความว่าคุณสามารถเพิ่มจำนวนอักขระ padding สูงสุดที่คุณต้องการได้ซึ่งก็คือสามตัว ( b'===') และ base64 จะตัดทอนอักขระที่ไม่จำเป็นออก

สิ่งนี้ช่วยให้คุณเขียน:

base64.b64decode(s + b'===')

ซึ่งง่ายกว่า:

base64.b64decode(s + b'=' * (-len(s) % 4))

1
โอเคไม่ "น่าเกลียด" เกินไปขอบคุณ :) โดยวิธีการที่ฉันคิดว่าคุณไม่จำเป็นต้องมีตัวอักษรขยายมากกว่า 2 ตัว อัลกอริทึม Base64 ทำงานกับกลุ่ม 3 ตัวอักษรในแต่ละครั้งและต้องการช่องว่างภายในเมื่อตัวอักษรกลุ่มสุดท้ายของคุณมีความยาวเพียง 1 หรือ 2 ตัวอักษรเท่านั้น
Otto

@ ช่องว่างภายในสำหรับถอดรหัสซึ่งใช้งานได้กับกลุ่ม 4 ตัวอักษร การเข้ารหัส Base64 ใช้งานได้กับกลุ่ม 3 ตัวอักษร :)
Henry Woody

แต่ถ้าคุณรู้ว่าในระหว่างการเข้ารหัสสูงสุด 2 จะถูกเพิ่มซึ่งอาจกลายเป็น "สูญหาย" ในภายหลังบังคับให้คุณเพิ่มใหม่ก่อนที่จะถอดรหัสคุณจะรู้ว่าคุณจะต้องเพิ่ม 2 สูงสุดในระหว่างการถอดรหัสด้วย #ChristmasTimeArgumentForTheFunOfIt
Otto

@ ฉันเชื่อว่าคุณพูดถูก ในขณะที่สตริงที่เข้ารหัส base64 ที่มีความยาวเช่น 5 จะต้องใช้อักขระ padding 3 ตัวสตริงความยาว 5 ไม่ใช่ความยาวที่ถูกต้องสำหรับสตริงที่เข้ารหัส base64 คุณจะได้รับข้อผิดพลาด: binascii.Error: Invalid base64-encoded string: number of data characters (5) cannot be 1 more than a multiple of 4. ขอบคุณที่ชี้ให้เห็น!
Henry Woody

24

"ช่องว่างภายในที่ไม่ถูกต้อง" ไม่เพียง แต่หมายถึง "ช่องว่างภายในที่ขาดหายไป" แต่ยังหมายถึง "ช่องว่างภายในที่ไม่ถูกต้อง" ด้วย (เชื่อหรือไม่)

หากวิธีการ "เพิ่มช่องว่างภายใน" ที่แนะนำไม่ได้ผลให้ลองลบไบต์ต่อท้ายบางส่วน:

lens = len(strg)
lenx = lens - (lens % 4 if lens % 4 else 4)
try:
    result = base64.decodestring(strg[:lenx])
except etc

อัปเดต: การเล่นซอเกี่ยวกับการเพิ่มช่องว่างภายในหรือการลบไบต์ที่อาจไม่ดีออกจากส่วนท้ายควรทำหลังจากลบช่องว่างใด ๆ มิฉะนั้นการคำนวณความยาวจะทำให้เสีย

เป็นความคิดที่ดีหากคุณแสดงตัวอย่าง (สั้น ๆ ) ของข้อมูลที่คุณต้องการกู้คืน แก้ไขคำถามและสำเนาของคุณ / print repr(sample)วางผลมาจากการ

อัปเดต 2: เป็นไปได้ว่าการเข้ารหัสได้กระทำในลักษณะที่ปลอดภัยของ URL ในกรณีนี้คุณจะสามารถเห็นเครื่องหมายลบและขีดล่างในข้อมูลของคุณและคุณควรจะสามารถถอดรหัสได้โดยใช้base64.b64decode(strg, '-_')

หากคุณไม่เห็นอักขระลบและขีดล่างในข้อมูลของคุณ แต่สามารถเห็นอักขระบวกและเครื่องหมายทับแสดงว่าคุณมีปัญหาอื่น ๆ และอาจต้องใช้เทคนิคการเพิ่มช่องว่างหรือการลบจุดเริ่มต้น

หากคุณไม่เห็นเครื่องหมายลบขีดล่างบวกและทับในข้อมูลของคุณคุณจะต้องกำหนดอักขระทางเลือกสองตัว พวกเขาจะเป็นคนที่ไม่ได้อยู่ใน [A-Za-z0-9] จากนั้นคุณจะต้องทดลองเพื่อดูว่าต้องใช้ลำดับใดในอาร์กิวเมนต์ที่ 2 ของbase64.b64decode()

อัปเดต 3 : หากข้อมูลของคุณเป็น "ความลับของ บริษัท ":
(ก) คุณควรพูดอย่างนั้นล่วงหน้า
(ข) เราสามารถสำรวจช่องทางอื่น ๆ ในการทำความเข้าใจปัญหาซึ่งมีแนวโน้มสูงที่จะเกี่ยวข้องกับอักขระที่ใช้แทน+และ/ใน ตัวอักษรการเข้ารหัสหรือโดยการจัดรูปแบบอื่น ๆ หรืออักขระที่ไม่เกี่ยวข้อง

ช่องทางหนึ่งคือการตรวจสอบว่าอักขระที่ไม่เป็น "มาตรฐาน" ใดในข้อมูลของคุณเช่น

from collections import defaultdict
d = defaultdict(int)
import string
s = set(string.ascii_letters + string.digits)
for c in your_data:
   if c not in s:
      d[c] += 1
print d

ข้อมูลประกอบด้วยชุดอักขระ base64 มาตรฐาน ฉันค่อนข้างมั่นใจว่าปัญหาเกิดจากอักขระ 1 ตัวขึ้นไปหายไปจึงเกิดข้อผิดพลาดในการเว้นวรรค ถ้าไม่มีวิธีแก้ปัญหาที่มีประสิทธิภาพใน Python ฉันจะไปกับวิธีการเรียก openssl
FunLovinCoder

1
"วิธีแก้ปัญหา" ที่เพิกเฉยต่อข้อผิดพลาดอย่างเงียบ ๆ แทบจะไม่สมควรได้รับคำว่า "แข็งแกร่ง" ดังที่ฉันได้กล่าวไว้ก่อนหน้านี้คำแนะนำต่างๆของ Python เป็นวิธีการแก้ปัญหาเพื่อค้นหาว่าปัญหาคืออะไรการเตรียมการสำหรับโซลูชัน PRINCIPLED ... คุณไม่สนใจสิ่งนั้นหรือ?
John Machin

7
ความต้องการของฉันคือไม่แก้ปัญหาว่าทำไม base64 ถึงเสียหาย - มันมาจากแหล่งที่ฉันไม่สามารถควบคุมได้ ความต้องการของฉันคือการให้ข้อมูลเกี่ยวกับข้อมูลที่ได้รับแม้ว่าจะเสียหายก็ตาม วิธีหนึ่งในการทำเช่นนี้คือการดึงข้อมูลไบนารีออกจาก base64 ที่เสียหายเพื่อที่ฉันจะได้รวบรวมข้อมูลจาก ASN ที่อยู่เบื้องหลัง กระแส. ฉันถามคำถามเดิมเพราะฉันต้องการคำตอบสำหรับคำถามนั้นไม่ใช่คำตอบสำหรับคำถามอื่นเช่นวิธีการดีบัก base64 ที่เสียหาย
FunLovinCoder

เพียงแค่ทำให้สตริงปกติลบสิ่งที่ไม่ใช่อักขระ Base64 ทุกที่ไม่ใช่แค่เริ่มต้นหรือสิ้นสุด
Martijn Pieters

24

ใช้

string += '=' * (-len(string) % 4)  # restore stripped '='s

เครดิตไปแสดงความคิดเห็นที่ไหนสักแห่งที่นี่

>>> import base64

>>> enc = base64.b64encode('1')

>>> enc
>>> 'MQ=='

>>> base64.b64decode(enc)
>>> '1'

>>> enc = enc.rstrip('=')

>>> enc
>>> 'MQ'

>>> base64.b64decode(enc)
...
TypeError: Incorrect padding

>>> base64.b64decode(enc + '=' * (-len(enc) % 4))
>>> '1'

>>> 

4
เขาหมายถึงความคิดเห็นนี้: stackoverflow.com/questions/2941995/…
jackyalcine

22

หากมีข้อผิดพลาดในการขยายอาจหมายความว่าสตริงของคุณเสียหาย สตริงที่เข้ารหัส base64 ควรมีความยาวหลายสี่ คุณสามารถลองเพิ่มอักขระช่องว่างภายใน ( =) ด้วยตัวเองเพื่อทำให้สตริงเป็นทวีคูณของสี่ แต่ควรมีอยู่แล้วเว้นแต่จะมีบางอย่างผิดปกติ


ข้อมูลไบนารีพื้นฐานคือ ASN.1 แม้จะมีความเสียหายฉันก็ต้องการกลับไปที่ไบนารีเพราะฉันยังสามารถรับข้อมูลที่เป็นประโยชน์จากสตรีม ASN.1 ได้
FunLovinCoder

ไม่เป็นความจริงถ้าคุณต้องการถอดรหัส jwt เพื่อตรวจสอบความปลอดภัยคุณจะต้องใช้
DAG

4

ตรวจสอบเอกสารของแหล่งข้อมูลที่คุณกำลังพยายามถอดรหัส เป็นไปได้ไหมที่คุณตั้งใจจะใช้base64.urlsafe_b64decode(s)แทนbase64.b64decode(s)? นั่นเป็นเหตุผลหนึ่งที่คุณอาจเห็นข้อความแสดงข้อผิดพลาดนี้

ถอดรหัสสตริงโดยใช้ตัวอักษรที่ปลอดภัยสำหรับ URL ซึ่งใช้แทน - แทน + และ _ แทน / ในตัวอักษร Base64 มาตรฐาน

นี่เป็นตัวอย่างสำหรับ Google APIs ต่างๆเช่น Identity Toolkit ของ Google และเพย์โหลดของ Gmail


1
นี้ไม่ตอบคำถามเลย นอกจากurlsafe_b64decodeนี้ยังต้องมีช่องว่างภายใน
rdb

ฉันมีปัญหาก่อนที่จะตอบคำถามนี้ซึ่งเกี่ยวข้องกับ Identity Toolkit ของ Google ฉันได้รับข้อผิดพลาดของช่องว่างภายในที่ไม่ถูกต้อง (ฉันเชื่อว่ามันอยู่บนเซิร์ฟเวอร์) แม้ว่าช่องว่างภายในจะดูยากก็ตาม base64.urlsafe_b64decodeกลับกลายเป็นว่าผมต้องใช้
Daniel F

ฉันยอมรับว่ามันไม่ได้ตอบคำถาม rdb แต่มันก็เป็นสิ่งที่ฉันต้องการฟังเช่นกัน ฉันเปลี่ยนคำตอบเป็นน้ำเสียงที่ดีกว่านี้ฉันหวังว่านี่จะเหมาะกับคุณแดเนียล
Henrik Heimbuerger

ดีอย่างสมบูรณ์แบบ ฉันไม่ได้สังเกตว่ามันฟังดูไร้ความปรานีฉันแค่คิดว่ามันจะเป็นการแก้ไขที่เร็วที่สุดถ้ามันจะแก้ไขปัญหาได้และด้วยเหตุนี้ควรเป็นสิ่งแรกที่ต้องลอง ขอขอบคุณสำหรับการเปลี่ยนแปลงของคุณยินดีต้อนรับ
Daniel F

คำตอบนี้ช่วยแก้ปัญหาของฉันในการถอดรหัส Google Access Token ที่มาจาก JWT ความพยายามอื่น ๆ ทั้งหมดทำให้เกิด "ช่องว่างภายในไม่ถูกต้อง"
John Hanley

2

การเพิ่มช่องว่างภายในค่อนข้าง ... นี่คือฟังก์ชั่นที่ผมเขียนด้วยความช่วยเหลือของความคิดเห็นในกระทู้นี้เช่นเดียวกับหน้าวิกิพีเดียสำหรับ base64 (มันเป็นประโยชน์ที่น่าแปลกใจ) เดอะhttps://en.wikipedia.org/wiki/Base64#Padding

import logging
import base64
def base64_decode(s):
    """Add missing padding to string and return the decoded base64 string."""
    log = logging.getLogger()
    s = str(s).strip()
    try:
        return base64.b64decode(s)
    except TypeError:
        padding = len(s) % 4
        if padding == 1:
            log.error("Invalid base64 string: {}".format(s))
            return ''
        elif padding == 2:
            s += b'=='
        elif padding == 3:
            s += b'='
        return base64.b64decode(s)

2

คุณสามารถใช้base64.urlsafe_b64decode(data)หากคุณกำลังพยายามถอดรหัสภาพบนเว็บ มันจะดูแลช่องว่างภายในโดยอัตโนมัติ


ช่วยได้จริง!
ดวงจันทร์

2

เกิดข้อผิดพลาดในการเพิ่มช่องว่างที่ไม่ถูกต้องเนื่องจากบางครั้งข้อมูลเมตายังอยู่ในสตริงที่เข้ารหัสด้วยหากสตริงของคุณมีลักษณะดังนี้: 'data: image / png; base64, ... base 64 stuff .... ' คุณต้องลบสิ่งแรกออก ก่อนที่จะถอดรหัส

บอกว่าคุณมีสตริงเข้ารหัสรูปภาพ base64 หรือไม่ลองด้านล่างตัวอย่าง ..

from PIL import Image
from io import BytesIO
from base64 import b64decode
imagestr = 'data:image/png;base64,...base 64 stuff....'
im = Image.open(BytesIO(b64decode(imagestr.split(',')[1])))
im.save("image.png")

1

มีสองวิธีในการแก้ไขข้อมูลอินพุตที่อธิบายไว้ที่นี่หรือโดยเฉพาะอย่างยิ่งและสอดคล้องกับ OP เพื่อให้เมธอด b64decode ของ Python base64 สามารถประมวลผลข้อมูลอินพุตไปยังบางสิ่งได้โดยไม่ต้องเพิ่มข้อยกเว้นที่ไม่ถูกจับ:

  1. ต่อท้าย == ต่อท้ายข้อมูลอินพุตและเรียก base64.b64decode (... )
  2. หากนั่นทำให้เกิดข้อยกเว้นขึ้นมา

    ผม. จับได้ด้วยการลอง / ยกเว้น

    ii. (R?) Strip any = อักขระจากข้อมูลอินพุต (NB ซึ่งอาจไม่จำเป็น),

    สาม. ผนวก A == เข้ากับข้อมูลอินพุต (A == ถึง P == จะทำงาน)

    iv. เรียก base64.b64decode (... ) ด้วย A == - ข้อมูลอินพุตที่ต่อท้าย

ผลลัพธ์จากรายการ 1. หรือรายการ 2. ด้านบนจะให้ผลลัพธ์ที่ต้องการ

ข้อควรระวัง

สิ่งนี้ไม่ได้รับประกันว่าผลลัพธ์ที่ถอดรหัสจะเป็นสิ่งที่เข้ารหัสไว้ แต่เดิม (บางครั้ง?) จะให้ OP เพียงพอที่จะทำงานกับ:

แม้จะมีการทุจริตฉันก็ต้องการกลับไปที่ไบนารีเพราะฉันยังสามารถรับข้อมูลที่เป็นประโยชน์จากสตรีม ASN.1 ")

ดูสิ่งที่เรารู้และสมมติฐานด้านล่าง

TL; ดร

จากการทดสอบอย่างรวดเร็วของ base64.b64decode (... )

  1. ดูเหมือนว่าจะไม่สนใจอักขระที่ไม่ใช่ [A-Za-z0-9 + /] ซึ่งรวมถึงการละเว้น = s เว้นแต่ว่าจะเป็นอักขระสุดท้ายในกลุ่มที่แยกวิเคราะห์เป็นสี่กลุ่มซึ่งในกรณีนี้ = s จะยุติการถอดรหัส (a = b = c = d = ให้ผลลัพธ์เช่นเดียวกับ abc = และ a = = b == c == ให้ผลลัพธ์เหมือนกับ ab ==)

  2. นอกจากนี้ยังดูเหมือนว่าอักขระทั้งหมดที่ต่อท้ายจะถูกละเว้นหลังจากจุดที่ base64.b64decode (... ) ยุติการถอดรหัสเช่นจาก = เป็นตัวที่สี่ในกลุ่ม

ตามที่ระบุไว้ในหลายความคิดเห็นด้านบนมีช่องว่างที่ต้องการเป็นศูนย์หรือหนึ่งหรือสอง = s ที่ส่วนท้ายของข้อมูลอินพุตเมื่อค่า [จำนวนอักขระที่แยกวิเคราะห์ไปยังจุดนั้นโมดูโล 4] เป็น 0 หรือ 3 หรือ 2 ตามลำดับ ดังนั้นจากรายการ 3. และ 4. ด้านบนการต่อท้าย = s สองตัวขึ้นไปในข้อมูลอินพุตจะช่วยแก้ไขปัญหา [ช่องว่างที่ไม่ถูกต้อง] ในกรณีเหล่านั้น

อย่างไรก็ตามการถอดรหัสไม่สามารถจัดการกับกรณีที่ [จำนวนอักขระที่แยกวิเคราะห์ modulo 4] เป็น 1 ได้เนื่องจากต้องใช้อักขระที่เข้ารหัสอย่างน้อยสองตัวเพื่อแทนไบต์แรกที่ถอดรหัสในกลุ่มที่มีสามไบต์ที่ถอดรหัส ในข้อมูลอินพุตที่เข้ารหัสโดยไม่เสียหาย [N modulo 4] = 1 กรณีนี้ไม่เคยเกิดขึ้น แต่เนื่องจาก OP ระบุว่าอักขระอาจขาดหายไปจึงอาจเกิดขึ้นที่นี่ นั่นคือเหตุผลที่การต่อท้าย = s ไม่ได้ผลเสมอไปและเหตุใดการต่อท้ายA == จึงใช้ได้ผลเมื่อไม่ต่อท้าย == NB การใช้ [A] เป็นทั้งหมดยกเว้นตามอำเภอใจ: เพิ่มเฉพาะบิตเคลียร์ (ศูนย์) ให้กับการถอดรหัสซึ่งอาจถูกต้องหรือไม่ก็ได้ แต่วัตถุที่นี่ไม่ถูกต้อง แต่เสร็จสมบูรณ์โดย base64.b64decode (... ) ไม่มีข้อยกเว้น .

สิ่งที่เรารู้จาก OP และโดยเฉพาะอย่างยิ่งความคิดเห็นที่ตามมาคือ

  • สงสัยว่าจะมีข้อมูลที่ขาดหายไป (อักขระ) ในข้อมูลอินพุตที่เข้ารหัส Base64
  • การเข้ารหัส Base64 ใช้มาตรฐาน 64 place-values ​​บวก padding: AZ; az; 0-9; +; /; = เป็นช่องว่างภายใน สิ่งนี้ได้รับการยืนยันหรืออย่างน้อยก็แนะนำโดยข้อเท็จจริงที่ได้openssl enc ...ผล

สมมติฐาน

  • ข้อมูลอินพุตประกอบด้วยข้อมูล ASCII 7 บิตเท่านั้น
  • ความเสียหายประเภทเดียวคือไม่มีข้อมูลอินพุตที่เข้ารหัส
  • OP ไม่สนใจข้อมูลเอาต์พุตที่ถอดรหัส ณ จุดใดก็ได้หลังจากนั้นซึ่งสอดคล้องกับข้อมูลอินพุตที่เข้ารหัสที่ขาดหาย

Github

นี่คือ Wrapper เพื่อใช้โซลูชันนี้:

https://github.com/drbitboy/missing_b64


0

เพียงเพิ่มอักขระเพิ่มเติมเช่น "=" หรืออื่น ๆ และทำให้เป็นผลคูณของ 4 ก่อนที่คุณจะลองถอดรหัสค่าสตริงเป้าหมาย สิ่งที่ต้องการ;

if len(value) % 4 != 0: #check if multiple of 4
    while len(value) % 4 != 0:
        value = value + "="
    req_str = base64.b64decode(value)
else:
    req_str = base64.b64decode(value)

0

ในกรณีที่ข้อผิดพลาดนี้มาจากเว็บเซิร์ฟเวอร์: ลองเข้ารหัส URL ของค่าโพสต์ของคุณ ฉันกำลังโพสต์ผ่าน "curl" และพบว่าฉันไม่ได้เข้ารหัส url ค่า base64 ของฉันดังนั้นอักขระอย่าง "+" จึงไม่ได้หลบหนีดังนั้นตรรกะการถอดรหัส URL ของเว็บเซิร์ฟเวอร์จึงเรียกใช้การถอดรหัส URL และแปลง + เป็นช่องว่างโดยอัตโนมัติ

"+" เป็นอักขระ base64 ที่ถูกต้องและอาจเป็นอักขระเดียวที่ถูกทำลายโดยการถอดรหัส URL ที่ไม่คาดคิด


0

ในกรณีของฉันฉันพบข้อผิดพลาดนั้นขณะแยกวิเคราะห์อีเมล ฉันได้รับไฟล์แนบเป็นสตริง base64 และแตกไฟล์ผ่าน re.search ในที่สุดก็มีสตริงย่อยเพิ่มเติมแปลก ๆ ในตอนท้าย

dHJhaWxlcgo8PCAvU2l6ZSAxNSAvUm9vdCAxIDAgUiAvSW5mbyAyIDAgUgovSUQgWyhcMDAyXDMz
MHtPcFwyNTZbezU/VzheXDM0MXFcMzExKShcMDAyXDMzMHtPcFwyNTZbezU/VzheXDM0MXFcMzEx
KV0KPj4Kc3RhcnR4cmVmCjY3MDEKJSVFT0YK

--_=ic0008m4wtZ4TqBFd+sXC8--

เมื่อฉันลบ--_=ic0008m4wtZ4TqBFd+sXC8--และถอดสตริงการแยกวิเคราะห์ได้รับการแก้ไขแล้ว

ดังนั้นคำแนะนำของฉันคือตรวจสอบให้แน่ใจว่าคุณกำลังถอดรหัสสตริง base64 ที่ถูกต้อง


0

คุณควรใช้

base64.b64decode(b64_string, ' /')

โดยค่าเริ่มต้น altchars '+/'มี


1
ไม่ทำงานใน python 3.7 assert len ​​(altchars) == 2, repr (altchars)
Dat TT

0

ฉันพบปัญหานี้เช่นกันและไม่มีอะไรได้ผล ในที่สุดฉันก็หาวิธีแก้ปัญหาที่เหมาะกับฉัน ฉันได้ซิปเนื้อหาใน base64 และสิ่งนี้เกิดขึ้นกับ 1 ในล้านบันทึก ...

นี่คือเวอร์ชันของโซลูชันที่แนะนำโดย Simon Sapin

ในกรณีที่ช่องว่างภายในหายไป 3 ฉันจะลบอักขระ 3 ตัวสุดท้ายออก

แทนที่จะเป็น "0gA1RD5L / 9AUGtH9MzAwAAA =="

เราได้รับ "0gA1RD5L / 9AUGtH9MzAwAA"

        missing_padding = len(data) % 4
        if missing_padding == 3:
            data = data[0:-3]
        elif missing_padding != 0:
            print ("Missing padding : " + str(missing_padding))
            data += '=' * (4 - missing_padding)
        data_decoded = base64.b64decode(data)   

ตามคำตอบนี้ต่อท้ายในฐาน 64เหตุผลคือโมฆะ แต่ฉันยังไม่รู้ว่าทำไมตัวเข้ารหัสถึงยุ่งขนาดนี้ ...


0

ฉันได้รับข้อผิดพลาดนี้โดยไม่ต้องใช้ base64 ดังนั้นฉันจึงได้วิธีแก้ปัญหาว่าข้อผิดพลาดอยู่ในlocalhostมันทำงานได้ดีบน127.0.0.1


คำตอบนี้ดูเหมือนจะไม่เกี่ยวข้องกับคำถาม คุณช่วยอธิบายเพิ่มเติมได้ไหมว่าปัญหาเกิดขึ้นที่ใดและเกี่ยวข้องอย่างไร
darclander

ฉันพบปัญหานี้ใน django ขณะเรียกใช้แอปพลิเคชันบนเบราว์เซอร์ Chrome โดยปกติแอปพลิเคชัน django จะทำงานบน localhost แต่วันนี้มันไม่ทำงานใน localhost ดังนั้นผมจึงมีการเปลี่ยนแปลงนี้localhostเพื่อ127.0.0.1 ตอนนี้มันใช้งานได้แล้วมันยังทำงานบนเบราว์เซอร์อื่นเช่น firefox โดยไม่ต้องเปลี่ยน localhost
Nooras Fatima Ansari
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.