programing

Python: base64 디코딩 시 '잘못된 패딩' 오류 무시

lastmoon 2023. 7. 6. 22:32
반응형

Python: base64 디코딩 시 '잘못된 패딩' 오류 무시

나는 base64로 인코딩된 일부 데이터를 가지고 있어서 패딩 오류가 있더라도 바이너리로 다시 변환하고 싶습니다.사용할 경우

base64.decodestring(b64_string)

'잘못된 패딩' 오류가 발생합니다.다른 방법이 없나요?

업데이트: 모든 피드백에 감사드립니다.솔직히 언급된 모든 방법들이 약간 히트하고 빗나가서 openssl을 시도해보기로 했습니다.다음 명령은 효과가 있었습니다.

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

디코딩하기 전에 바이트에 패딩만 추가하면 되는 것 같습니다.이 질문에 대한 다른 많은 답변이 있지만, 저는 그것을 지적하고 싶습니다(적어도 파이썬 3.x에서는).base64.b64decode추가 패딩이 처음부터 충분히 있는 경우 이를 잘라냅니다.

다음과 같은 것이 있습니다.b'abc='와 마찬가지로 잘 작동합니다.b'abc=='(하는 바와 같이b'abc=====').

할 수 . 즉 두 개의 할 수 있습니다.b'=='파일을 .base64는 파일 이름입니다.

이를 통해 다음과 같이 쓸 수 있습니다.

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

이는 다음보다 단순합니다.

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

이 " 자문열이만약이"인 경우 하십시오.s 이패이있예다니습딩)이 .b"aGVsbG8="), 이 접근 방식은 다음과 같은 경우에만 작동합니다.validate키워드 인수가 다음으로 설정되었습니다.False(기본값).한다면validate이라True이것은 결과를 초래할 것입니다.binascii.Error총 패딩 길이가 2자를 초과할 경우 상승됩니다.

문서에서:

Validate가 다음인 경우False(기본값), 일반 base-64 알파벳이나 대체 알파벳에 없는 문자는 패딩 검사 전에 삭제됩니다.Validate가 다음인 경우True입력에 있는 이러한 비선택적 문자는 결과적으로 다음과 같습니다.binascii.Error.

만약 만지면, 에약.validate이라False(또는 기본값으로 비워두기) 문제 없이 두 개의 패딩 문자를 맹목적으로 추가할 수 있습니다.EIGHEZ님께서 댓글로 지적해주셔서 감사합니다.

다른 응답에서 말했듯이 base64 데이터가 손상될 수 있는 다양한 방법이 있습니다.

그러나 위키백과에서 말하는 것처럼 패딩(base64 인코딩 데이터의 끝에 있는 '=' 문자)을 제거하는 것은 "무손실"입니다.

이론적인 관점에서, 누락된 바이트 수는 기본 64자리 숫자로 계산할 수 있기 때문에 패딩 문자가 필요하지 않습니다.

따라서 이것이 base64 데이터에서 유일하게 "잘못된" 것이라면 패딩을 다시 추가할 수 있습니다.저는 WeasyPrint의 "데이터" URL을 구문 분석할 수 있도록 이것을 고안했는데, 그 중 일부는 패딩이 없는 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/tests/test_css.py#L68

필요에 따라 패딩만 추가하면 됩니다.하지만 마이클의 경고에 주의하세요.

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

"잘못된 패딩"은 "누락된 패딩" 뿐만 아니라 (믿거나 말거나) "잘못된 패딩"을 의미할 수 있습니다.

제안된 "패딩 추가" 방법이 작동하지 않으면 일부 후행 바이트를 제거해 보십시오.

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-safe 방식으로 인코딩이 수행되었을 수 있습니다.이 경우 데이터에서 마이너스 및 밑줄 문자를 볼 수 있으며 다음을 사용하여 디코딩할 수 있습니다.base64.b64decode(strg, '-_')

데이터에서 마이너스 및 밑줄 문자는 볼 수 없지만 플러스 및 슬래시 문자는 볼 수 있는 경우 다른 문제가 있으며 추가 패딩 또는 제거 크래프트 트릭이 필요할 수 있습니다.

데이터에서 빼기, 밑줄, 더하기 및 슬래시가 보이지 않으면 두 개의 대체 문자를 결정해야 합니다. [A-Za-z0-9]에 없는 문자입니다.그런 다음 두 번째 Arg에서 어떤 순서로 사용해야 하는지 실험해야 합니다.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

사용하다

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'

>>> 

패딩 오류가 발생하면 문자열이 손상된 것일 수 있습니다. base64 인코딩 문자열의 길이는 4개여야 합니다. 캐릭터패딩캐릭추수있다니습볼가해를터▁(▁the다패니▁adding▁you▁character)를 추가해 볼 수 .=) 자신이 문자열을 4의 배수로 만들지만, 잘못된 경우가 아니라면 이미 문자열이 있어야 합니다.

