Comment vérifier si une chaîne est encodée en Base64 ou non

195

Je souhaite décoder une chaîne encodée en Base64, puis la stocker dans ma base de données. Si l'entrée n'est pas encodée en Base64, je dois lancer une erreur.

Comment puis-je vérifier si une chaîne est encodée en Base64?

Loganathan
la source
Pourquoi? Comment la situation peut-elle survenir?
Marquis de Lorne
2
sans spécifier le langage de programmation (et / ou) le système d'exploitation que vous ciblez, c'est une question très ouverte
bcarroll
5
Tout ce que vous pouvez déterminer, c'est que la chaîne contient uniquement des caractères valides pour une chaîne encodée en base64. Il peut être impossible de déterminer que la chaîne est la version encodée en base64 de certaines données. par exemple test1234est une chaîne codée en base64 valide, et lorsque vous la décodez, vous obtiendrez des octets. Il n'existe aucun moyen indépendant de l'application de conclure qu'il test1234ne s'agit pas d'une chaîne codée en base64.
Kinjal Dixit

Réponses:

249

Vous pouvez utiliser l'expression régulière suivante pour vérifier si une chaîne est encodée en base64 ou non:

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

Dans le codage base64, le jeu de caractères est [A-Z, a-z, 0-9, and + /]. Si la longueur restante est inférieure à 4, la chaîne est complétée avec des '='caractères.

^([A-Za-z0-9+/]{4})* signifie que la chaîne commence par 0 ou plusieurs groupes base64.

