Як перевірити, чи є рядок закодованою Base64 чи ні


195

Я хочу розшифрувати кодований рядок Base64, а потім зберегти його у своїй базі даних. Якщо вхід не закодований Base64, мені потрібно нанести помилку.

Як я можу перевірити, чи рядок закодовано Base64?


Чому? Як може виникнути ситуація?
Маркіз Лорн

2
не вказуючи, на яку мову програмування (та / або) операційної системи ви орієнтовані, це дуже відкрите питання
bcarroll

5
Все, що ви можете визначити, - це те, що рядок містить лише символи, які дійсні для кодованої рядки base64. Визначити, що рядок є кодованою базовою версією деяких даних, можливо, неможливо. наприклад, test1234є дійсно кодованою рядком base64, і коли ви її розшифруєте, ви отримаєте кілька байтів. Не існує незалежного від додатку способу зробити висновок, що test1234це не кодований рядок base64.
Kinjal Dixit

Відповіді:


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}==.


10
Просто хотів перевірити, будь ласка, допоможіть з моїм запитанням: яка гарантія того, що цей регулярний вираз завжди посилається лише на рядок base64 ?? Якщо будь-який рядок, який не має місця, і він кратний 4 символам, то чи вважатиметься ця рядок базовою рядком ????
DShah

3
Тоді це допустимий рядок base64, який можна розшифрувати. Ви можете додати обмеження мінімальної довжини; наприклад, замість нуля або більше повторень груп із чотирьох, потрібно (скажімо) чотири чи більше. Це також залежить від вашої проблеми; якщо ваші користувачі часто вводять одне слово мовою з довгими словами та чистим ASCII (гавайською?), це більш схильне до помилок, ніж якщо введення non-base64 зазвичай містить пробіли, пунктуацію тощо
tripleee

62
Це тільки говорять , що вхід може бути B64 закодоване значення, але не сказати , є вхідний є фактично B64 закодоване значення. Іншими словами, це abcdбуде відповідати, але це не обов'язково представляти закодоване значення, а просто звичайний abcdвхід
Tzury Bar Yochay

3
Ваш регулярний вираз помилковий, оскільки він не відповідає порожній рядку, з базовим кодуванням бінарних даних нульової довжини відповідно до RFC 4648 є базове64
червонуватий

5
@Adomas, "pass" є цілком допустимою base64 рядки, яка декодує в електронних даних 0xa5, 0xabі 0x2c. Навіщо відкидати це апріорі , якщо у вас немає більше контексту для вирішення?
Луїс Колорадо

51

Якщо ви використовуєте Java, ви можете фактично використовувати бібліотеку commons-кодеків

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

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

18
з документації: isArrayByteBase64(byte[] arrayOctet)Застаріле. 1.5 Використання isBase64(byte[]), буде видалено в 2.0.
Avinash R

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, ви, ймовірно, можете просто використовувати будь-яку бібліотеку, наявну на вашій платформі, щоб спробувати розшифрувати її до байтового масиву, викинувши виняток, якщо це недійсна база 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.
}

3
так, це варіант, але не забувайте, що лов на Java
пансер

2
Це вже не так. Поводження з винятками працює досить добре. Краще не забувайте, що Java Regex досить повільна. Я маю на увазі: дійсно повільно! Насправді швидше розшифрувати Base64 і перевірити, чи він (не) працює замість того, щоб збігати String з вищевказаним Regex. Я зробив грубу перевірку, і відповідність Java Regex приблизно в шість разів повільніше (!!), ніж ловити можливий виняток на декодуванні.
Свен Дорінг

При більшій кількості випробувань це насправді в одинадцять разів повільніше. Настав час для кращої реалізації Regex на Java. Навіть перевірка Regex за допомогою JavaScript Nashorn JavaScript на Java набагато швидша. Неймовірно. Крім того, JavaScript Regex (з Нашорном) настільки потужніший.
Свен Дорінг

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

Перевірте IF довжиною струни кратно 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 існує багато , тому варто лише визначити, чи нагадує ваш рядок той варіант, який ви плануєте обробити. Таким чином , ви , можливо , буде потрібно налаштувати регулярний вираз нижче по відношенню до індексу і заповнюють символів (тобто +, /, =).

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?

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

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 у моєму застосуванні в рейках, у мене була лише одна проблема, це те, що він розпізнає рядок "errorDescripcion", я генерую помилку, щоб вирішити її просто перевірити довжину рядка.


Вищевказаний регекс /^.....$/.match(my_string) видає помилку форматування, кажучи "Незрівнянне закриття)"
james2611nov

І з 'передчасним закінченням чар-класу: / ^ (([синтаксичні помилки A-Za-z0-9 + /'.
james2611nov

Ніколи не виправляйте його, додаючи \ перед кожним символом.
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, за винятком того, що рядок у вашій системі має певні обмеження чи ідентифікацію.


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 розшифровано. Це не дуже динамічно, але чудово працює для мого невеликого застосування.


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)

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

Гаразд, чи можете ви тоді дати рішення?
Марко

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()перевіряє це?
сіра борода
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.