잘못된 패딩 오류가 발생하는 이유는 인코딩된 문자열에도 메타데이터가 있기 때문입니다. 문자열이 'data:image/png;base64,...base64 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")

간단히 사용할 수 있습니다.base64.urlsafe_b64decode(data)웹 이미지를 디코딩하려는 경우.그것은 자동으로 패딩을 처리할 것입니다.

디코딩하려는 데이터 원본의 설명서를 확인합니다.당신이 의도했던 것이 가능합니까?base64.urlsafe_b64decode(s)base64.b64decode(s)이러한 이유로 이 오류 메시지가 표시되었을 수 있습니다.

표준 Base64 알파벳에서 +와 _ 대신에 / 대신에 -를 대체하는 URL 안전 알파벳을 사용하여 문자열을 디코딩합니다.

예를 들어, Google의 Identity Toolkit 및 Gmail 페이로드와 같은 다양한 Google API의 경우입니다.

패딩을 추가하는 것은 오히려...안절부절못하는여기 제가 이 스레드에 있는 댓글과 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)

여기에 설명된 입력 데이터를 수정하거나, 더 구체적으로, OP와 일치하는 두 가지 방법이 있습니다. Python 모듈 base64의 b64 디코딩 방법은 잡히지 않은 예외를 발생시키지 않고 입력 데이터를 처리할 수 있습니다.

  1. 입력 데이터 끝에 ==를 추가하고 base64.b64(...)를 호출합니다.
  2. 만약 그것이 예외를 제기한다면,

    시도/제외를 통해 캐치합니다.

    ii. (R?)입력 데이터에서 = 문자를 제거합니다(N.B. 필요하지 않을 수 있음).

    iii. 입력 데이터에 A==를 추가합니다(A==에서 P==까지 작동).

    iv. A==가 추가된 입력 데이터가 있는 base64.b64(...)로 전화하십시오.

위의 항목 1. 또는 항목 2.의 결과는 원하는 결과를 산출합니다.

주의사항

이렇게 하면 디코딩된 결과가 원래 인코딩된 결과가 된다는 보장은 없지만, OP에 다음 작업을 충분히 제공합니다(때로는?).

손상이 있더라도 ASN.1 스트림에서 유용한 정보를 얻을 수 있기 때문에 바이너리로 돌아가고 싶습니다.")

아래 내용가정참조하십시오.

TL;DR

base64.b64decode(...)의 일부 빠른 테스트에서

  1. [A-Za-z0-9+/] 이외의 문자는 무시하는 것으로 보입니다. 여기에는 4개의 구문 분석 그룹에서 마지막 문자가 아닌 경우 =를 무시하는 것이 포함됩니다. 이 경우 =는 디코딩을 종료합니다(a=b=c=d=는 ab=와 동일한 결과를 제공하고, a==b==c==와 동일한 결과를 제공함).

  2. 또한 base64.b64"(...)가 그룹의 네 번째로 =에서 디코딩을 종료하는 시점 이후에는 추가된 모든 문자가 무시되는 것으로 나타납니다.

위의 몇 가지 설명에서 언급한 것처럼, [해당 지점에 대한 구문 분석된 문자 수 4] 값이 각각 0 또는 3 또는 2일 때 입력 데이터 끝에 필요한 패딩 =가 0 또는 1 또는 2개 있습니다.따라서 위의 항목 3.과 4.부터 입력 데이터에 두 개 이상의 =를 추가하면 이러한 경우 [잘못된 패딩] 문제가 수정됩니다.

그러나, 디코딩은 [총 파싱된 문자 수 modulo 4]가 1인 경우를 처리할 수 없습니다. 디코딩된 3개의 바이트 그룹에서 첫 번째 디코딩된 바이트를 나타내기 위해서는 적어도 2개의 인코딩된 문자가 필요하기 때문입니다.손상되지 않은 인코딩된 입력 데이터에서는 이 [N모듈로 4]=1의 경우는 절대 발생하지 않지만 OP에서 문자가 누락될 수 있다고 언급한 것처럼 여기서 발생할 수 있습니다.그렇기 때문에 단순히 =를 추가하는 것이 항상 작동하는 것은 아니며, ==를 추가할 때 A==를 추가하는 것은 작동하지 않습니다. N.B. [A]를 사용하는 것은 거의 임의적입니다. [A]는 디코딩에 지워진 (0) 비트만 추가합니다. 이는 정확성이 아닐 수도 있지만 여기서 객체는 정확성이 아니라 base64.b64(...) 예외적으로 완료됩니다.

