5 분 소요

☀️공지 사항☀️ 해당 게시글은 SK 쉴더스 루키즈, 생성형AI 활용 사이버보안 전문인력 양성과정 을 수업을 듣고 정리한 글입니다. 자세한 교육 정보는 SK 쉴더스 홈페이지 를 확인해주세요.

학습 내용 요약 (25/10/30)

1. 파이썬 함수의 기본 및 심화 활용

1.1. 함수의 정의 및 장점

파이썬의 함수(Function)는 객체 지향 프로그래밍(OOP)에서 메서드(Method)라고도 불리는 것으로, 일련의 실행 코드를 묶어 재사용 가능하게 만든 단위이다. 함수를 사용하면 다음과 같은 장점을 얻을 수 있다:

  • 코드 재사용이 가능하여 개발 효율성을 높인다.
  • 가독성이 향상되어 코드 이해가 쉬워진다.
  • 유지보수 및 디버깅이 용이해진다.
  • 코드를 논리적으로 나누어 모듈화할 수 있다 (예: import utils).

1.2. 인자 전달 방식

함수 호출 시 인자를 전달하는 방식은 위치 인자(Positional Argument)와 키워드 인자(Keyword Argument)로 나뉜다.

  • 위치 인자는 함수 정의 시의 매개변수 순서대로 값을 전달하는 방식이다.
  • 키워드 인자는 매개변수명=값 형태로 이름을 명시하여 순서에 관계없이 값을 전달하는 방식이다.
  • 함수 정의 시 def greet(name='guest'):와 같이 기본값 매개변수(Default Parameter)를 설정할 수 있으며, 이 경우 호출 시 인자값이 생략되면 기본값이 사용된다.
  • 가변인자는 *args 또는 **args로 나뉘는데, *args는** 튜플 형태의 인자, **args는 **dict 형태의 키워드 인자가 들어간다.

코드 예시

def userAdd(a, b):
    return a**b

======================================================================
# 위치 인자(Positional Argument) 예시
result = userAdd(2, 3)
print('type - ', type(result))
print('result - ', result)

======================================================================
# 키워드 인자(Keyword Argument) 예시
result = userAdd(b=3, a=2)
print('type - ', type(result))
print('result - ', result)


======================================================================
# default parameter
def greet(name='guest'):      # 입력값이 들어오지 않으면 기본값인 'guest'가 입력된다.
[ . . . ]

======================================================================

가변인자 예시

# *args, **kwargs 섞은거
def variableLenArgsMix(subject, *args, **kwargs) :  # 순서도 신경써야된다. 첫번째에 가변인자를 넣으면 에러뜨는 거 같음
    print('subject - ', subject)
    print('args - ', args)
    print('kwargs - ', kwargs)

variableLenArgsMix("사용자 정보", "임섭순", "섭섭해", "힝구리퐁퐁", "너무해", a=1, b=2)

=========================================================================
# 출력 예시
subject -  사용자 정보
args -  ('임섭순', '섭섭해', '힝구리퐁퐁', '너무해')
kwargs -  {'a': 1, 'b': 2}

1.3. 람다 함수 및 고차 함수 활용

람다 함수(Lambda Function)는 이름이 없는 익명 함수이며, lambda [매개 변수] : [실행문] 형태로 간단한 표현식을 한 줄로 작성할 때 유용하다. return 없이 결과값을 바로 반환한다.

  • map(function, iterable): 반복 가능한 객체에 람다 함수를 적용하여 새로운 객체를 생성하는 데 사용된다.
  • filter(function, iterable): 람다 함수의 결과가 참(True)인 요소들만 필터링하여 새로운 객체를 생성하는 데 사용된다.
  • sorted() 함수에서 key 매개변수로 람다 함수를 사용하여 정렬 기준을 정의할 수 있다. 예를 들어, 문자열 리스트를 길이 기준으로 정렬할 수 있다.

코드 예시

lst = [1,2,3,4,5,6,7,8]

