Как проверить, закодирована ли строка в Base64 или нет

195

Я хочу декодировать строку в кодировке Base64, а затем сохранить ее в своей базе данных. Если вход не в кодировке Base64, мне нужно выдать ошибку.

Как я могу проверить, закодирована ли строка в Base64?

Loganathan
источник
Зачем? Как может возникнуть ситуация?
Маркиз Лорн
2
без указания какого языка программирования (и / или) операционной системы вы нацеливаете, это очень открытый вопрос
bcarroll
5
Все, что вы можете определить, это то, что строка содержит только символы, допустимые для строки в кодировке base64. Может оказаться невозможным определить, что строка является версией некоторых данных в кодировке base64. например, test1234допустимая строка в кодировке base64, и когда вы ее декодируете, вы получите несколько байтов. Не существует независимого от приложения способа сделать вывод, что test1234это не кодированная строка base64.
Кинджал Диксит

Ответы:

249

Вы можете использовать следующее регулярное выражение, чтобы проверить, закодирована ли строка в base64:

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

В кодировке base64 набор символов [A-Z, a-z, 0-9, and + /]. Если длина покоя меньше 4, строка дополняется '='символами.

^([A-Za-z0-9+/]{4})* означает, что строка начинается с 0 или более групп base64.

([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$означает , что строка заканчивается в одной из трех форм: [A-Za-z0-9+/]{4}, [A-Za-z0-9+/]{3}=или [A-Za-z0-9+/]{2}==.

xuanyuanzhiyuan
источник
10
Просто хотел проверить, поэтому, пожалуйста, помогите с моим вопросом: Какая гарантия, что это регулярное выражение всегда будет относиться только к строке base64 ?? Если есть какая-либо строка без пробела и она кратна 4 символам, то эта строка будет считаться строкой base64 ????
DShah
3
Тогда это допустимая строка base64, которую можно декодировать. Вы можете добавить ограничение минимальной длины; например, вместо нуля или более повторений групп из четырех, требуется (скажем) четыре или более. Это также зависит от вашей проблемы; если ваши пользователи часто вводят одно слово в языке с длинными словами и чистым ASCII (гавайским?), это более подвержено ошибкам, чем если бы ввод не в base64 обычно содержал пробелы, знаки препинания и т. д.
tripleee
62
Это только говорят , что вход может быть B64 закодированное значение, но не сказать , является ли входной является фактически B64 закодированное значение. Другими словами, abcdбудет совпадать, но это не обязательно будет представлять закодированное значение, а не просто простой abcdввод
Цуры Бар Йохай
3
Ваше регулярное выражение неверно, так как оно не совпадает с пустой строкой, с помощью base64-кодировки двоичных данных нулевой длины в соответствии с RFC 4648.
красноватый
5
@Adomas, "pass" это совершенно правильная строка base64, которая декодирует в последовательность байтов 0xa5, 0xabи 0x2c. Зачем отказываться от него априори , если у вас нет большего контекста, чтобы решить?
Луис Колорадо
52

Если вы используете Java, вы можете использовать библиотеку commons-codec

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

String stringToBeChecked = "...";
boolean isBase64 = Base64.isArrayByteBase64(stringToBeChecked.getBytes());
zihaoyu
источник
18
из документации: isArrayByteBase64(byte[] arrayOctet)устарела. 1.5 Использование isBase64(byte[]), будет удалено в 2.0.
Авинаш Р
7
Вы также можете использовать Base64.isBase64 (String base64) вместо преобразования его в байтовый массив самостоятельно.
Саша
5
К сожалению, на основе документации: commons.apache.org/proper/commons-codec/apidocs/org/apache/… : "Проверяет данную строку, чтобы увидеть, содержит ли она только допустимые символы в алфавите Base64. В настоящее время метод обрабатывает пробельные символы как действует «. Это означает, что у этих методов есть некоторые ложные срабатывания, такие как «пробел» или числа («0», «1»).
Кристиан Вьельма
для строки Base64.isBase64 (содержимое)
ema
4
Этот ответ неверен, потому что, если stringToBeChecked="some plain text"он задан, он устанавливается, boolean isBase64=trueхотя это не кодированное значение Base64. Прочитайте исходный код для commons-codec-1.4, Base64.isArrayByteBase64()он только проверяет, что каждый символ в строке является допустимым для учета в кодировке Base64 и допускает пробелы.
Брэд
49

Ну, вы можете:

  • Убедитесь, что длина кратна 4 символам
  • Убедитесь, что каждый символ находится в наборе AZ, az, 0-9, +, /, за исключением заполнения в конце, которое состоит из 0, 1 или 2 символов '='

Если вы ожидаете, что это будет base64, то вы, вероятно, можете просто использовать любую библиотеку, доступную на вашей платформе, чтобы попытаться декодировать ее в байтовый массив, выдав исключение, если оно не является действительным base 64. Это зависит от вашей платформы, конечно.

Джон Скит
источник
Разбор отличается от проверки, по крайней мере, тем, что он требует памяти для декодированного массива байтов. Так что это не самый эффективный подход в некоторых случаях.
Виктор Ярема
1
@VictorYarema: Я предложил как подход только для проверки (маркеры), так и метод парсинга (после маркеров).
Джон Скит
16

Начиная с Java 8, вы можете просто использовать java.util.Base64, чтобы попытаться декодировать строку:

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

try {
    decoder.decode(someString);
} catch(IllegalArgumentException iae) {
    // That string wasn't valid.
}
Philippe
источник
3
да, это вариант, но не забывайте, что catch является довольно дорогой операцией в Java
panser
2
Это больше не так. Обработка исключений выполняется довольно хорошо. Не стоит забывать, что Java Regex работает довольно медленно. Я имею в виду: действительно медленно! На самом деле быстрее декодировать Base64 и проверять, что он (не) работает, вместо сопоставления String с приведенным выше регулярным выражением. Я провел грубый тест, и сопоставление Java Regex примерно в шесть раз медленнее (!!), чем обнаружение возможного исключения при декодировании.
Свен Деринг
При большем количестве тестовых прогонов это на самом деле в 11 раз медленнее Настало время для лучшей реализации Regex в Java. Даже проверка Regex с движком Nashorn JavaScript в Java намного быстрее. Невероятно. Кроме того, JavaScript Regex (с Nashorn) намного мощнее.
Свен Деринг,
3
В Java 11 (вместо Java 8) проверка Regex выполняется даже в 22 раза медленнее. 🤦 (потому что декодирование Base64 стало быстрее.)
Свен Деринг,
15

Попробуйте вот так для 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"; 
}

Используйте это для 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
Какой это язык? Вопрос был задан без обращения к языку
Озкан
Это не будет работать. читать документы Returns FALSE if input contains character from outside the base64 alphabet. base64_decode
Алей
1
Как? если вход содержит внешний символ, то это не base64, верно?
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

Проверьте, ЕСЛИ длина строки кратна 4. Aftwerwards использует это регулярное выражение, чтобы убедиться, что все символы в строке являются символами base64.

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

Если используемая вами библиотека добавляет новую строку для наблюдения правила 76 максимальных символов на строку, замените их пустыми строками.

Йо Боакье
источник
Ссылка показывает 404. Пожалуйста, проверьте и обновите.
Анкур
Извините @AnkurKumar, но это то, что происходит, когда у людей есть не крутые URL-адреса: они постоянно меняются. Я понятия не имею, куда это перемещено. Я надеюсь, что вы найдете другие полезные ресурсы через Google
Yaw Boakye
Вы всегда можете получить старые страницы с web.archive.org - вот оригинальный URL. web.archive.org/web/20120919035911/http://… или я разместил текст здесь: gist.github.com/mika76/d09e2b65159e435e7a4cc5b0299c3e84
Младен Михайлович
4

Есть много вариантов Base64 , поэтому рассмотрим только определения , если ваша строка похожа на varient вы ожидаете обрабатывать. Таким образом , вы , возможно , потребуется настроить регулярное выражение ниже по отношению к индексу и заполняющих символов (т.е. +, /, =).

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

Использование:

raise 'the string does not resemble Base64' unless my_string.resembles_base64?
user664833
источник
3

Попробуй это:

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
источник
3

Невозможно проверить, закодирована ли строка в base64 или нет. Проверка возможна только в том случае, если эта строка имеет формат строки, закодированный в base64, что означает, что она может быть строкой, созданной кодировкой base64 (чтобы убедиться, что строка может быть проверена с помощью регулярного выражения или может использоваться библиотека, многие другие ответы на этот вопрос предоставляют хорошие способы проверить это, поэтому я не буду вдаваться в подробности).

Например, строка flowявляется допустимой строкой в ​​кодировке base64. Но невозможно узнать, является ли это просто простая строка, английское слово flow, или это строка, закодированная в формате 64~Z0

Адомас
источник
2
/^([A-Za-z0-9+\/]{4})*([A-Za-z0-9+\/]{4}|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{2}==)$/

это регулярное выражение помогло мне идентифицировать base64 в моем приложении в rails, у меня была только одна проблема, это то, что оно распознает строку «errorDescripcion», я генерирую ошибку, для ее решения просто проверяю длину строки.

Onironauta
источник
Приведенное выше регулярное выражение /^.....$/.match(my_string) выдает ошибку форматирования, говоря «Непревзойденное закрытие)»
james2611nov
И с 'преждевременным окончанием char-класса: / ^ (([A-Za-z0-9 + /' синтаксические ошибки.
james2611nov
Nevermind исправил это, добавив \ перед каждым / символом.
james2611nov
errorDescriptionявляется допустимой base64 строки, он декодирует в двоичную последовательность байт (в шестнадцатеричном виде ): 7a ba e8 ac 37 ac 72 b8 a9 b6 2a 27.
Луис Колорадо
Он отлично работал для меня, чтобы проверить base64 кодированную строку.
Дипак Лакхара
1

