Jak sprawdzić, czy łańcuch jest zakodowany w standardzie Base64, czy nie


194

Chcę zdekodować ciąg zakodowany w standardzie Base64, a następnie zapisać go w mojej bazie danych. Jeśli dane wejściowe nie są zakodowane w standardzie Base64, muszę zgłosić błąd.

Jak mogę sprawdzić, czy ciąg znaków jest zakodowany w standardzie Base64?


Czemu? Jak może powstać sytuacja?
Markiz Lorne

2
bez określenia, który język programowania (i / lub) system operacyjny jest celem, jest to bardzo otwarte pytanie
bcarroll

5
Wszystko, co możesz ustalić, to że ciąg zawiera tylko znaki, które są poprawne dla ciągu zakodowanego w standardzie base64. Może nie być możliwe ustalenie, że ciąg jest wersją niektórych danych zakodowanych w standardzie base64. na przykład test1234jest prawidłowym ciągiem zakodowanym w standardzie base64, a kiedy go zdekodujesz, otrzymasz trochę bajtów. Nie istnieje niezależny od aplikacji sposób wnioskowania, który test1234nie jest łańcuchem zakodowanym w standardzie base64.
Kinjal Dixit

Odpowiedzi:


249

Możesz użyć następującego wyrażenia regularnego, aby sprawdzić, czy łańcuch jest zakodowany w standardzie base64:

^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$

W kodowaniu base64 zestaw znaków to [A-Z, a-z, 0-9, and + /]. Jeśli długość reszty jest mniejsza niż 4, ciąg znaków jest uzupełniany '='znakami.

^([A-Za-z0-9+/]{4})* oznacza, że ​​ciąg zaczyna się od 0 lub więcej grup base64.