print('case01 - list comprehension')
result = [ data ** 2 for data in lst ]
print(result)

print('\n---\n')

print('case02 - lambda')
print('map function')   # 열거형 타입(반복 가능한 요소에 대해서 특정 함수를 적용하고 그 결과를 map 객체로 반환함)
print('map(function, iterable)')  # map 함수는 매개변수가 2개인데, 앞에는 함수, 뒤에는 열거형 객체를 넣어준다.
# double = lambda data : data ** 2 -> 오류 발생

double=list(map(lambda data : data ** 2, lst))
print(double)  

print('\n---\n')

print('case03 - 람다 + 삼항연산 활용')
print('filter(function, iterable)')
even=list(filter(lambda data : data % 2 == 0, lst))
print(even)   

출력 예시

case01 - list comprehension
[1, 4, 9, 16, 25, 36, 49, 64]

---

case02 - lambda
map function
map(function, iterable)
[1, 4, 9, 16, 25, 36, 49, 64]

---

case03 - 람다 + 삼항연산 활용
filter(function, iterable)
[2, 4, 6, 8]

2. 파이썬 스코프 및 함수 특성 (LEGB, Closure)

2.1. 변수의 스코프 규칙 (LEGB)

파이썬에서 변수 이름을 찾는 규칙은 LEGB 순서를 따른다.

  1. L (Local): 현재 작업 중인 함수 내부의 지역 스코프이다.
  2. E (Enclosing): 중첩 함수가 있을 때, 바깥쪽(둘러싸는) 함수의 지역 스코프이다.
  3. G (Global): 모듈(파일)의 최상단 전역 스코프이다.
  4. B (Built-in): 파이썬 내장 이름들의 스코프이다 (예: print(), len()).

2.2. global 및 nonlocal 키워드

  • global: 함수 내부에서 전역(Global) 스코프의 변수 값을 읽고 수정할 수 있도록 지정하는 키워드이다.
  • nonlocal: 중첩 함수 구조에서, 안쪽 함수가 자신을 둘러싸고 있는 바깥쪽 함수(Enclosing Scope)의 변수 값을 수정할 수 있도록 지정하는 키워드이다.

2.3. 클로저(Closure)와 보안 관점

클로저는 중첩 함수의 한 형태로, 함수가 종료된 후에도 외부 함수(Enclosing)의 변수 값을 기억하고 참조하는 것을 핵심 특징으로 한다.

  • 보안 관점: 클로저는 전역 변수를 사용하지 않고도 함수 내부에서 상태를 유지할 수 있게 한다. 이는 상태를 외부에 노출하지 않고 함수 호출 간에 안전하게 캡슐화하고 관리할 수 있게 하여, 보안 설계 측면에서 이점을 제공한다. 카운터 함수 예시(counter())가 대표적이다.
  • 데코레이터는 이러한 클로저를 기반으로 구현된다.
# 전역 변수를 사용하지 않는 상태를 유지하는 코드 개선 - 클로저 이용

def counter():
    count = 0
    def increase():
        nonlocal count
        count += 1
        return count
    return increase

cnt = counter()
print(cnt())
print(cnt())
print(cnt())

======================================================================
# 출력 예시
1
2
3

3. 함수 장식자 (Decorator)

데코레이터는 함수를 감싸서 기존 함수의 코드 수정 없이 기능(공통 로직)을 수정하거나 추가시켜주는 디자인 패턴이다. 이는 클로저의 원리를 활용하여 구현된다.

  • 현업 활용 예시: 데코레이터는 로깅(Logging), 권한 체크(Permission Check), 함수 실행 시간 측정(Timer) 등의 공통 로직을 여러 함수에 일괄적으로 적용하는 데 자주 사용된다.
  • 보안 활용: 웹 프레임워크에서 특정 함수(@loginRequired) 위에 데코레이터를 붙여 사용자 인증이나 접근 권한을 손쉽게 검사하는 데 핵심적으로 사용된다.

4. 보안 관점의 함수 설계 및 코드 개선

