วิธีการตรวจสอบว่าสตริงนั้นมีการเข้ารหัส Base64 หรือไม่


195

ฉันต้องการถอดรหัสสตริงที่เข้ารหัส Base64 แล้วเก็บไว้ในฐานข้อมูลของฉัน หากอินพุตไม่ได้เข้ารหัส Base64 ฉันต้องโยนข้อผิดพลาด

ฉันจะตรวจสอบว่าสตริงนั้นเข้ารหัส Base64 ได้อย่างไร?


ทำไม? สถานการณ์จะเกิดขึ้นได้อย่างไร?
— มาร์ควิสแห่ง Lorne

2
โดยไม่ต้องระบุภาษาการเขียนโปรแกรม (และ / หรือ) ระบบปฏิบัติการที่คุณกำลังกำหนดเป้าหมายนี่เป็นคำถามที่เปิดกว้างมาก
— bcarroll

5
สิ่งที่คุณสามารถกำหนดได้คือสตริงนั้นมีอักขระที่ใช้ได้สำหรับสตริงที่เข้ารหัส base64 เท่านั้น อาจเป็นไปไม่ได้ที่จะตัดสินว่าสายอักขระนั้นเป็นรุ่นที่เข้ารหัสเบส 64 ของข้อมูลบางอย่าง ตัวอย่างเช่น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
เพียงต้องการตรวจสอบดังนั้นโปรดช่วยด้วยคำถามของฉัน: อะไรคือการรับประกันว่า regex นี้จะหมายถึงเฉพาะเบสสตริง 64? หากมีสตริงใด ๆ ที่ไม่มีช่องว่างและเป็นจำนวนมากกว่า 4 อักขระสตริงนั้นจะถูกพิจารณาเป็นสตริง base64 ????
— DShah

3
จากนั้นเป็นสตริงเบส 64 ที่ถูกต้องซึ่งสามารถถอดรหัสได้ คุณสามารถเพิ่มข้อจำกัดความยาวขั้นต่ำ ตัวอย่างเช่นแทนที่จะมีการทำซ้ำกลุ่มเป็นศูนย์อย่างน้อยสี่กลุ่มต้องการ (พูด) สี่ครั้งขึ้นไป ขึ้นอยู่กับปัญหาของคุณเช่นกัน หากผู้ใช้ของคุณมักป้อนคำเดียวในภาษาที่มีคำที่ยาวและ ASCII บริสุทธิ์ (ฮาวาย?) มันจะเกิดข้อผิดพลาดได้ง่ายกว่าโดยปกติแล้วการป้อนข้อมูลที่ไม่ใช่ base64 มักจะมีช่องว่างเครื่องหมายวรรคตอน ฯลฯ
— tripleee

62
สิ่งนี้บอกเพียงว่าอินพุตอาจเป็นค่าที่เข้ารหัส b64 แต่มันไม่ได้บอกว่าอินพุตนั้นเป็นค่าที่เข้ารหัส b64 หรือไม่ กล่าวอีกนัยหนึ่งabcdจะจับคู่ แต่ไม่จำเป็นต้องแสดงถึงค่าที่เข้ารหัสของi·เพียงabcdอินพุตธรรมดา
— Tzury Bar Yochay

3
regexp ของคุณไม่ถูกต้องเนื่องจากไม่ตรงกับสตริงว่างโดยมีการเข้ารหัส base64 ของข้อมูลไบนารีที่มีความยาวเป็นศูนย์ตาม RFC 4648
— reddish

5
@Adomas, "pass" เป็นสตริง base64 ที่ถูกต้องสมบูรณ์ที่ถอดรหัสเป็นลำดับของไบต์0xa5, และ0xab 0x2cทำไมต้องยกเลิกมันก่อนหากคุณไม่มีบริบทที่จะตัดสินใจมากกว่านี้
— ลูอิสโคโลราโด

52

หากคุณกำลังใช้ Java คุณสามารถใช้ไลบรารีคอมมอนส์ - codec ได้

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) แทนการแปลงเป็นอาร์เรย์ไบต์ด้วยตัวคุณเอง
— Sasa