([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$Oznacza końce ciągów w jednej z trzech postaci: [A-Za-z0-9+/]{4}, [A-Za-z0-9+/]{3}=lub [A-Za-z0-9+/]{2}==.


10
Chciałem tylko zweryfikować, więc pomóżcie z moim pytaniem: Jaka jest gwarancja, że ​​to wyrażenie regularne zawsze będzie odnosić się tylko do ciągu base64? Jeśli istnieje ciąg znaków bez spacji i jest on wielokrotnością 4 znaków, to czy zostanie on uznany za ciąg base64 ????
DShah

3
Jest to prawidłowy ciąg base64, który można zdekodować. Możesz dodać ograniczenie minimalnej długości; na przykład zamiast zero lub więcej powtórzeń grup po cztery, wymagają (powiedzmy) czterech lub więcej. To zależy również od twojego problemu; jeśli Twoi użytkownicy często wpisują pojedyncze słowo w języku z długimi słowami i czystym ASCII (hawajskim?), jest to bardziej podatne na błędy niż wtedy, gdy dane inne niż base64 zwykle zawierają spacje, interpunkcję itp.
tripleee

62
To tylko mówi, że wejście mogło być zakodowaną wartością b64, ale nie mówi, czy wejście jest rzeczywiście zakodowaną wartością b64. Innymi słowy, abcdbędzie pasować, ale niekoniecznie reprezentuje zakodowaną wartość raczej zwykłego abcdwejścia
Tzury Bar Yochay

3
Twoje wyrażenie regularne jest niepoprawne, ponieważ nie pasuje do pustego ciągu, z kodowaniem base64 danych binarnych o zerowej długości zgodnie z RFC 4648.
czerwonawy

5
@Adomas, "pass" jest doskonale prawidłowy ciąg base64, który dekoduje do sekwencji bajtów 0xa5, 0xaba 0x2c. Po co odrzucać to z góry , jeśli nie masz więcej kontekstu do podjęcia decyzji?
Luis Colorado,

50

Jeśli używasz Javy, możesz faktycznie użyć biblioteki kodeków commons

import org.apache.commons.codec.binary.Base64;

String stringToBeChecked = "...";
boolean isBase64 = Base64.isArrayByteBase64(stringToBeChecked.getBytes());

17
z dokumentacji: isArrayByteBase64(byte[] arrayOctet)Przestarzałe. 1.5 Użycie isBase64(byte[])zostanie usunięte w wersji 2.0.
Avinash R

7
Możesz także użyć Base64.isBase64 (String base64) zamiast samodzielnie przekonwertować go na tablicę bajtów.
Sasa

5
Niestety, na podstawie dokumentacji: commons.apache.org/proper/commons-codec/apidocs/org/apache/… : "Testuje dany ciąg znaków, aby sprawdzić, czy zawiera on tylko prawidłowe znaki w alfabecie Base64. Obecnie metoda traktuje białe znaki jako ważny." Oznacza to, że ta metoda ma pewne fałszywe alarmy, takie jak „biała spacja” lub liczby („0”, „1”).
Christian Vielma,

dla ciągu Base64.isBase64 (treść)
ema

4
Ta odpowiedź jest błędna, ponieważ podana stringToBeChecked="some plain text"wtedy ustawia, boolean isBase64=truemimo że nie jest to wartość zakodowana w standardzie Base64. Odczytaj źródło dla commons-codec-1.4 Base64.isArrayByteBase64(), sprawdza tylko, czy każdy znak w ciągu jest poprawny do uwzględnienia w kodowaniu Base64 i dopuszcza białe znaki.
Brad

49

Cóż, możesz:

  • Sprawdź, czy długość jest wielokrotnością 4 znaków
  • Sprawdź, czy każdy znak znajduje się w zbiorze AZ, az, 0-9, +, /, z wyjątkiem wypełniania na końcu, które zawiera 0, 1 lub 2 znaki „=”

Jeśli spodziewasz się, że będzie to base64, prawdopodobnie możesz po prostu użyć biblioteki dostępnej na platformie, aby spróbować ją zdekodować do tablicy bajtów, zgłaszając wyjątek, jeśli nie jest to poprawna baza 64. To zależy od twojej platformy, oczywiście.


Parsowanie różni się od sprawdzania poprawności przynajmniej tym, że wymaga pamięci dla dekodowanej tablicy bajtów. W niektórych przypadkach nie jest to najskuteczniejsze podejście.
Victor Yarema

1
@VictorYarema: Zasugerowałem zarówno podejście oparte wyłącznie na sprawdzaniu poprawności (punkty wypunktowane), jak i podejście analizujące (po punktach wypunktowanych).
Jon Skeet

16

Począwszy od Java 8, możesz po prostu użyć java.util.Base64, aby spróbować zdekodować ciąg:

String someString = "...";
Base64.Decoder decoder = Base64.getDecoder();

try {
    decoder.decode(someString);
} catch(IllegalArgumentException iae) {
    // That string wasn't valid.
}

3
tak, jest to opcja, ale nie zapominaj, że catch jest dość kosztowną operacją w Javie
panser

2
Tak już nie jest. Obsługa wyjątków działa całkiem dobrze. Lepiej nie zapomnij, że Java Regex działa dość wolno. Mam na myśli: NAPRAWDĘ WOLNIE! W rzeczywistości szybsze jest dekodowanie Base64 i sprawdzenie, czy (nie) działa ono zamiast dopasowywania ciągu znaków do powyższego wyrażenia regularnego. Zrobiłem zgrubny test i dopasowanie Java Regex jest około sześć razy wolniejsze (!!) niż wyłapanie ewentualnego wyjątku w dekodowaniu.
Sven Döring

Przy większej liczbie testów jest on jedenaście razy wolniejszy. Czas na lepszą implementację Regex w Javie. Nawet sprawdzenie Regex za pomocą silnika JavaScript Nashorn w Javie jest o wiele szybsze. Nie do wiary. Dodatkowo JavaScript Regex (z Nashorn) jest o wiele potężniejszy.
Sven Döring

3
W Javie 11 (zamiast Java 8) sprawdzanie Regex jest nawet 22 razy wolniejsze. 🤦 (Ponieważ dekodowanie Base64 stało się szybsze.)
Sven Döring

15

Spróbuj tego w PHP5

//where $json is some data that can be base64 encoded
$json=some_data;

//this will check whether data is base64 encoded or not
if (base64_decode($json, true) == true)
{          
   echo "base64 encoded";          
}
else 
{
   echo "not base64 encoded"; 
}

Użyj tego dla PHP7

 //$string parameter can be base64 encoded or not

function is_base64_encoded($string){
 //this will check if $string is base64 encoded and return true, if it is.
 if (base64_decode($string, true) !== false){          
   return true;        
 }else{
   return false;
 }
}

1
Jaki to język? Pytanie zadano bez odwoływania się do języka
Ozkan

to nie zadziała. przeczytaj dokumentację Returns FALSE if input contains character from outside the base64 alphabet. base64_decode
Aley

1
W jaki sposób? jeśli wejście zawiera znak zewnętrzny, to nie jest to base64, prawda?
Suneel Kumar

7
var base64Rejex = /^(?:[A-Z0-9+\/]{4})*(?:[A-Z0-9+\/]{2}==|[A-Z0-9+\/]{3}=|[A-Z0-9+\/]{4})$/i;
var isBase64Valid = base64Rejex.test(base64Data); // base64Data is the base64 string

if (isBase64Valid) {
    // true if base64 formate
    console.log('It is base64');
} else {
    // false if not in base64 formate
    console.log('it is not in base64');
}

5

Sprawdź, czy JEŻELI długość łańcucha jest wielokrotnością 4. Po drugiej stronie tego wyrażenia regularnego upewnij się, że wszystkie znaki w łańcuchu są znakami base64.

\A[a-zA-Z\d\/+]+={,2}\z

Jeśli używana biblioteka dodaje nowy wiersz jako sposób na przestrzeganie 76 maksymalnych znaków w linii, zastąp je pustymi łańcuchami.


Wspomniany link pokazuje 404. Sprawdź i zaktualizuj.
Ankur

Niestety @AnkurKumar, ale tak się dzieje, gdy ludzie mają niechłodzone adresy URL: cały czas się zmieniają. Nie mam pojęcia, dokąd się to przeniosło. Mam nadzieję, że znajdziesz inne przydatne zasoby za pośrednictwem Google
Yaw Boakye

Zawsze możesz pobrać stare strony z web.archive.org - oto oryginalny adres URL. web.archive.org/web/20120919035911/http://… lub zamieściłem tekst tutaj: gist.github.com/mika76/d09e2b65159e435e7a4cc5b0299c3e84
Mladen Mihajlovic

4

Istnieje wiele wariantów Base64 , więc zastanów się nad ustaleniem, czy Twój ciąg znaków przypomina zmienną, którą spodziewasz się obsłużyć. Jako taka, może być konieczne, aby dostosować regex poniżej w odniesieniu do indeksu i wypełnienie znaków (czyli +, /, =).

class String
  def resembles_base64?
    self.length % 4 == 0 && self =~ /^[A-Za-z0-9+\/=]+\Z/
  end
end

Stosowanie:

raise 'the string does not resemble Base64' unless my_string.resembles_base64?

3

Spróbuj tego:

public void checkForEncode(String string) {
    String pattern = "^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$";
    Pattern r = Pattern.compile(pattern);
    Matcher m = r.matcher(string);
    if (m.find()) {
        System.out.println("true");
    } else {
        System.out.println("false");
    }
}

3

Nie można sprawdzić, czy łańcuch jest zakodowany w standardzie base64, czy nie. Sprawdzanie poprawności jest możliwe tylko wtedy, gdy ten ciąg ma format łańcucha zakodowany w standardzie base64, co oznaczałoby, że może to być ciąg utworzony przez kodowanie base64 (aby sprawdzić, czy łańcuch może być sprawdzony pod kątem wyrażenia regularnego lub można użyć biblioteki, wiele inne odpowiedzi na to pytanie zapewniają dobre sposoby na sprawdzenie tego, więc nie będę wchodził w szczegóły).

Na przykład ciąg flowjest prawidłowym ciągiem zakodowanym w standardzie base64. Nie można jednak ustalić, czy jest to zwykły ciąg, angielskie słowo flow, czy też ciąg znaków zakodowany w podstawie 64~Z0


2
/^([A-Za-z0-9+\/]{4})*([A-Za-z0-9+\/]{4}|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{2}==)$/

to wyrażenie regularne pomogło mi zidentyfikować base64 w mojej aplikacji w szynach, miałem tylko jeden problem, to znaczy, że rozpoznaje ciąg „errorDescripcion”, generuję błąd, aby go rozwiązać, po prostu zweryfikuj długość łańcucha.


Powyższe wyrażenie /^.....$/.match(my_string) podaje błąd formatowania, mówiąc „
Niedopasowane

I z „przedwczesnym końcem klasy char: / ^ ((błędy składniowe [A-Za-z0-9 + /”.
james2611nov

Nevermind naprawił to, dodając \ przed każdą postacią /.
james2611nov

errorDescriptionJest to prawidłowy ciąg base64, dekoduje go do binarnego sekwencji bajtów (w hex) 7a ba e8 ac 37 ac 72 b8 a9 b6 2a 27.
Luis Colorado,

Działa idealnie dla mnie, aby sprawdzić ciąg zakodowany w base64.
Deepak Lakhara

1

Działa to w Pythonie:

import base64

def IsBase64(str):
    try:
        base64.b64decode(str)
        return True
    except Exception as e:
        return False

if IsBase64("ABC"):
    print("ABC is Base64-encoded and its result after decoding is: " + str(base64.b64decode("ABC")).replace("b'", "").replace("'", ""))
else:
    print("ABC is NOT Base64-encoded.")

if IsBase64("QUJD"):
    print("QUJD is Base64-encoded and its result after decoding is: " + str(base64.b64decode("QUJD")).replace("b'", "").replace("'", ""))
else:
    print("QUJD is NOT Base64-encoded.")

Podsumowanie: IsBase64("string here") zwraca true, jeśli string herejest zakodowany w standardzie Base64, i zwraca false, jeśli string hereNIE został zakodowany w standardzie Base64.


1

C # To działa świetnie:

static readonly Regex _base64RegexPattern = new Regex(BASE64_REGEX_STRING, RegexOptions.Compiled);

private const String BASE64_REGEX_STRING = @"^[a-zA-Z0-9\+/]*={0,3}$";

private static bool IsBase64(this String base64String)
{
    var rs = (!string.IsNullOrEmpty(base64String) && !string.IsNullOrWhiteSpace(base64String) && base64String.Length != 0 && base64String.Length % 4 == 0 && !base64String.Contains(" ") && !base64String.Contains("\t") && !base64String.Contains("\r") && !base64String.Contains("\n")) && (base64String.Length % 4 == 0 && _base64RegexPattern.Match(base64String, 0).Success);
    return rs;
}

1
Console.WriteLine("test".IsBase64()); // true
Langdon,

2
Polecenie zmiany języka programowania w celu rozwiązania problemu nie jest poprawną odpowiedzią.
Luis Colorado,

0

Nie ma sposobu na odróżnienie łańcucha i kodowania base64, z wyjątkiem tego, że łańcuch w twoim systemie ma określone ograniczenia lub identyfikację.


0

Ten fragment kodu może być przydatny, gdy znasz długość oryginalnej treści (np. Suma kontrolna). Sprawdza, czy zakodowana forma ma prawidłową długość.

public static boolean isValidBase64( final int initialLength, final String string ) {
  final int padding ;
  final String regexEnd ;
  switch( ( initialLength ) % 3 ) {
    case 1 :
      padding = 2 ;
      regexEnd = "==" ;
      break ;
    case 2 :
      padding = 1 ;
      regexEnd = "=" ;
      break ;
    default :
      padding = 0 ;
      regexEnd = "" ;
  }
  final int encodedLength = ( ( ( initialLength / 3 ) + ( padding > 0 ? 1 : 0 ) ) * 4 ) ;
  final String regex = "[a-zA-Z0-9/\\+]{" + ( encodedLength - padding ) + "}" + regexEnd ;
  return Pattern.compile( regex ).matcher( string ).matches() ;
}

0

Jeśli RegEx nie działa i znasz styl formatu oryginalnego łańcucha, możesz odwrócić logikę, wyrażając wyrażenie regularne dla tego formatu.

Na przykład pracuję z plikami XML zakodowanymi w standardzie base64 i po prostu sprawdzam, czy plik zawiera prawidłowe znaczniki xml. Jeśli nie, mogę założyć, że jest dekodowany w standardzie base64. Nie jest to zbyt dynamiczne, ale działa dobrze w mojej małej aplikacji.


0

Działa to w Pythonie:

def is_base64(string):
    if len(string) % 4 == 0 and re.test('^[A-Za-z0-9+\/=]+\Z', string):
        return(True)
    else:
        return(False)

0

Wypróbuj to, używając wcześniej wspomnianego wyrażenia regularnego:

String regex = "^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$";
if("TXkgdGVzdCBzdHJpbmc/".matches(regex)){
    System.out.println("it's a Base64");
}

... Możemy również dokonać prostej weryfikacji, np. Jeśli ma spacje, to nie może być Base64:

String myString = "Hello World";
 if(myString.contains(" ")){
   System.out.println("Not B64");
 }else{
    System.out.println("Could be B64 encoded, since it has no spaces");
 }

Ok, czy mógłbyś więc podać rozwiązanie?
Marco

0

jeśli podczas dekodowania otrzymamy ciąg ze znakami ASCII, to nie zostanie on zakodowany

(RoR) rozwiązanie rubinowe:

def encoded?(str)
  Base64.decode64(str.downcase).scan(/[^[:ascii:]]/).count.zero?
end

def decoded?(str)
  Base64.decode64(str.downcase).scan(/[^[:ascii:]]/).count > 0
end

0

Próbuję tego użyć, tak, to działa

^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$

ale dodałem pod warunkiem, że przynajmniej koniec znaku to =

string.lastIndexOf("=") >= 0

Po co sprawdzać =: Base64jakiej specyfikacji używasz? Co to end of the characterznaczy i jak to nieujemne to lastIndexOf()sprawdza?
Greybeard
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.