([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$signifie que les extrémités de chaîne dans l' une des trois formes suivantes : [A-Za-z0-9+/]{4}, [A-Za-z0-9+/]{3}=ou [A-Za-z0-9+/]{2}==.

xuanyuanzhiyuan
la source
10
Je voulais juste vérifier, alors aidez-moi avec ma question: Quelle est la garantie que cette expression régulière ne se réfère toujours qu'à une chaîne de base64? S'il y a une chaîne sans espace et qu'elle est multiple de 4 caractères, cette chaîne sera-t-elle considérée comme une chaîne base64 ????
DShah
3
Ensuite, c'est une chaîne base64 valide qui peut être décodée. Vous pouvez ajouter une contrainte de longueur minimale; par exemple, au lieu de zéro ou plus de répétitions de groupes de quatre, il en faut (disons) quatre ou plus. Cela dépend aussi de votre problème; si vos utilisateurs entrent souvent un seul mot dans une langue avec des mots longs et de l'ASCII pur (hawaïen?), il est plus sujet aux erreurs que si une entrée non base64 contient généralement des espaces, de la ponctuation, etc.
tripleee
62
Cela indique seulement qu'une entrée aurait pu être une valeur codée en b64, mais cela ne dit pas si l'entrée est en fait une valeur codée en b64. En d'autres termes, abcdcorrespondra, mais ce n'est pas nécessairement la valeur codée d' une abcdentrée simple
Tzury Bar Yochay
3
Votre expression régulière est incorrecte, car elle ne correspond pas à la chaîne vide, avec l'encodage en base64 des données binaires de longueur nulle selon RFC 4648.
rougeâtre
5
@Adomas, "pass" est une chaîne de base64 parfaitement valide, qui se décode dans la séquence d'octets 0xa5, 0xabet 0x2c. Pourquoi l'éliminer a priori , si vous n'avez plus de contexte pour décider?
Luis Colorado
52

Si vous utilisez Java, vous pouvez en fait utiliser la bibliothèque commons-codec

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

String stringToBeChecked = "...";
boolean isBase64 = Base64.isArrayByteBase64(stringToBeChecked.getBytes());
zihaoyu
la source
18
à partir de la documentation: isArrayByteBase64(byte[] arrayOctet)obsolète. 1.5 Utilisation isBase64(byte[]), sera supprimée dans 2.0.
Avinash R
7
Vous pouvez également utiliser Base64.isBase64 (String base64) au lieu de le convertir vous-même en tableau d'octets.
Sasa
5
Malheureusement, sur la base de la documentation: commons.apache.org/proper/commons-codec/apidocs/org/apache/… : "Teste une chaîne donnée pour voir si elle ne contient que des caractères valides dans l'alphabet Base64. Actuellement, la méthode traite les espaces comme valide." Cela signifie que cette méthode a des faux positifs tels que "les espaces" ou les nombres ("0", "1").
Christian Vielma
pour la chaîne Base64.isBase64 (content)
ema
4
Cette réponse est fausse car donnée stringToBeChecked="some plain text"alors elle est définie boolean isBase64=truemême si ce n'est pas une valeur encodée en Base64. Lisez le source pour commons-codec-1.4, Base64.isArrayByteBase64()il vérifie uniquement que chaque caractère de la chaîne est valide pour être pris en compte pour l'encodage Base64 et autorise les espaces blancs.
Brad
49

Bien, vous pouvez:

  • Vérifiez que la longueur est un multiple de 4 caractères
  • Vérifiez que chaque caractère est dans l'ensemble AZ, az, 0-9, +, / sauf pour le remplissage à la fin qui est 0, 1 ou 2 '=' caractères

Si vous attendez que ce sera être base64, vous pouvez probablement utiliser la bibliothèque qui est disponible sur votre plate - forme pour essayer de le décoder à un tableau d'octets, lancer une exception si ce n'est pas la base valide 64. Cela dépend de votre plate - forme, bien sûr.

Jon Skeet
la source
L'analyse diffère de la validation au moins par le fait qu'elle nécessite de la mémoire pour le tableau d'octets décodés. Ce n'est donc pas l'approche la plus efficace dans certains cas.
Victor Yarema
1
@VictorYarema: J'ai suggéré à la fois une approche de validation uniquement (puces) et une approche d'analyse (après les puces).
Jon Skeet
16

À partir de Java 8, vous pouvez simplement utiliser java.util.Base64 pour essayer de décoder la chaîne:

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

try {
    decoder.decode(someString);
} catch(IllegalArgumentException iae) {
    // That string wasn't valid.
}
Philippe
la source
3
oui, c'est une option, mais n'oubliez pas que la capture est une opération assez coûteuse à Java
panser
2
Ce n'est plus le cas. La gestion des exceptions fonctionne plutôt bien. Vous feriez mieux de ne pas oublier que Java Regex est assez lent. Je veux dire: VRAIMENT LENT! Il est en fait plus rapide de décoder un Base64 et de vérifier qu'il fonctionne (ne) pas au lieu de faire correspondre la chaîne avec le Regex ci-dessus. J'ai fait un test approximatif et la correspondance Java Regex est environ six fois plus lente (!!) que la détection d'une éventuelle exception sur le décodage.
Sven Döring le
Avec plus de tests, il est en fait onze fois plus lent. Il est temps pour une meilleure implémentation Regex en Java. Même une vérification Regex avec le moteur JavaScript Nashorn en Java est tellement plus rapide. Incroyable. De plus, JavaScript Regex (avec Nashorn) est beaucoup plus puissant.
Sven Döring le
3
Avec Java 11 (au lieu de Java 8), le contrôle Regex est même 22 fois plus lent. 🤦 (Parce que le décodage Base64 est devenu plus rapide.)
Sven Döring
15

Essayez comme ça pour 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"; 
}

Utilisez ceci pour 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;
 }
}
Suneel Kumar
la source
1
Quelle langue est-ce? La question a été posée sans faire référence à une langue
Ozkan
cela ne fonctionnera pas. lire la documentation Returns FALSE if input contains character from outside the base64 alphabet. base64_decode
Aley
1
Comment? si l'entrée contient un caractère extérieur, alors ce n'est pas base64, non?
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');
}
Deepak Sisodiya
la source
5

Vérifiez SI la longueur de la chaîne est un multiple de 4. Aftwerwards utiliser cette regex pour vous assurer que tous les caractères de la chaîne sont base64 caractères.

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

Si la bibliothèque que vous utilisez ajoute une nouvelle ligne pour observer les 76 caractères maximum par règle de ligne, remplacez-les par des chaînes vides.

Yaw Boakye
la source
Le lien mentionné montre 404. Veuillez vérifier et mettre à jour.
Ankur
Désolé @AnkurKumar mais c'est ce qui arrive quand les gens ont des URL pas cool: elles changent tout le temps. Je n'ai aucune idée de la destination. J'espère que vous trouverez d'autres ressources utiles via Google
Yaw Boakye
Vous pouvez toujours obtenir d'anciennes pages sur web.archive.org - voici l'url d'origine. web.archive.org/web/20120919035911/http : //
Mladen Mihajlovic
4

Il existe de nombreuses variantes de Base64 , pensez donc simplement à déterminer si votre chaîne ressemble à la variante que vous prévoyez de gérer. A ce titre, vous devrez peut - être régler le regex ci - dessous par rapport aux caractères d'index et remplissage (c. -à +, /, =).

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

