วิธีการตรวจสอบว่าสตริงนั้นมีการเข้ารหัส 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จะจับคู่ แต่ไม่จำเป็นต้องแสดงถึงค่าที่เข้ารหัสของเพียง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.