5
น่าเศร้าอ้างอิงจากเอกสาร: commons.apache.org/proper/commons-codec/apidocs/org/apache/ ...... : "ทดสอบสตริงที่กำหนดเพื่อดูว่ามีอักขระที่ถูกต้องภายในตัวอักษร Base64 หรือไม่ปัจจุบันมีวิธีการใช้ช่องว่างเป็น ถูกต้อง." ซึ่งหมายความว่าวิธีการนี้มีผลบวกปลอมเช่น "ช่องว่าง" หรือตัวเลข ("0", "1")
— Christian Vielma

สตริง 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 ที่ถูกต้องขึ้นอยู่กับแพลตฟอร์มของคุณ แน่นอน.


การแยกวิเคราะห์แตกต่างจากการตรวจสอบอย่างน้อยโดยความจริงที่ว่ามันต้องมีหน่วยความจำสำหรับอาร์เรย์ไบต์ถอดรหัส ดังนั้นนี่ไม่ใช่วิธีการที่มีประสิทธิภาพที่สุดในบางกรณี
— Victor Yarema

1
@VictorYarema: ฉันแนะนำทั้งวิธีการตรวจสอบเท่านั้น (สัญลักษณ์แสดงหัวข้อย่อย) และวิธีการแยกวิเคราะห์ (หลังสัญลักษณ์แสดงหัวข้อย่อย)
— Jon Skeet

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
— panser

2
นั่นไม่ใช่กรณีอีกต่อไป การจัดการข้อยกเว้นทำงานได้ค่อนข้างดี คุณอย่าลืมว่า Java Regex ค่อนข้างช้า ฉันหมายถึง: ช้าจริงๆ! มันเร็วกว่าในการถอดรหัส Base64 และตรวจสอบว่ามันทำงาน (ไม่) แทนที่จะจับคู่สตริงกับ Regex ด้านบน ฉันทำการทดสอบคร่าวๆและการจับคู่ Java Regex ช้ากว่าประมาณหกครั้ง (!!) มากกว่าการจับข้อยกเว้นในที่สุดเมื่อถอดรหัส
— Sven Döring

ด้วยการทดสอบที่มากขึ้นมันจะช้าลงสิบเอ็ดเท่า ถึงเวลาแล้วสำหรับการติดตั้ง Regex ที่ดีขึ้นใน Java แม้แต่การตรวจสอบ Regex ด้วยเอ็นจิน Nashorn JavaScript ใน Java ก็เร็วขึ้นมาก เหลือเชื่อ. นอกจากนี้ JavaScript Regex (กับ Nashorn) มีประสิทธิภาพมากกว่ามาก
— Sven Döring

3
ด้วย Java 11 (แทนที่จะเป็น Java 8) การตรวจสอบ Regex จะช้ากว่า 22 เท่า 🤦 (เนื่องจากการถอดรหัส Base64 เร็วขึ้น)
— Sven Döring

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
ภาษานี้คืออะไร? คำถามถูกถามโดยไม่อ้างอิงภาษา
— Ozkan

สิ่งนี้จะไม่ทำงาน อ่าน docs Returns FALSE if input contains character from outside the base64 alphabet. base64_decode
— Aley

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 ใช้ regex นี้เพื่อให้แน่ใจว่าทุกตัวละครในสตริงเป็น base64 ตัวอักษร

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

หากไลบรารีที่คุณใช้เพิ่มขึ้นบรรทัดใหม่เป็นวิธีการสังเกต 76 max chars ต่อกฎบรรทัดให้แทนที่ด้วยสตริงว่าง


ลิงก์ที่กล่าวถึงแสดง 404 โปรดตรวจสอบและอัปเดต
— Ankur

