Como verificar se uma string é codificada em Base64 ou não

194

Quero decodificar uma string codificada em Base64 e armazená-la no meu banco de dados. Se a entrada não estiver codificada em Base64, preciso gerar um erro.

Como posso verificar se uma string é codificada em Base64?

loganathan
fonte
Por quê? Como a situação pode surgir?
Marquês de Lorne
2
sem especificar qual linguagem de programação (e / ou) Sistema Operacional lhe são dirigidas, esta é uma pergunta muito aberta
bcarroll
5
Tudo o que você pode determinar é que a sequência contém apenas caracteres válidos para uma sequência codificada em base64. Talvez não seja possível determinar se a sequência é a versão codificada em base64 de alguns dados. por exemplo, test1234é uma string codificada em base64 válida e, quando você a decodificar, receberá alguns bytes. Não há maneira independente de concluir a aplicação que test1234não seja uma sequência codificada em base64.
Kinjal Dixit

Respostas:

249

Você pode usar a seguinte expressão regular para verificar se uma sequência está codificada em base64 ou não:

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

Na codificação base64, o conjunto de caracteres é [A-Z, a-z, 0-9, and + /]. Se o comprimento restante for menor que 4, a sequência será preenchida com '='caracteres.

^([A-Za-z0-9+/]{4})* significa que a sequência começa com 0 ou mais grupos base64.

