본문 바로가기
해킹 기초지식

정규 표현식(Regex)

by whiteTommy 2023. 11. 27.

보안에서 공격은 이용자가 값을 자유롭게 입력할 수 있는 지점에서 발생한다. 이러한 취약점을 줄이기 위해서는 사용자의 입력 값을 절대 신뢰해서는 안 되며, 항상 검증하여(Never Trust, Always Verify) 서버에서 올바른 데이터만 다루도록 강제해야 한다. 이러한 검증을 위해서는 정규 표현식이 사용된다. 간단하게 특정 형식의 문자열을 표현하고, 형식이 일치하는지 검증할 수 있다.

 

정규 표현식

: 특정한 패턴으로 문자열을 표현하는 식이다.

정규 표현식에 부합하는 문자열의 경우, 정규 표현식 혹은 패턴에 '매치한다'라고 표현한다.

 

아래는 이메일 형식을 표현하는 정규 표현식의 예시이다. 

^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$

 

매우 긴 문자열에서 원하는 형식의 문자열을 검색하여 추출할 도 정규 표현식을 사용한다. 

 

 

정규 표현식 패턴

: '패턴' 혹은 /패턴/의 형태로 작성한다. /로 패턴을 감싸는 경우, /뒤에 플래그를 작성할 수 있다.

 

매치

  • ^ : 문자열의 시작이 특정 패턴인 경우 매치한다.
  • $ : 문자열의 끝이 특정 패턴인 경우 매치한다.
  • . : 모든 문자와 매치한다.
  • | : 앞 또는 뒤의 패턴과 매치한다.
  • 문자 혹은 문자열 : 해당 문자 혹은 문자열과 매치한다.
  • [ ] : [ ] 안의 문자와 매치한다.
  • [^ ] : ^ 뒤의 패턴을 제외한 나머지와 매치한다.
  • \ : \ 뒤의 특수문자와 매치한다. 특별한 목적으로 사용되는 특수 문자를 문자 그대로 쓰기 위한 이스케이핑이다.
  • [a-z] , [A-Z], [0-9] : 두 문자 사이 범위의 문자와 매치한다.
  • \w : 알파벳 또는 숫자 또는 _ 와 매치한다. [A-Z a-z 0-9 _ ] 
  • \d : 숫자와 매치한다. [0-9]
  • \s: 공백 문자와 매치한다. [ \b \f \n \r \t \v ]

 

수량자

  • * : 앞에 나온 문자가 0개 이상이면 매치한다.
  • + : 앞에 나온 문자가 1개 이상이면 매치한다.
  • ? : 앞에 나온 문자 0개 혹은 1개이면 매치한다.
  • 수량자? : 수량자 뒤에?를 붙이면 게으른 수량자로, 최소한의 문자만 매치한다.
  • {n} : 앞에 나온 문자가 정확히 n개이면 매치한다.
  • {n, } : 앞에 나온 문자가 n개 이상이면 매치한다.
  • {n1, n2} : 앞에 나온 문자가 n1개 이상, n2개 이하이면 매치한다.
Hac{2,3}k -> Hacck //매치(c가 2개 이상 3개 이하)
Hac{2, }k -> Haccck //매치(c가 2개 이상)
Hac{3}k -> Haccck //매치(c가 3개)
Hack+? -> Hackk //매치X (k가 최소한의 문자(1개))
Hack+? -> Hack //매치(k가 최소한의 문자인 1개)

 

아래는 수량자?에 관한 더 자세한 내용이다.

<p>.*</p> -> <p>Hello</p><p>Hi</p>	//모두 매치

 

*는 앞에 나온 문자(. : 모든 문자)가 0개 이상이면 매치된다. 즉, <p></p> 사이에 있는 모든 문자가 매치된다.

 

<p>.*?</p> -> <p>Hello</p><p>Hi</p>		//<p>Hello</p>만 매치

 

<p> 태그로 감싸진 모든 내용을 매치하지만, 게으른(lazy) 수량자로서 매치가 발생하면 종료된다. 기본적으로 정규 표현식의 수량자는 탐욕적(greedy) 수량자이다.

 

 

그룹화

  • ( ) : ( )로 감싼 부분을 그룹화하여 하나의 문자처럼 여긴다.
(ha)+ck -> hahahack 	//매치

 

 

정규 표현식 플래그

: 검색의 옵션을 지정하는 역할을 한다. / 패턴 / 플래그 형식으로 작성한다.

 

  1. g(global search) : 매치하는 모든 문자/문자열을 검색한다.
  2. i(ignore case) : 대소문자를 구분하지 않고 검색한다.
  3. m(multiline) : 여러 줄에서 검색한다.
  4. s(single line(dotall)) : 메타문자 . 가 개행문자도 포함한다.

 

 

Python 정규 표현식