Это работает в 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.")

Сводка: IsBase64("string here") возвращает true, если string hereкодируется Base64, и возвращает false, если string hereкод не был Base64.

дал
источник
1

C # Это отлично работает:

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
Лэнгдон
2
Рекомендовать переключать язык программирования для решения проблемы, как правило, не является правильным ответом.
Луис Колорадо
0

Нет способа различить строку и кодировку base64, за исключением того, что строка в вашей системе имеет определенные ограничения или идентификацию.

pinxue
источник
0

Этот фрагмент может быть полезен, когда вы знаете длину исходного содержимого (например, контрольной суммы). Он проверяет, что закодированная форма имеет правильную длину.

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

Если RegEx не работает, и вы знаете стиль формата исходной строки, вы можете изменить логику, выполнив регулярное выражение для этого формата.

Например, я работаю с XML-файлами в кодировке Base64 и просто проверяю, содержит ли файл допустимую разметку XML. Если это не так, я могу предположить, что это base64 декодируется. Это не очень динамично, но отлично работает для моего небольшого приложения.

Jankapunkt
источник
0

Это работает в 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
источник
0

Попробуйте это с помощью ранее упомянутого регулярного выражения:

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

... Мы также можем сделать простую проверку, например, если у нее есть пробелы, она не может быть 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
источник
Хорошо, не могли бы вы дать решение тогда?
Марко
0

если при декодировании мы получаем строку с символами ASCII, то строка не была закодирована

(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
Игорь Хлебников
источник
0

Я пытаюсь использовать это, да, это работает

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

но я добавил условие, чтобы проверить хотя бы конец символа =

string.lastIndexOf("=") >= 0
Ашади Седана Пратама
источник
Зачем проверять =: какие спецификации Base64вы используете? Что это end of the characterзначит, и как это можно lastIndexOf()проверить с помощью негатива ?
седобородый