4.1. XSS 취약점 방어: URL 인코딩 및 유효성 검증

사용자로부터 입력받은 데이터를 처리하여 URL을 생성하는 함수는 크로스 사이트 스크립팅(XSS) 공격에 취약할 수 있다. 악성 스크립트가 포함된 입력값이 URL 문자열에 그대로 포함될 경우, 해당 스크립트가 실행될 위험이 있다.

이러한 취약점을 방어하기 위해 다음과 같은 개선 방법이 적용되었다:

  • 개선 1: URL 인코딩 적용 (urllib.parse.quote)

    • 파이썬의 urllib.parse 모듈의 quote() 함수를 사용하여 입력 문자열 내의 특수문자를 안전하게 인코딩한다.
    • <는 %3C, >는 %3E 등으로 변환되어 브라우저가 스크립트로 해석하지 못하게 막는다.
    from urllib.parse import quote
      
    def safeMakeUrl(listIn:list) -> list:
        # quote()를 사용하여 특수문자를 인코딩하여 XSS 공격을 방지한다.
        return list(map(lambda x:'www.'+quote(x)+'.com', listIn))
    
  • 개선 2: 입력 타입 유효성 검증

    • 함수의 안정성을 위해 입력값의 타입이 예상한 list와 그 내부 요소가 str인지 검증하는 로직을 추가한다.
    • isinstance(lst, list)로 전체 타입 검사를 수행하고, all(isinstance(name, str) for name in lst)로 리스트 내부 요소 전체의 타입을 검사하여 예상치 못한 타입 입력(예: 숫자 10)으로 인한 오류를 방지한다.
    def safeMakeUrl(lst:list) -> list:
        if not isinstance(lst, list):
            raise TypeError("입력은 리스트 타입으로 전달 부탁드립니다.")
        if not all(isinstance(name, str) for name in lst):
            raise ValueError("요소의 타입은 문자열로 전달 부탁드립니다.")
        # 검증 통과 시 안전하게 URL 인코딩 후 리턴한다.
        return list(map(lambda x:'www.'+quote(x)+'.com', lst)) 
    

4.2. API 요청 생성 시 매개변수 화이트리스트 적용

**kwargs를 이용하여 가변적인 키워드 인자를 받는 API 요청 생성 함수에서, 보안 강화 및 매개변수 남용 방지를 위해 화이트리스트(whiteList)를 적용하여 허용된 매개변수만 사용하는 것이 중요하다.

  • 보안 원칙: API 요청 시 필요 없는 매개변수를 차단하여 불필요한 데이터 전송을 최소화하고, 잠재적인 민감 정보나 공격 매개변수가 API에 전달되는 것을 막는 방어 기법이다.
  • makeApiRequest 함수는 whiteList에 정의된 키('q', 'page', 'lang')만 필터링하여 안전한 safeParams를 생성하고, 이를 기반으로 URL을 인코딩한다.
from urllib.parse import urlencode

def makeApiRequest(endpoint, **params):
    whiteList = {'q', 'page', 'lang'}  # 허용된 매개변수 화이트리스트
    
    # 화이트리스트에 있는 키만 필터링하여 안전한 매개변수(safeParams)를 생성한다.
    safeParams = { key:value for key, value in params.items() if key in whiteList }
    queryString = urlencode(safeParams)

    if queryString:
        url = f"{endpoint}?{queryString}"
    else:
        url = endpoint

    return url

공부 후기

오늘 파이썬 함수의 심화 개념과 보안 적용 기법에 대해 매우 깊이 있게 공부했다. 오늘은 특별히 앞선 날보다 더 어려웠다ㅠㅠ..(끝나고 동기들한테 물어보니 전공자들도 어려웠다고..)

하지만 보안 관점에서 개선할만한 기법들을 많이 배운 것 같아서 뿌듯한 하루였다! 정리한 내용을 계속 반복해서 보면서 익숙해져야겠다..! 내일도 화이팅!

태그: ,

카테고리:

업데이트:

댓글 남기기