Usage:

raise 'the string does not resemble Base64' unless my_string.resembles_base64?
user664833
la source
3

Essaye ça:

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");
    }
}
user5499458
la source
3

Il est impossible de vérifier si une chaîne est encodée en base64 ou non. Il n'est possible de valider que si cette chaîne est d'un format de chaîne encodé en base64, ce qui signifierait qu'il pourrait s'agir d'une chaîne produite par encodage en base64 (pour vérifier que, la chaîne pourrait être validée par rapport à une expression rationnelle ou une bibliothèque pourrait être utilisée, beaucoup d'autres réponses à cette question fournissent de bons moyens de vérifier cela, donc je n'entrerai pas dans les détails).

Par exemple, string flowest une chaîne codée en base64 valide. Mais il est impossible de savoir s'il s'agit d'une simple chaîne, d'un mot anglais flowou d'une chaîne encodée en base 64~Z0

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

cette expression régulière m'a aidé à identifier la base64 dans mon application dans les rails, je n'ai eu qu'un seul problème, c'est qu'elle reconnaît la chaîne "errorDescripcion", je génère une erreur, pour la résoudre il suffit de valider la longueur d'une chaîne.

Onironauta
la source
L'expression régulière ci-dessus /^.....$/.match(my_string) donne une erreur de formatage en disant `` Fermeture sans correspondance) '
james2611nov
Et avec 'fin prématurée de char-class: / ^ (([A-Za-z0-9 + /' erreurs de syntaxe.
james2611nov
Nevermind l'a corrigé en ajoutant \ devant chaque caractère /.
james2611nov
errorDescriptionest une chaîne de base64 valide, il décode dans la séquence binaire d'octets (en hexadécimal): 7a ba e8 ac 37 ac 72 b8 a9 b6 2a 27.
Luis Colorado
C'est parfait pour moi de vérifier la chaîne encodée en base64.
Deepak Lakhara
1

Cela fonctionne en Python:

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.")

Résumé: IsBase64("string here") renvoie true si string hereest encodé en Base64, et il renvoie false si string heren'est PAS encodé en Base64.

donné
la source
1

C # Cela fonctionne très bien:

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;
}
Veni Souto
la source
1
Console.WriteLine("test".IsBase64()); // true
Langdon
2
Recommander de changer de langage de programmation pour résoudre un problème n'est en général pas une réponse valide.
Luis Colorado
0

Il n'y a aucun moyen de distinguer la chaîne et l'encodage en base64, sauf que la chaîne de votre système a une limitation ou une identification spécifique.

pinxue
la source
0

Cet extrait de code peut être utile lorsque vous connaissez la longueur du contenu original (par exemple une somme de contrôle). Il vérifie que le formulaire codé a la bonne longueur.

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() ;
}
Laurent Caillette
la source
0

Si le RegEx ne fonctionne pas et que vous connaissez le style de format de la chaîne d'origine, vous pouvez inverser la logique, par regexing pour ce format.

Par exemple, je travaille avec des fichiers xml encodés en base64 et je vérifie simplement si le fichier contient un balisage xml valide. Si ce n'est pas le cas, je peux supposer qu'il est décodé en base64. Ce n'est pas très dynamique mais fonctionne bien pour ma petite application.

Jankapunkt
la source
0

Cela fonctionne en Python:

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

Essayez ceci en utilisant une expression régulière mentionnée précédemment:

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");
}

... On peut aussi faire une simple validation comme, s'il y a des espaces ça ne peut pas être 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");
 }
Marco
la source
Ok, pourriez-vous s'il vous plaît donner une solution alors?
Marco
0

si lors du décodage nous obtenons une chaîne avec des caractères ASCII, alors la chaîne n'a pas été encodée

(RoR) solution de rubis:

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

def decoded?(str)
  Base64.decode64(str.downcase).scan(/[^[:ascii:]]/).count > 0
end
Игорь Хлебников
la source
0

J'essaye d'utiliser ça, oui celui-ci ça marche

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

mais j'ai ajouté à la condition de vérifier au moins la fin du caractère est =

string.lastIndexOf("=") >= 0
Ashadi Sedana Pratama
la source
Pourquoi vérifier =: quelle spécification Base64utilisez-vous? Qu'est-ce que cela end of the charactersignifie, et comment le non-négatif lastIndexOf()vérifie cela?
greybeard