Base64 데이터를 구문 분석하거나 유효성을 검사하는 RegEx


99

RegEx를 사용하여 Base64 데이터의 유효성을 검사하거나 삭제하는 것이 가능합니까? 그것은 간단한 질문이지만이 질문을 유도하는 요인은 그것을 어렵게 만드는 것입니다.

RFC 사양을 따르기 위해 입력 데이터에 완전히 의존 할 수없는 Base64 디코더가 있습니다. 그래서 내가 직면하는 문제는 아마도 Base64 데이터와 같은 문제이며 78로 나뉘 지 않을 수도 있습니다 (78이라고 생각합니다. RFC를 다시 확인해야하므로 정확한 숫자가 잘못되었다고 생각하지 마십시오). 라인 또는 라인이 CRLF로 끝나지 않을 수 있습니다. CR 또는 LF 만 있거나 둘 다 없을 수도 있습니다.

그래서 나는 그런 형식의 Base64 데이터를 파싱하는 데 엄청난 시간을 보냈습니다. 이로 인해 다음과 같은 예는 안정적으로 디코딩 할 수 없게됩니다. 간결성을 위해 부분 MIME 헤더 만 표시합니다.

Content-Transfer-Encoding: base64

VGhpcyBpcyBzaW1wbGUgQVNDSUkgQmFzZTY0IGZvciBTdGFja092ZXJmbG93IGV4YW1wbGUu

좋습니다. 파싱은 문제가되지 않으며 우리가 기대하는 결과입니다. 그리고 99 %의 경우, 버퍼의 각 문자가 유효한 base64 문자인지 확인하기 위해 코드를 사용하면 완벽하게 작동합니다. 그러나 다음 예제에서는 렌치를 믹스에 넣습니다.

Content-Transfer-Encoding: base64

http://www.stackoverflow.com
VGhpcyBpcyBzaW1wbGUgQVNDSUkgQmFzZTY0IGZvciBTdGFja092ZXJmbG93IGV4YW1wbGUu

이 버전은 일부 바이러스 및 일부 메일 독자가 모든 비용을 들여 마임을 구문 분석하려는 다른 것들에서 본 Base64 인코딩 버전입니다. 당신이 원한다면.

My Base64 디코더는 두 번째 예제를 다음 데이터 스트림으로 디코딩합니다. 여기서 명심하세요. 원본 스트림은 모두 ASCII 데이터입니다!

[0x]86DB69FFFC30C2CB5A724A2F7AB7E5A307289951A1A5CC81A5CC81CDA5B5C1B19481054D0D
2524810985CD94D8D08199BDC8814DD1858DAD3DD995C999B1BDDC8195E1B585C1B194B8

누구나 한 번에 두 가지 문제를 해결할 수있는 좋은 방법이 있습니까? 다른 규칙이 적용된 데이터에 대해 두 가지 변환을 수행하고 결과를 비교하는 것 외에는 가능할지 모르겠습니다. 그러나 그러한 접근 방식을 취했다면 어떤 결과물을 신뢰합니까? ASCII 휴리스틱 스가 최상의 솔루션 에 관한 것 같지만 ,이 코드가 실제로 관여하는 바이러스 스캐너만큼 복잡한 것에 얼마나 더 많은 코드, 실행 시간 및 복잡성이 추가 될까요? 허용되는 Base64와 그렇지 않은 것을 학습하기 위해 휴리스틱 엔진을 어떻게 훈련 시키겠습니까?


최신 정보:

이 질문이 계속해서 얻는 조회수를 고려하여 지금까지 C # 애플리케이션에서 3 년 동안 사용해 온 간단한 RegEx를 수십만 건의 트랜잭션으로 게시하기로 결정했습니다. 솔직히 검보 님 의 답변 이 가장 마음에 들어서 제가 선택한 답변으로 꼽았습니다. 그러나 C #을 사용하는 사람에게 문자열 또는 byte []에 유효한 Base64 데이터가 포함되어 있는지 여부를 감지하는 매우 빠른 방법을 찾고있는 사람에게는 다음이 매우 잘 작동한다는 것을 알았습니다.