([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$significa que as extremidades da corda em uma de três formas: [A-Za-z0-9+/]{4}, [A-Za-z0-9+/]{3}=ou [A-Za-z0-9+/]{2}==.

xuanyuanzhiyuan
fonte
10
Só queria verificar, por favor ajude com a minha pergunta: Qual é a garantia de que esse regex sempre se refere apenas à string base64? Se houver qualquer sequência que não tenha espaço e for múltiplo de 4 caracteres, essa sequência será considerada como sequência base64 ????
DShah 01/10/12
3
Então é uma string base64 válida que pode ser decodificada. Você pode adicionar uma restrição de comprimento mínimo; por exemplo, em vez de zero ou mais repetições de grupos de quatro, exija (digamos) quatro ou mais. Depende do seu problema também; (? havaiana) se os usuários muitas vezes entra uma única palavra em um idioma com palavras longas e ASCII puro que é mais propenso a erros do que se a entrada não-base64 normalmente contém espaços, pontuação, etc.
tripleee
62
Isso indica apenas que uma entrada poderia ter sido um valor codificado em b64, mas não informa se a entrada é realmente um valor codificado em b64. Em outras palavras, abcdirá corresponder, mas não é necessariamente representam o valor codificado de sim apenas uma planície abcdde entrada
Tzury Bar Yochay
3
Seu regexp é incorrecta, uma vez que não coincide com a cadeia vazia, com é a codificação base64 de dados binários de comprimento zero de acordo com RFC 4648.
avermelhada
5
@Adomas, "pass" é uma cadeia de base64 perfeitamente válido, que decodifica os dados para a sequência de bytes 0xa5, 0xabe 0x2c. Por que descartá-lo a priori , se você não tem mais contexto para decidir?
Luis Colorado
50

Se você estiver usando Java, poderá usar a biblioteca commons-codec

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

String stringToBeChecked = "...";
boolean isBase64 = Base64.isArrayByteBase64(stringToBeChecked.getBytes());
zihaoyu
fonte
17
da documentação: isArrayByteBase64(byte[] arrayOctet)Descontinuado. 1.5 Use isBase64(byte[]), será removido no 2.0.
Avinash R
7
Você também pode usar Base64.isBase64 (String base64) em vez de convertê-lo em matriz de bytes.
Sasa
5
Infelizmente, com base na documentação: commons.apache.org/proper/commons-codec/apidocs/org/apache/… : "Testa uma determinada String para ver se ela contém apenas caracteres válidos no alfabeto Base64. Atualmente, o método trata o espaço em branco como válido." Isso significa que esse método possui alguns falsos positivos, como "espaço em branco" ou números ("0", "1").
Christian Vielma
para string Base64.isBase64 (content)
ema
3
Essa resposta está errada porque, em stringToBeChecked="some plain text"seguida, é definida, boolean isBase64=truemesmo que não seja um valor codificado em Base64. Leia a fonte do commons-codec-1.4 Base64.isArrayByteBase64(), apenas verifica se cada caractere na sequência é válido para ser considerado na codificação Base64 e permite espaço em branco.
Brad
49

Bem, você pode:

  • Verifique se o comprimento é múltiplo de 4 caracteres
  • Verifique se todos os caracteres estão no conjunto AZ, az, 0-9, +, /, exceto pelo preenchimento no final, que é 0, 1 ou 2 '=' caracteres

Se você está esperando que vai ser base64, então provavelmente você pode simplesmente usar qualquer biblioteca está disponível em sua plataforma para tentar decodificá-lo para um array de bytes, lançando uma exceção se não é de base válido 64. Isso depende de sua plataforma, claro.

Jon Skeet
fonte
A análise difere da validação pelo menos pelo fato de exigir memória para uma matriz de bytes decodificada. Portanto, essa não é a abordagem mais eficaz em alguns casos.
Victor Yarema 22/09/19
1
@ VictorYarema: sugeri uma abordagem somente de validação (pontos de bala) e também uma abordagem de análise (após os pontos de bala).
Jon Skeet
16

No Java 8, você pode simplesmente usar java.util.Base64 para tentar decodificar a sequência:

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

try {
    decoder.decode(someString);
} catch(IllegalArgumentException iae) {
    // That string wasn't valid.
}
Philippe
fonte
3
sim, é uma opção, mas não se esqueça que captura é uma operação muito caro em Java
Panser
2
Esse não é mais o caso. O tratamento de exceções está executando muito bem. É melhor não esquecer que o Java Regex é bem lento. Quero dizer: REALMENTE LENTO! Na verdade, é mais rápido decodificar um Base64 e verificar se ele está (não) funcionando em vez de corresponder a String ao Regex acima. Fiz um teste aproximado e a correspondência do Java Regex é cerca de seis vezes mais lenta (!!) do que a captura de uma exceção eventual na decodificação.
Sven Döring
Com mais testes, é onze vezes mais lento. Está na hora de uma melhor implementação do Regex em Java. Mesmo uma verificação Regex com o mecanismo JavaScript Nashorn em Java é muito mais rápida. Inacreditável. Além disso, o JavaScript Regex (com Nashorn) é muito mais poderoso.
Sven Döring
3
No Java 11 (em vez do Java 8), a verificação Regex é 22 vezes mais lenta. 🤦 (Porque a decodificação Base64 ficou mais rápido.)
Sven Döring
15

Tente assim 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 isso 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
fonte
1
Que idioma é esse? A pergunta foi feita sem se referir a um idioma
Ozkan 27/11
isso não vai funcionar. leia os documentos Returns FALSE if input contains character from outside the base64 alphabet. base64_decode
Aley
1
Quão? se a entrada contém caracteres externos, não é base64, certo?
Suneel Kumar 01/02
6
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
fonte
5

Verifique se o comprimento da sequência é múltiplo de 4. Posteriormente, use esse regex para garantir que todos os caracteres na sequência sejam caracteres base64.

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

Se a biblioteca que você usa adicionar uma nova linha como uma maneira de observar a regra de 76 caracteres máximos por linha, substitua-as por cadeias vazias.

Yaw Boakye
fonte
O link mencionado mostra 404. Por favor, verifique e atualize.
Ankur
Desculpe @AnkurKumar, mas é isso que acontece quando as pessoas têm URLs não legais: elas mudam o tempo todo. Não faço ideia para onde foi movido. Espero que você encontre outros recursos úteis pelo Google
Yaw Boakye
Você sempre pode obter páginas antigas em web.archive.org - aqui está o URL original. web.archive.org/web/20120919035911/http://… ou eu postei o texto aqui: gist.github.com/mika76/d09e2b65159e435e7a4cc5b0299c3e84
Mladen Mihajlovic
4

Existem muitas variantes do Base64 , portanto, considere apenas determinar se sua sequência se assemelha à variação que você espera manipular. Como tal, pode ser necessário ajustar a regex abaixo com respeito aos caracteres de índice e enchimento (isto é +, /, =).

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?
user664833
fonte
3

Tente o seguinte:

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
fonte
3

É impossível verificar se uma sequência é codificada em base64 ou não. Só é possível validar se essa sequência possui um formato de sequência codificada em base64, o que significa que poderia ser uma sequência produzida pela codificação base64 (para verificar se a sequência pode ser validada em um regexp ou se uma biblioteca pode ser usada, muitos outras respostas a essa pergunta fornecem boas maneiras de verificar isso, para não entrar em detalhes).

Por exemplo, string flowé uma string codificada em base64 válida. Mas é impossível saber se é apenas uma sequência simples, uma palavra em inglês flowou se é uma sequência codificada de base 64~Z0

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

essa expressão regular me ajudou a identificar a base64 na minha aplicação em trilhos, só tive um problema, é que reconhece a string "errorDescripcion", gere um erro, para resolvê-la apenas valida o comprimento de uma string.

Onironauta
fonte
O regex acima /^.....$/.match(my_string) fornece um erro de formatação dizendo 'Fechamento sem correspondência)'
james2611nov
E com 'final prematuro da classe char: / ^ (([A-Za-z0-9 + /' erros de sintaxe.
james2611nov
Não importa, conserte-o adicionando \ na frente de cada caractere /.
James2611nov 17/05/19
errorDescriptioné uma cadeia de base64 válido, descodifica-o na sequência de binário de bytes (em hexadecimal): 7a ba e8 ac 37 ac 72 b8 a9 b6 2a 27.
Luis Colorado
Funcionou perfeito para eu verificar a string codificada em base64.
Deepak Lakhara,
1

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

Resumo: IsBase64("string here") retorna true se string herefor codificado em Base64 e retorna false se string herenão foi codificado em Base64.

deu
fonte
1

C # Isso está executando muito bem:

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
fonte
1
Console.WriteLine("test".IsBase64()); // true
Langdon
2
A recomendação de alternar a linguagem de programação para resolver um problema geralmente não é uma resposta válida.
Luis Colorado
0

Não há como distinguir a string e a base64, exceto que a string no seu sistema possui alguma limitação ou identificação específica.

pinxue
fonte
0

Este trecho pode ser útil quando você souber o tamanho do conteúdo original (por exemplo, uma soma de verificação). Ele verifica se o formulário codificado tem o comprimento correto.

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

Se o RegEx não funcionar e você souber o estilo de formato da sequência original, poderá inverter a lógica regexando para esse formato.

Por exemplo, eu trabalho com arquivos xml codificados em base64 e apenas verifico se o arquivo contém uma marcação xml válida. Se não, posso assumir, que é decodificado em base64. Isso não é muito dinâmico, mas funciona bem para meu pequeno aplicativo.

Jankapunkt
fonte
0

Isso funciona em 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
fonte
0

Tente isso usando um regex mencionado 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");
}

... Também podemos fazer uma validação simples como, se tiver espaços, não poderá 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
fonte
Ok, você poderia por favor dar uma solução então?
Marco
0

se ao decodificar obtemos uma sequência com caracteres ASCII, a sequência não foi codificada

Solução de rubi (RoR):

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

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

Eu tento usar isso, sim este está funcionando

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

mas eu adicionei a condição de verificar pelo menos o final do caractere é =

string.lastIndexOf("=") >= 0
Ashadi Sedana Pratama
fonte
Por que verificar =: Qual especificação Base64você está usando? O que end of the charactersignifica e como não negativo lastIndexOf()verifica isso?
greybeard 23/04