: re 모듈을 통해 정규 표현식을 사용한다. re 모듈의 함수를 호출하여 패턴에 일치하는 문자열을 검색하거나 치환하는 등 다양한 동작을 수행한다.

  • re.compile(pattern, flags) : 정규 표현식 패턴을 컴파일한다. (패턴 객체 반환)
  • re.search(pattern, string, flags) : 문자열 내에서 패턴에 처음으로 매치하는 문자열을 검색한다. (매치하는 문자열이 있으면 문자열 객체를 반환, 없으면 None을 반환)  group() 메서드를 사용한다.
  • re.match(pattern, string, flags) : 문자열 시작 부분에서 패턴에 매치하는 문자열을 검색한다. (매치하는 문자열이 있으면 문자열 객체를 반환, 없으면 None을 반환)  group() 메소드를 사용한다.
  • re.fullmatch(pattern, string, flags) : 전체 문자열이 패턴과 정확하게 매치하는지 확인한다. (매치하는 문자열이 있으면 문자열 객체를 반환, 없으면 None을 반환)  group() 메소드를 사용한다.
  • re.findall(pattern, string, flags) : 문자열 내에서 패턴에 매치하는 모든 문자열을 검색한다. (리스트로 반환)
  • re.finditer(pattern, string, flags) : 문자열 내에서 패턴에 매치하는 모든 문자열을 검색한다.(리스트로 반환)

 

flags 

: Python에서 정규 표현식 플래그는 함수의 flags 인자 값으로 지정하거나, 패턴에 인라인 형식으로 작성한다.

플래그 flags 인자 값 인라인 플래그
i re.I(re.IGNORECASE) (?i)
m re.M(re.MULTILINE) (?m)
s re.S(re.DOTALL) (?s)
g 자동으로 적용된다.

 

Row String(r-string)

: 정규 표현식 패턴 내에 백슬래쉬를 사용하면 이스케이프 문자로 인식되어 패턴이 의도와 다르게 해석될 수 있다. 이를 막기 위해, 패턴을 작성할 때 사용되는 것이다. 문자열 앞에 'r'을 붙여 나타낸다. 이스케이프 문자를 문자 그대로 인식하는 특수한 문자열이다. 

print('\t' + 'Hi')
# Result : 	Hi

# Raw String
print(r'\t' + 'Hi')
# Result : \tHi

 

아래는 정규 표현식을 활용하여 전체 문자열에서 알파벳 대문자만 출력하는 예시이다.

import re

result = re.findall('[A-Z]', 'Hello, DreamHack!')

#same
pattern = re.compile('[A-Z]')
result = pattern.findall('Hello, DreamHack!')

print(result)

#result = ['H', 'D', 'H']

 

 

 

JavaScript 정규 표현식

  1. 정규 표현식 리터럴 : /패턴/ 혹은 /패턴/플래그의 형태로 작성한다.
  2. RegExp 객체를 생성 : new RegExp(정규 표현식 리터럴, '플래그') 혹은 new RegExp('패턴', '플래그')로 객체를 생성한다.
  • pattern.exec(string) : 패턴에 처음으로 매치하는 문자열의 일치 정보를 나타내는 결과 배열을 반환한다
  • patten.test(string) : 패턴에 매치하는 부분이 있으면 true, 없으면 false를 반환한다
  • string.match(pattern) : 패턴에 매치하는 모든 문자열을 배열 형태로 반환한다
const r = /\d/g;
// same
// const r = new RegExp('\\d','g');
// const r = new RegExp(/\d/,'g');

const str = 'H3ll0, DreamH4ck!';
const result = str.match(r);
console.log(result);

결과 : ['3', '0', '4']

 

 

이제, 배운 내용들을 바탕으로 앞서 언급했던 이메일 정규 표현식을 살펴보자.

^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$

 

^ : 문자열의 시작을 매치한다.

[\w-\.]+ : 이메일의 앞 부분을 매치한다. word(\w)와 하이픈(-), 마침표(.) 문자 중 하나 이상이 여러 번 반복되는 문자열을 매치한다. 

 

@ : 이메일 가운데에 위치한 @문자를 매치한다.

 

[\w-] + \ .)+ : @뒤에 도메인 부분을 매치한다. word(\w)와 하이픈(-), 마침표(.) 문자 중 하나 이상이 여러 번 반복되는 문자열인데, 마지막에 마침표 (. )가 있는 문자열을 매치한다. '('와 ')'로 감싼 후 가장 우측에 +를 사용했기 때문에, domain. 도 매치하고, subdomain.domain. 도 매치한다.

 

[\w-] {2,4} : 이 부분은 도메인 이름의 최상위 도메인(com, net)을 매치한다. word(\w)와 하이픈(-) 문자 중 하나 이상이 2개에서 4개까지 반복되는 문자열을 매치한다.

 

$ : 문자열의 끝을 매치한다.