우리가 OP와 특히 후속 코멘트를 통해 알고 있는 은.

  • Base64 인코딩된 입력 데이터에 누락된 데이터(문자)가 있는 것으로 의심됩니다.
  • Base64 인코딩은 표준 64 자리 값 더하기 패딩을 사용합니다. A-Z; a-z; 0-9; +; /; =는 패딩입니다.이것은 확인되거나 적어도 시사되는 사실에 의해 확인됩니다.openssl enc ...작동하다.

가정

  • 입력 데이터에는 7비트 ASCII 데이터만 포함됩니다.
  • 유일한 손상 유형은 인코딩된 입력 데이터 누락입니다.
  • OP는 누락된 인코딩된 입력 데이터에 해당하는 디코딩된 출력 데이터에 대해 어느 시점에서도 신경 쓰지 않습니다.

깃헙

다음은 이 솔루션을 구현하기 위한 래퍼입니다.

https://github.com/drbitboy/missing_b64

나는 base64를 사용하지 않고 이 오류를 얻었습니다.그래서 저는 로컬 호스트에 오류가 있다는 해결책을 얻었습니다. 127.0.0.1에서 잘 작동합니다.

제 경우 Gmail Web API는 이메일 내용을 base64 인코딩 문자열로 반환했지만 표준 base64 문자/알파벳으로 인코딩하는 대신 "web-safe" 문자/알파벳 변형인 base64로 인코딩했습니다.+그리고./가 문가로대됨으로 됩니다.-그리고._ python 3을 합니다.base64.urlsafe_b64decode().

이 작업은 한 줄로 수행할 수 있습니다. 임시 변수를 추가할 필요가 없습니다.

b64decode(f"{s}{'=' * (4 - len(s) % 4)}")

이 오류가 웹 서버에서 발생한 경우:게시물 값을 url 인코딩해 보십시오."curl"을 통해 POST를 진행하던 중 "+"와 같은 문자가 이스케이프되지 않도록 기본 64 값을 URL 인코딩하고 있지 않다는 것을 발견하여 웹 서버 url-decode 로직이 자동으로 url-decode를 실행하고 +를 공간으로 변환했습니다.

는 유효한 base64 문자이며 예상치 못한 url-dump에 의해 망가지는 유일한 문자일 수 있습니다.

사용해야 합니다.

base64.b64decode(b64_string, ' /')

는 "altchar"입니다.'+/'.

저도 이 문제에 부딪혔지만 아무 것도 작동하지 않았습니다.저는 마침내 저에게 맞는 해결책을 찾을 수 있었습니다.64번 베이스에 내용을 압축했는데 백만개의 레코드 중에 하나가...

이것은 사이먼 사핀이 제안한 솔루션 버전입니다.

패딩이 3개가 누락된 경우 마지막 3개 문자를 삭제합니다.

"0gA1" 대신RD5L/9AugtH9MzAwAAA=="

우리는 "0gA1"을 얻습니다.RD5L/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)   

base64의 이 답변에 따르면 이유는 null입니다.하지만 인코더가 왜 이걸 엉망으로 만드는지 아직도 모르겠어요

def base64_decode(data: str) -> str:
    
    data = data.encode("ascii")

    rem = len(data) % 4

    if rem > 0:
        data += b"=" * (4 - rem)
    return base64.urlsafe_b64decode(data).decode('utf-8')

대상 문자열 값을 디코딩하기 전에 "=" 또는 다른 문자를 추가하고 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)

저의 경우 이메일을 구문 분석하는 동안 해당 오류가 발생했습니다.첨부파일을 base64 string으로 받아서 re.search를 통해 추출합니다.결국 마지막에 이상한 추가 하위 문자열이 있었습니다.

dHJhaWxlcgo8PCAvU2l6ZSAxNSAvUm9vdCAxIDAgUiAvSW5mbyAyIDAgUgovSUQgWyhcMDAyXDMz
MHtPcFwyNTZbezU/VzheXDM0MXFcMzExKShcMDAyXDMzMHtPcFwyNTZbezU/VzheXDM0MXFcMzEx
KV0KPj4Kc3RhcnR4cmVmCjY3MDEKJSVFT0YK

--_=ic0008m4wtZ4TqBFd+sXC8--

가 ㅠㅠㅠㅠㅠㅠㅠㅠㅠ을 했을 때.--_=ic0008m4wtZ4TqBFd+sXC8--그리고 문자열을 제거한 다음 구문 분석이 수정되었습니다.

따라서 올바른 base64 문자열을 디코딩하는 것이 좋습니다.

브라우저 쿠키를 지우고 다시 확인하면 작동합니다.

저의 경우, 특정 프로젝트의 venv를 삭제한 후 각 필드에 오류가 표시되어 Browser(Chrome에서 Edge로)를 변경하여 사용해 보았는데, 실제로 작동했습니다.

언급URL : https://stackoverflow.com/questions/2941995/python-ignore-incorrect-padding-error-when-base64-decoding

반응형