Cómo verificar si una cadena tiene codificación Base64 o no

194

Quiero decodificar una cadena codificada en Base64 y luego almacenarla en mi base de datos. Si la entrada no está codificada en Base64, necesito lanzar un error.

¿Cómo puedo verificar si una cadena está codificada en Base64?

loganathan
fuente
¿Por qué? ¿Cómo puede surgir la situación?
Marqués de Lorne
2
sin especificar a qué lenguaje de programación (y / o) sistema operativo se dirige, esta es una pregunta muy abierta
bcarroll el
55
Todo lo que puede determinar es que la cadena contiene solo caracteres que son válidos para una cadena codificada en base64. Es posible que no sea posible determinar que la cadena es la versión codificada en base64 de algunos datos. por ejemplo, test1234es una cadena codificada en base64 válida, y cuando la decodifique obtendrá algunos bytes. No existe una forma independiente de aplicación de concluir que test1234no sea una cadena codificada en base64.
Kinjal Dixit

Respuestas:

249

Puede usar la siguiente expresión regular para verificar si una cadena está codificada en base64 o no:

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

En la codificación base64, el conjunto de caracteres es [A-Z, a-z, 0-9, and + /]. Si la longitud restante es inferior a 4, la cadena se rellena con '='caracteres.

^([A-Za-z0-9+/]{4})* significa que la cadena comienza con 0 o más grupos base64.