[^-A-Za-z0-9+/=]|=[^=]|={3,}$

그리고 예, 이것은 올바른 형식의 RFC1341 메시지가 아닌 Base64 데이터 의 STRING 을위한 것 입니다. 따라서 이러한 유형의 데이터를 처리하는 경우 위의 RegEx를 사용하기 전에이를 고려하십시오. 당신은 Base16, Base32, 기수 또는 다른 목적 (URL을 파일 이름, XML 인코딩 등)도 Base64로 처리하는 경우,되어 매우 당신이 읽을 것을 권장 RFC4648을 것을 검보는 당신이 잘 할 필요가로서 그의 대답에 언급 이 질문 / 답변 세트의 제안을 사용하기 전에 구현에서 사용하는 문자 세트와 종결자를 알고 있어야합니다.


작업을 더 잘 정의해야한다고 생각합니다. 당신의 목표가 무엇인지는 완전히 불분명합니다. 엄격해야합니까? 샘플의 100 %를 구문 분석 하시겠습니까? ...
ADEpt

첫 번째 예는 'VGhpcyBpcyBhIHNpbXBsZSBBU0NJSSBCYXNlNjQgZXhhbXBsZSBmb3IgU3RhY2tPdmVyZmxvdy4 ='이어야합니다
jfs

귀하의 언어로 표준 솔루션을 사용하지 않는 이유는 무엇입니까? 정규식을 기반으로 손으로 작성한 파서가 필요한 이유는 무엇입니까?
jfs

1
좋은 질문입니다. NPM에서 반환 한 base64 인코딩 SHA에 대해 실행 하여 UPDATE 정규식을 시도했지만 실패한 반면 선택한 답변의 정규식은 잘 작동합니다 .
Josh Habdas

1
UPDATE 정규식이 수정없이 어떻게 게시 되는지 확실 하지 않지만 작성자 가 시작 앵커로 대괄호 외부 를 넣을 의도 로 한 것처럼 보입니다 ^. 그러나, 더 나은 정규식은 허용 대답처럼 복잡받지 않고, 될 것이다^[-A-Za-z0-9+/]*={0,3}$
kael

답변:


147

로부터 4648 RFC :

데이터의 기본 인코딩은 레거시 이유로 US-ASCII 데이터로 제한되는 환경에서 데이터를 저장하거나 전송하기 위해 많은 상황에서 사용됩니다.

따라서 데이터가 위험한 것으로 간주되어야하는 경우 인코딩 된 데이터의 사용 목적에 따라 다릅니다.

그러나 Base64로 인코딩 된 단어와 일치하는 정규식을 찾고 있다면 다음을 사용할 수 있습니다.

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

10
가장 간단한 해결책은 유효성 검사 전에 모든 공백 (RFC에 따라 무시 됨)을 제거하는 것입니다.
Ben Blank

2
패딩에 대한 마지막 비 캡처 그룹은 선택 사항입니다.
Gumbo

4
처음에는 복잡성에 회의적 이었지만 꽤 잘 검증되었습니다. base64-ish와 일치하고 싶다면 ^ [a-zA-Z0-9 + /] = {0,3} $를하는 것이 좋습니다!
Lodewijk 2014 년

3
@BogdanNechyporenko 이는 name(hex) 바이트 시퀀스의 유효한 Base64 인코딩 이기 때문 입니다 9d a9 9e.
Marten

3
^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{4})$반발을
피해야

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

이것은 좋지만 빈 문자열과 일치합니다.

이것은 빈 문자열과 일치하지 않습니다.

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

2
빈 문자열이 잘못된 이유는 무엇입니까?
Josh Lee

8
그렇지 않습니다. 그러나 정규식을 사용하여 주어진 문자열이 base64인지 아닌지 확인하는 경우 빈 문자열에 관심이 없을 가능성이 있습니다. 적어도 나는 그렇지 않다는 것을 압니다.
njzk2

4
@LayZee : 그렇게하면 base64 문자열에 최소 4 개의 크기 블록이 포함되도록 강제 MQ==하여 표현식과 일치하지 않는 것과 같은 유효한 값을 렌더링합니다
njzk2