ขออภัย @AnkurKumar แต่นั่นคือสิ่งที่เกิดขึ้นเมื่อผู้คนมี URL ที่ไม่ได้เก็บข้อมูล: พวกเขาเปลี่ยนตลอดเวลา ฉันไม่รู้ว่ามันถูกย้ายไปที่ใด ฉันหวังว่าคุณจะพบทรัพยากรที่มีประโยชน์อื่น ๆ ผ่าน Google
— Yaw Boakye

คุณสามารถรับหน้าเก่าจาก web.archive.org - นี่คือ URL ดั้งเดิม web.archive.org/web/20120919035911/http://…หรือฉันโพสต์ข้อความที่นี่: gist.github.com/mika76/d09e2b65159e435e7a4cc5b0299c3e84
— Mladen Mihajlovic

4

มีหลายสายพันธุ์ของ Base64ดังนั้นให้พิจารณาเพียงว่าสตริงของคุณคล้ายกับค่าความแปรปรวนที่คุณคาดหวังว่าจะจัดการหรือไม่ ดังนั้นคุณอาจจำเป็นต้องปรับ regex ด้านล่างที่เกี่ยวกับดัชนีและการขยายตัวละคร (เช่น+, /, =)

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 (เพื่อตรวจสอบว่าสตริงสามารถตรวจสอบได้กับ regexp หรือสามารถใช้ไลบรารีได้หลายคน คำตอบอื่น ๆ สำหรับคำถามนี้ให้วิธีที่ดีในการตรวจสอบดังนั้นฉันจะไม่ลงรายละเอียด)

ตัวอย่างเช่นสตริง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" ฉันสร้างข้อผิดพลาดเพื่อแก้ไขความยาวของสตริง


regex ข้างต้น /^.....$/.match(my_string) ให้ข้อผิดพลาดการจัดรูปแบบโดยบอกว่า 'ปิดไม่ตรงกัน)'
— james2611nov

และด้วย 'การสิ้นสุดก่อนกำหนดของคลาส char: / ^ (([A-Za-z0-9 + /' ข้อผิดพลาดทางไวยากรณ์)
— james2611nov

ไม่ต้องสนใจแก้ไขด้วยการเพิ่ม \ ด้านหน้าของทุก / อักขระ
— james2611nov

errorDescriptionเป็นสตริง base64 ที่ถูกต้องก็ถอดรหัสเข้าไปในลำดับไบนารีไบต์ 7a ba e8 ac 37 ac 72 b8 a9 b6 2a 27(ในฐานสิบหก):
— ลูอิสโคโลราโด

มันทำงานได้อย่างสมบูรณ์แบบสำหรับฉันที่จะตรวจสอบเบสสตริงที่เข้ารหัส 64
— Deepak Lakhara

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")ส่งคืนจริงถ้าstring hereเข้ารหัส Base64 และส่งคืนเท็จถ้า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
— Langdon

2
แนะนำให้เปลี่ยนภาษาโปรแกรมเพื่อแก้ปัญหาโดยทั่วไปไม่ใช่การตอบสนองที่ถูกต้อง
— ลูอิสโคโลราโด

0

ไม่มีวิธีในการเข้ารหัสสตริงและเบส 64 ที่แตกต่างกันยกเว้นสตริงในระบบของคุณมีข้อ จำกัด หรือการระบุเฉพาะ


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 ใช้งานไม่ได้และคุณรู้จักรูปแบบการจัดรูปแบบของสตริงต้นฉบับคุณสามารถย้อนกลับตรรกะได้โดย regexing สำหรับรูปแบบนี้

ตัวอย่างเช่นฉันทำงานกับไฟล์ xml ที่เข้ารหัส base64 และตรวจสอบว่าไฟล์มีมาร์กอัพ xml ที่ถูกต้องหรือไม่ หากฉันไม่สามารถสันนิษฐานได้ว่ามันเป็นเบส 64 ถอดรหัส มันไม่ได้เป็นแบบไดนามิกมาก แต่ทำงานได้ดีสำหรับแอปพลิเคชันขนาดเล็กของฉัน


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

ลองใช้โดยใช้ regex ที่กล่าวถึงก่อนหน้านี้:

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()ตรวจสอบที่?
— greybeard
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.