([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$significa que los extremos de cadena en una de tres formas: [A-Za-z0-9+/]{4}, [A-Za-z0-9+/]{3}=o [A-Za-z0-9+/]{2}==.

xuanyuanzhiyuan
fuente
10
Solo quería verificar, así que por favor ayude con mi pregunta: ¿Cuál es la garantía de que esta expresión regular siempre se refiere solo a una cadena base64? Si hay una cadena que no tiene espacio y es múltiplo de 4 caracteres, ¿se considerará esa cadena como cadena base64?
DShah
3
Entonces es una cadena base64 válida que se puede decodificar. Puede agregar una restricción de longitud mínima; por ejemplo, en lugar de cero o más repeticiones de grupos de cuatro, requieren (por ejemplo) cuatro o más. También depende de tu problema; (? hawaiano) si sus usuarios a menudo entran en una sola palabra en un lenguaje con palabras largas y ASCII puro que es más propenso a errores que si de entrada no base 64 típicamente contiene espacios, puntuacion, etc.
tripleee
62
Esto solo indica que una entrada podría haber sido un valor codificado en b64, pero no indica si la entrada es realmente un valor codificado en b64. En otras palabras, abcdcoincidirá, pero no representa necesariamente el valor codificado de una abcdentrada simple
sino Tzury Bar Yochay,
3
Su expresión regular es incorrecta, ya que no coincide con la cadena vacía, con la codificación base64 de datos binarios de longitud cero de acuerdo con RFC 4648.
rojizo
55
@Adomas, "pass" es una cadena base64 perfectamente válida, que decodifica en la secuencia de bytes 0xa5, 0xaby 0x2c. ¿Por qué descartarlo a priori si no tiene más contexto para decidir?
Luis Colorado
50

Si está utilizando Java, en realidad puede usar la biblioteca de códec commons

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

String stringToBeChecked = "...";
boolean isBase64 = Base64.isArrayByteBase64(stringToBeChecked.getBytes());
zihaoyu
fuente
17
de la documentación: en isArrayByteBase64(byte[] arrayOctet)desuso. 1.5 Uso isBase64(byte[]), se eliminará en 2.0.
Avinash R
77
También puede usar Base64.isBase64 (String base64) en lugar de convertirlo usted mismo en una matriz de bytes.
Sasa
55
Lamentablemente, según la documentación: commons.apache.org/proper/commons-codec/apidocs/org/apache/… : "Prueba una cadena dada para ver si contiene solo caracteres válidos dentro del alfabeto Base64. Actualmente el método trata los espacios en blanco como válido." Esto significa que este método tiene algunos falsos positivos como "espacios en blanco" o números ("0", "1").
Christian Vielma
para la cadena Base64.isBase64 (contenido)
ema
44
Esta respuesta es incorrecta porque dada stringToBeChecked="some plain text"entonces se establece boolean isBase64=truea pesar de que no es un valor codificado en Base64. Lea la fuente de commons-codec-1.4 Base64.isArrayByteBase64(), solo verifica que cada carácter de la cadena sea válido para ser considerado para la codificación Base64 y permita espacios en blanco.
Brad
49

Bien tu puedes:

  • Compruebe que la longitud es un múltiplo de 4 caracteres.
  • Verifique que cada carácter esté en el conjunto AZ, az, 0-9, +, / excepto el relleno al final que es 0, 1 o 2 caracteres '='

Si usted está esperando que va a ser base 64, entonces probablemente puede utilizar cualquier biblioteca está disponible en su plataforma para tratar de decodificar a una matriz de bytes, lanzar una excepción si no es válido para la base 64. Eso depende de la plataforma, por supuesto.

Jon Skeet
fuente
El análisis difiere de la validación al menos por el hecho de que requiere memoria para la matriz de bytes decodificada. Por lo tanto, este no es el enfoque más efectivo en algunos casos.
Victor Yarema el
1
@VictorYarema: sugerí un enfoque de solo validación (puntos de viñeta) y también un enfoque de análisis (después de los puntos de viñeta).
Jon Skeet
16

A partir de Java 8, simplemente puede usar java.util.Base64 para intentar decodificar la cadena:

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

try {
    decoder.decode(someString);
} catch(IllegalArgumentException iae) {
    // That string wasn't valid.
}
Philippe
fuente
3
Sí, es una opción, pero no olvide que la captura es una operación bastante costosa en Java
análisis
2
Ese ya no es el caso. El manejo de excepciones está funcionando bastante bien. Es mejor no olvidar que Java Regex es bastante lento. Quiero decir: ¡REALMENTE LENTO! En realidad, es más rápido decodificar un Base64 y verificar que (no) funcione en lugar de hacer coincidir la Cadena con la expresión regular anterior. Hice una prueba aproximada y la coincidencia de Java Regex es aproximadamente seis veces más lenta (!!) que detectar una eventual excepción en la decodificación.
Sven Döring
Con más pruebas, en realidad es once veces más lento. Es hora de una mejor implementación de Regex en Java. Incluso una verificación Regex con el motor JavaScript de Nashorn en Java es mucho más rápido. Increíble. Además, JavaScript Regex (con Nashorn) es mucho más poderoso.
Sven Döring
3
Con Java 11 (en lugar de Java 8) la comprobación de expresiones regulares es incluso 22 veces más lenta. 🤦 (Porque la decodificación Base64 se hizo más rápida.)
Sven Döring
15

Prueba así para 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"; 
}

Use esto para 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
fuente
1
¿Que idioma es este? La pregunta se hizo sin hacer referencia a un idioma
Ozkan
Esto no funcionará. leer los documentos Returns FALSE if input contains character from outside the base64 alphabet. base64_decode
Aley
1
¿Cómo? si la entrada contiene caracteres externos, entonces no es base64, ¿verdad?
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
fuente
5

Compruebe SI longitud de la cadena es un múltiplo de 4. Aftwerwards utilizar esta expresión regular para asegurarse de que todos los caracteres de la cadena son base64 caracteres.

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

Si la biblioteca que usa agrega una nueva línea como una forma de observar los 76 caracteres máximos por regla de línea, reemplácelos con cadenas vacías.

Yaw Boakye
fuente
El enlace mencionado muestra 404. Por favor verifique y actualice.
Ankur
Lo siento @AnkurKumar, pero eso es lo que sucede cuando las personas tienen URLs poco interesantes: cambian todo el tiempo. No tengo idea de a dónde se trasladó. Espero que encuentres otros recursos útiles a través de Google
Yaw Boakye
Siempre puede obtener páginas antiguas de web.archive.org: aquí está la url original. web.archive.org/web/20120919035911/http://… o publiqué
Mladen Mihajlovic el
4

Hay muchas variantes de Base64 , por lo tanto, considere determinar si su cadena se parece a la variante que espera manejar. Como tal, es posible que tenga que ajustar la expresión regular a continuación con respecto a los caracteres de índice y de relleno (es decir +, /, =).

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

Uso:

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

Prueba esto:

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

Es imposible verificar si una cadena está codificada en base64 o no. Solo es posible validar si esa cadena es de un formato de cadena codificada en base64, lo que significa que podría ser una cadena producida por la codificación base64 (para verificar que la cadena podría validarse contra una expresión regular o se podría usar una biblioteca, muchas otras respuestas a esta pregunta proporcionan buenas formas de verificar esto, por lo que no entraré en detalles).

Por ejemplo, la cadena flowes una cadena codificada en base64 válida. Pero es imposible saber si es solo una cadena simple, una palabra en inglés flowo si es una cadena codificada en base 64~Z0

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

esta expresión regular me ayudó a identificar la base64 en mi aplicación en rails, solo tuve un problema, es que reconoce la cadena "errorDescripcion", genero un error, para resolverlo solo validar la longitud de una cadena.

Onironauta
fuente
La expresión regular anterior /^.....$/.match(my_string) da un error de formato al decir 'Cierre no
coincidente
Y con 'final prematuro de la clase char: / ^ (([A-Za-z0-9 + /' errores de sintaxis.
james2611nov
No importa lo solucionó agregando \ delante de cada / carácter.
james2611nov
errorDescriptiones una cadena base64 válido, se decodifica en la secuencia binaria de bytes (en hexadecimal): 7a ba e8 ac 37 ac 72 b8 a9 b6 2a 27.
Luis Colorado
Funcionó perfecto para mí para verificar la cadena codificada en base64.
Deepak Lakhara
1

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

Resumen: IsBase64("string here") devuelve verdadero si string hereestá codificado en Base64, y devuelve falso si string hereNO fue codificado en Base64.

dio
fuente
1

C # Esto está funcionando muy 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
fuente
1
Console.WriteLine("test".IsBase64()); // true
Langdon
2
Recomendar cambiar el lenguaje de programación para resolver un problema en general no es una respuesta válida.
Luis Colorado
0

No hay forma de codificar una cadena distinta y una base64, excepto que la cadena en su sistema tiene alguna limitación o identificación específica.

pinxue
fuente
0

Este fragmento puede ser útil cuando conoce la longitud del contenido original (por ejemplo, una suma de verificación). Comprueba que la forma codificada tiene la longitud correcta.

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
fuente
0

Si el RegEx no funciona y conoce el estilo de formato de la cadena original, puede revertir la lógica, regexing para este formato.

Por ejemplo, trabajo con archivos xml codificados en base64 y solo verifico si el archivo contiene un marcado xml válido. Si no es así, puedo suponer que es decodificado en base64. Esto no es muy dinámico, pero funciona bien para mi pequeña aplicación.

Jankapunkt
fuente
0

Esto funciona 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
fuente
0

Pruebe esto usando una expresión regular mencionada anteriormente:

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

... También podemos hacer una validación simple como, si tiene espacios, no puede ser 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
fuente
Ok, ¿podrías dar una solución entonces?
Marco
0

si al decodificar obtenemos una cadena con caracteres ASCII, entonces la cadena no fue codificada

(RoR) solución de rubí:

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

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

Intento usar esto, sí, este está funcionando

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

pero agregué la condición para verificar que al menos el final del carácter sea =

string.lastIndexOf("=") >= 0
Ashadi Sedana Pratama
fuente
¿Por qué buscar =? ¿Qué especificación Base64utiliza? ¿Qué end of the charactersignifica y cómo no negativo lastIndexOf()verifica eso?
barba gris