5
@ruslan도 마찬가지입니다. 유효한 base 64 문자열이 아닙니다. (크기는 23이며 // 4가 아닙니다). AQENVg688MSGlEgdOJpjIUC=유효한 형식입니다.
njzk2

1
@JinKwon base64는 0, 1 또는 2로 끝납니다 =. 마지막 ?은 0 =입니다. 로 {1}=
바꾸

4

둘은 " : "도 아니고 "이 . 난 당신이 명확하게 버릴 수 있다고 생각하므로, 유효 Base64로에 표시됩니다" http://www.stackoverflow.com라인. Perl에서는 다음과 같이 말하십시오.

my $sanitized_str = join q{}, grep {!/[^A-Za-z0-9+\/=]/} split /\n/, $str;

say decode_base64($sanitized_str);

당신이 원하는 것일 수 있습니다. 그것은 생성합니다

이것은 StackOverflow 예제를위한 간단한 ASCII Base64입니다.


동의 할 수는 있지만 URL의 다른 모든 문자는 유효한 base64입니다 ... 그래서, 선을 어디에서 그리나요? 줄 바꿈에서? (라인 중간에 무작위 문자 몇 개만있는 것을 본 적이 있습니다. 그 때문에 나머지 라인을 던질 수는 없습니다. IMHO) ...
LarryF

@LarryF : base-64로 인코딩 된 데이터에 대한 무결성 검사가 없으면 잘못된 문자가 포함 된 base-64 데이터 블록으로 무엇을해야하는지 알 수 없습니다. 가장 좋은 경험적 방법은 잘못된 문자 (모든 올바른 문자 허용)를 무시하거나 줄을 거부하거나 로트를 거부하는 것입니다.
Jonathan Leffler

(계속) : 짧은 대답은 "따라 다릅니다"입니다. 데이터의 출처와 데이터에서 찾은 엉망의 종류에 따라 다릅니다.
Jonathan Leffler

(재개 됨) : 댓글에서 base-64 일 수있는 모든 것을 수락하고 싶은 질문에 대한 내용을 확인했습니다. 따라서 줄 바꿈 및 콜론을 포함하여 base-64 알파벳에없는 모든 문자 (URL 안전 및 기타 변형 인코딩이 있음)를 매핑하고 남은 문자를 가져 오십시오.
Jonathan Leffler

3

지금까지 찾을 수있는 최고의 정규식이 여기에 있습니다. https://www.npmjs.com/package/base64-regex입니다.

현재 버전에있는 것은 다음과 같습니다.

module.exports = function (opts) {
  opts = opts || {};
  var regex = '(?:[A-Za-z0-9+\/]{4}\\n?)*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)';

  return opts.exact ? new RegExp('(?:^' + regex + '$)') :
                    new RegExp('(?:^|\\s)' + regex, 'g');
};

없이 어쩌면 더 나은 \\n?.
진 권

이것은 JSON 문자열에서 실패합니다
idleberg

3

base64 이미지의 유효성을 검사 하기 위해이 정규식을 사용할 수 있습니다.

/ ^ data : image / (?: gif | png | jpeg | bmp | webp) (? :; charset = utf-8) ?; base64, (? : [A-Za-z0-9] | [+ /] ) + = {0,2}

  private validBase64Image(base64Image: string): boolean {
    const regex = /^data:image\/(?:gif|png|jpeg|bmp|webp)(?:;charset=utf-8)?;base64,(?:[A-Za-z0-9]|[+/])+={0,2}/;
    return base64Image && regex.test(base64Image);
  }

0

다음은 대체 정규식입니다.

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

다음 조건을 충족합니다.

  • 문자열 길이는 4의 배수 여야합니다. (?=^(.{4})*$)
  • 내용은 영숫자 또는 + 또는 /-여야합니다. [A-Za-z0-9+/]*
  • 끝에 최대 2 개의 패딩 (=) 문자를 사용할 수 있습니다. ={0,2}
  • 빈 문자열을 허용합니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.