2020년 6월 29일 월요일

Credential Stuffing Attack

M8gu96mB76 Netflix 비밀번호로 설정한 다음 Amazon, New York Times 가입 및 은행 계좌의 비밀번호로 재사용한다고 가정해 보겠습니다. 해커가 이러한 시스템중 하나에 침입하여 암호를 얻으면 암호를 사용하여 나머지 모든 시스템에 액세스 할 수 있습니다.

Credential Stuffing 공격은 계정 탈취의 한 형태이며, 그 결과는 불편함 (계정에서 가입자를 잠그는 Disney + 해킹에서와 같이)에서 혼란스럽고 사악한 범죄 ( : 해커가 홈카메라로 침입하여 어린이를 몰래 감시)에 이르기까지 다양합니다.

Credential Stuffing 공격이 일반적으로 작동하는 방법은 다음과 같습니다.

1 단계 : 해커가 사용자 이름과 비밀번호가 포함된 데이터베이스에 액세스합니다. 이 초기 사이버 공격은 정교한 해킹에서부터 데이터베이스에 대한 액세스 권한이 있는 관리자에 대한 피싱 공격, 공개적으로 액세스할 수 있는 영역에 남겨진 보호되지 않은 레코드에 이르기까지 다양한 방식으로 발생할 수 있습니다.

2 단계 : 해커는 이 정보를 복사하여 다른 해커가 사용할 수 있도록 정보를 판매하거나 게시합니다 (일반적으로 다크웹에 게시).

3 단계 : 사이버 범죄자는 한 사이트의 사용자 이름과 비밀번호를 사용하여 다른 사이트에 액세스하려고 시도합니다. 성공률은 상대적으로 낮기 때문에 해커는 자동화에 의존합니다. 봇넷은 액세스 권한을 부여할 때까지 수백만개의 사용자 이름-암호 조합을 시도합니다.

해커가 피해자 사이트에 액세스하면 다양한 형태의 장난을 일으킬 수 있습니다. 다음은 가장 일반적인 3가지입니다.

손상된 계정에 대한 액세스 판매 : 특히 스트리밍 미디어 서비스에 일반적입니다. Disney+, Netflix Spotify는 해커가 구독 비용보다 적은 비용으로 사용자 계정에 대한 액세스 권한을 판매한 공격의 피해자입니다.

전자 상거래 사기 : 해커는 소매 웹사이트에서 합법적인 사용자를 사칭하여 사용 또는 재판매를 위해 고가의 제품을 주문할 수 있습니다. 이것은 일반적인 신원 도용의 형태로, 소매업은 자격증 소지에 가장 취약한 업종입니다.

회사 및 기관 도용 : 위의 2가지는 회사와 고객에게 심각한 결과를 초래하지만 이 공격은 비즈니스에 가장 치명적일 수 있습니다. 공격자가 직원이나 관리자의 계정을 도용하면 모든 종류의 민감한 내부 데이터에 액세스하여 최고 입찰자에게 판매할 수 있습니다. 당연히, 손상된 데이터에는 사용자 이름 및 비밀번호 데이터베이스가 포함될 수 있습니다.

2020년 6월 27일 토요일

파이썬의 input()을 사용한 입력방법

다른 프로그래밍 언어와 마찬가지로 파이썬에서 키보드를 통해 어떤 숫자나 문자열을 입력받을 수 있습니다. 그때 사용하는 구문이 "input()"입니다. Input()내에 입력할 때 의미를 잘 알 수 있도록 여러가지 문장도 추가가능합니다.

아래 소스가 input()을 활용한 소스 코드입니다.

a = input('점수를 입력하세요 : ')
print ("입력한 점수는 ", a, " 입니다")

if a < 100:
    print ("입력한 점수는 100보다 작다 : ", a)
elif a > 100:
   print ("입력한 점수는 100보다 크다 : ", a)
else:
   print ("입력한 점수는 100과 같습니다 : ", a)

그런데 위의 소스를 실행하면 아래와 같이 에러가 발생됩니다.

점수를 입력하세요 : 100
입력한 점수는  100  입니다
Traceback (most recent call last):
  File "test.py", line 11, in <module>
    if a < 100:
TypeError: '<' not supported between instances of 'str' and 'int'

그 이유는 파이썬의 input()로 입력받은 결과값은 문자열 형태이기 때문입니다. C언어에서도 숫자나 문자열을 입력받는 방법이 조금 다르죠. 그 해결방법은 입력받은 문자열을 필요한 다른 데이터 타입으로 변환시켜야 합니다.

다음의 소스를 보시면 input()int()를 사용해서 문자열을 정수로 변환시킵니다. 만약 실수형으로 변환하려면 float()를 사용하면 됩니다.

a = int( input('점수를 입력하세요 : ') )
print ("입력한 점수는 ", a, " 입니다")

if a < 100:
    print ("입력한 점수는 100보다 작다 : ", a)
elif a > 100:
   print ("입력한 점수는 100보다 크다 : ", a)
else:
   print ("입력한 점수는 100과 같습니다 : ", a)

위의 소스를 실행하면 아래와 같이 제대로 실행됨을 알 수 있습니다.

점수를 입력하세요 : 100
입력한 점수는  100  입니다
입력한 점수는 100과 같습니다 :  100


2020년 6월 26일 금요일

HDCP (High-Bandwidth Digital Content Protection)

영화나 TV를 시청할때 시청하는 콘텐츠는 보호되어야 하고 이러한 보호는 저작권법으로 정의되어 있습니다. 저작권 침해는 책이나 영화와 같은 저작물이 허가없이 사용될때 발생합니다. 저작물을 표시, 배포 또는 복제할 수 있는 권리는 디지털 또는 서면 컨텐츠의 저작권 보유자에게 부여됩니다. 허가없이 이러한 저작물을 사용하면 해당 권리가 침해되고 제작자 또는 소유자에게 손해를 끼치게 됩니다.

이 문제를 해결하기 위해 개발된 HDCP는 고대역폭 디지털 컨텐츠 보호 (High-Bandwidth Digital Content Protection)를 말하며, 콘텐츠 제작자와 배포자를 디지털 불법 복제로부터 보호하기 위해 설계된 DRM (Digital Rights Management)으로서 복사 방지 방식으로 영상 소스와 디스플레이 사이의 디지털 데이터 스트림을 가로챌 가능성을 제거합니다. 비디오 및 오디오가 제공되기 전에 인증 및 키 교환 절차 등이 정의되어 있습니다. DVD 플레이어, 위성 및 케이블 HDTV 셋톱 박스와 같은 HDCP 체계와 호환되는 제품은 호환되는 디스플레이에 연결해야 합니다. 장비에 HDCP를 사용하는 제조업체가 증가함에 따라 HDCP 호환 HDTV를 구매하는 것이 권고됩니다.

HDCP 암호화를 사용하는 디지털 (DVI 또는 HDMI) 연결을 통해 720p / 1080i / 1080p 등의 해상도들이 지원됩니다.

HDCP 세션에서 영상 소스와 디스플레이 장치간에 키가 교환되는데, 소스 장치는 비디오를 표시하기 전에 장비가 HDCP를 준수하는지 확인하기 위해 디스플레이를 확인합니다. PC 및 구형 DVI 제품과 같은 HDCP를 지원하지 않는 장치는 모든 DVI 호환 디스플레이에서 작동하지만 HDCP 호환 상자는 HDCP 호환 디스플레이에서만 이미지를 표시합니다.

HDCP의 영향을 받는 다른 제품으로는 스케일러 (Scaler), 스위처 (Switcher) 및 분배 앰프 (Distribution Amp)가 있습니다. 이러한 장치는 키 교환에 대한 인증을 하지 않지만 비디오가 어떤 방식으로든 처리되는 경우 HDCP의 존재를 전송할 수 있어야 합니다. 서로 다른 두가지 형식의 디지털 연결로 인해 적절한 통신이 불가능할 경우 상호 운용성이 상실될 수 있습니다.

다음은 DVD 플레이어에서 영화를 재생할때 HDCP 라이센스 장치에서 발생하는 하나의 예입니다.

DVD를 컴퓨터에 넣은후 송신기는 수신기 (컴퓨터) HDCP 키 컨트롤이 있는 올바른 라이센스가 있는지 확인합니다.
컴퓨터에 올바른 라이센스가 없으면 콘텐츠 데이터를 받지 않으며 HDCP 암호화 데이터를 표시할 수 없습니다.
컴퓨터에 HDCP 컨트롤이 있으면 동영상이 컴퓨터 화면에 표시됩니다.

이 프로세스는 영화를 볼때만 발생한다고 생각할 수 있지만 송신기는 시청하는 동안 지속적으로 HDCP 라이센스를 확인합니다. 한편, 다른 수신자가 콘텐츠를 훔치거나 보지 못하게 할 수도 있습니다.

아래는 간략하게 정리된 HDCP 연결 구성도입니다.

2020년 6월 24일 수요일

파이썬의 조건문 if, else, elif

다른 프로그래밍 언어와 마찬가지로 파이썬에서도 거의 비슷한 구문을 지원하는데, 바로 if, else,elif입니다.

간단한 샘플 코드를 보면 이해하기 쉬울거 같습니다.

a = 100
print ("a는 ", a)

if a == 100:
   print ("a는 100이다 : ", a)
else:
   print ("a는 100이 아니다 : ", a)


한가지 조건일 경우에는 "if ~ else ~"로 코드를 작성하면 됩니다. 아래는 위의 코드의 실행 결과입니다.

a는  100
a는 100이다 :  100


조건을 2개 이상일 경우에는 "if ~ elif ~ ... else"를 사용하면 됩니다.

a = 100
print ("a는 ", a)

if a < 100:
    print ("a는 100보다 작다 : ", a)
elif a > 100:
   print ("a는 100보다 크다 : ", a)
else:
   print ("a는 100이다 : ", a)


위의 코드의 실행 결과는 아래와 같습니다.

a는  100
a는 100이다 :  100

2020년 6월 23일 화요일

RPMB (Replay Protection Memory Block)

EMMC, UFS 및 NVMe와 같은 스토리지 기술은 범용 프로토콜 및 프레임 레이아웃을 가진 RPMB 하드웨어 파티션을 지원합니다.

RPMB 파티션은 표준 블록 계층을 통해 액세스할 수 없지만 WRITE, READ, GET_WRITE_COUNTER 및 PROGRAM_KEY와 같은 특정 명령 세트를 통해 액세스할 수 있습니다.
이러한 파티션은 인증 및 재생 보호 액세스 (Replay Protected Access)를 제공하므로 보안 스토리지로 적합합니다.

RPMB 계층은 Block Frame Signature을 안전하게 계산할 수 있는 TEE (Trusted Execution Environment) 장치를 위한 API를 제공합니다.

TEE (Trusted Execution Environment) 장치가 재생 보호 (Replay Protection) 데이터를 저장하고자 하는 경우, 요청된 데이터로 RPMB 프레임을 생성하고 프레임의 HMAC를 계산한 다음 RPMB 계층을 통해 저장 장치에 데이터를 저장하도록 요청합니다.

일반적으로 RPMB 파티션에 액세스 (예 : 읽기 또는 쓰기)하기 전에 RPMB 인증 키를 eMMC / UFS 또는 NVMe 장치의 RPMB 컨트롤러에 프로그래밍해야 합니다.

이 키는 한 번만 프로그래밍해야 하며 (최소한 RPMB 사양에 따라) 프로그래밍 명령 / 요청에서 RPMB 키를 일반 텍스트로 보내야 하므로 일반적으로 안전한 환경에서 프로비저닝해야 합니다. 예를 들면 공장 제조 라인 또는 eMMC / UFS / NVMe를 교체한후 현장의 신뢰할 수 있는 펌웨어 환경을 말합니다.

프로그래밍후 이 RPMB 키도 잘 보호해야 하므로 일반적으로 RPMB 사용시 OP-TEE, Google Android Trusty 또는 x86 Intel 플랫폼용 TEE (신뢰할 수 있는 실행 환경)가 제공됩니다. 그러나 이러한 TEE 환경에는 일반적으로 RPMB 드라이버가 없으며 이 키를 보호를 위해 TEE (또는 안전한 세계) 내에 안전하게 유지하는 반면, RPMB 드라이버 자체는 일반적인 비보안 환경에 있어야 합니다.

그런 다음, TEE는 RPMB 키를 사용하여 RPMB 데이터에 서명하고 HMAC-SHA256 인증 서명 (MAC)과 함께 RPMB 데이터를 Linux over IPC (보안 세계 TEE 및 secure world Linux)로 보냅니다. Linux 커널 드라이버는 인증 쓰기를 위해 해당 데이터 조각 (RPMB 프레임)을 RPMB 물리적 장치로 함께 전송하는 책임을 집니다.


REPLAY 보호와 관련하여 읽기 / 쓰기 액세스를 위해 다음과 같이 달성할 수 있습니다. 스토리지 컨트롤러 H/W 내장 쓰기 카운터 (Write Counter)가 쓰기 액세스에 대한 재생 보호에 사용됩니다. 인증 쓰기 (Authenticated Write)가 성공할 때마다 H/W 쓰기 카운터 (Write Counter)는 1씩 증가합니다 (처음에는 0임). 쓰기 카운터 (Write Counter)는 절대 감소하지 않으므로 재생 쓰기 액세스 (Replayed Write Access)는 거부됩니다. 이렇게 하면 데이터가 최신 상태를 유지할 수 있지만 카운터가 최대값 (32 비트)에 도달하면 모든 쓰기 액세스가 거부되는데, 이때 RPMB는 읽기 전용 스토리지가 됩니다.

소프트웨어 생성 난수 (nonce)는 읽기 액세스에서 재생 방지 (Replay Protection)에 사용되지만, 읽기 액세스에서는 TEE의 소프트웨어가 데이터를 인증하고 확인할 책임이 있으므로 데이터 재생을 방지하기 위해 동일한 난수 또는 허술한 무작위 난수를 사용해서는 안됩니다.

2020년 6월 9일 화요일

파이썬 for문의 다양한 반복 범위 지정 - list 구조체 활용

일반적으로 for문에서 정해진 범위만큼 반복하게 하는 것은 1씩 증가 또는 어떤 간격으로 반복하게 하는 것인데, 파이썬에서는 list 구조체를 활용하여 다양하게 범위를 지정할 수 있네요.

무척 재미있는 프로그래밍 언어인거 같습니다.

아래 소스를 보면 list 구조체 개수만큼 반복합니다.

for num in [0, 7, 5, 2, 10]:
   print (num)


실행시키면 인덱스 0부터 4까지 반복하면서 그 값을 출력하는 간단한 소스입니다.

0
7
5
2
10


list 구조체의 멤버가 문자열인 경우에도 아래와 같이 사용할 수 있습니다.

for s in ['Apple', 'Grape', 'Orange', 'Pepper']:
   print (s)


실행결과를 보면 참 재미있네요

Apple
Grape
Orange
Pepper


list 변수를 사용해도 됩니다. 아래 소스를 실행하면

s = ['Apple', 'Grape', 'Orange', 'Pepper']

for s in s:
   print (s)


아래와 같이 나옵니다.

Apple
Grape
Orange
Pepper


그리고 문자열은 문자들이 이어진 것이고 문자들이 모인 list 구조체라 생각할 수 있으므로 아래 소스와 같이 활용할 수 있습니다.

for s in 'Apple':
   print (s)


그러면 문자열내의 문자 하나씩 출력됩니다.

A
p
p
l
e

2020년 6월 5일 금요일

파이썬 list 구조체의 특정 위치의 멤버를 뽑아내기 - pop

list 구조체내의 여러 멤버들중 특정 위치에 있는 멤버만 뽑아내는 방법인데요.

이전의 remove와는 비슷한듯 하지만 조금 다릅니다.

remove는 어떤 값이나 문자열을 가진 멤버를 삭제하는 반면, pop은 인덱스 기준으로 뽑아냅니다.

그러면서 해당 인덱스에 있던 멤버의 값이나 문자열을 리턴시킵니다.

아래 소스가 그 예입니다.

list1 = [1, 5, 3, 9, 5]
print ("원래 list1 : ", list1)

print ("인덱스 3을 pop : ", list1.pop(3))
print ("pop 실행후 list1 : ", list1)


인덱스 3인 위치의 멤버 pop하면 해당되는 멤버의 값인 '9'가 리턴되고, list1은 마치 remove한 결과를 보여줍니다.

아래에 실행 결과가 있습니다.

원래 list1 :  [1, 5, 3, 9, 5]
인덱스 3을 pop :  9
pop 실행후 list1 :  [1, 5, 3, 5]

2020년 6월 4일 목요일

파이썬 list 구조체내의 특정 값을 가진 멤버의 위치 찾기 - index

list 구조체내에 특정 값을 가진 멤버의 위치를 찾는 방법입니다.

참고로 같은 값이 여러 개일때, 제일 빠른 위치의 멤버의 값을 비교하여 찾아 줍니다.

아래 소스를 보시면,

list1 = [1, 5, 3, 9, 5]
print ("list1 : ", list1)

print ("5의 인덱스는 : ", list1.index(5))
print ("5의 인덱스는 : ", list1.index(5))


5가 2개가 있어 위치를 찾아보면 항상 첫번째 위치만 나옴을 알 수 있습니다.

list1 :  [1, 5, 3, 9, 5]
5의 인덱스는 :  1
5의 인덱스는 :  1

2020년 6월 3일 수요일

파이썬 list 구조체내의 원소들을 거꾸로 뒤집기 - reverse


이전 포스트에서 이야기한 list 구조체 정렬시키는데 사용하는 sort는 알파벳 또는 가나다 순으로 순방향 또는 역방향으로 정렬시킬 수 있는데, 여기서 이야기하는 reverse는 그거와는 다른 역순으로 뒤집는 것인데요.

sort와는 달리 말그대로 거꾸로 뒤집는 것이죠.

아래 소스와 실행 결과를 보시면 이해가실 것입니다.

list1 = [1, 5, 3, 9, 5]
print ("원래 list1 : ", list1)

list1.reverse()
print ("거꾸로 뒤집힌 list1 : ", list1)

이 소스를 실행하면

원래 list1 :  [1, 5, 3, 9, 5]
거꾸로 뒤집힌 list1 :  [5, 9, 3, 5, 1]


2020년 6월 2일 화요일

파이썬 list 구조체의 모든 항목을 지우기 - clear 및 기타 방법

파이썬의 list 구조체의 항목수가 적을때는 하나씩 삭제해도 그다지 힘들지 않을텐데, 만약 그 항목수가 많으면 이 방법으로는 힘들겠죠?

clear를 사용하면 쉽게 할 수 있습니다.

list1 = [1, 5, 3, 9, 5]
print ("원래 list1 : ", list1)

list1.clear()
print ("모두 삭제된 list1 : ", list1)


이렇게 하면 한번에 모두 삭제 가능합니다. 아래 실행결과가 있습니다.

원래 list1 :  [1, 5, 3, 9, 5]
모두 삭제된 list1 :  []


그런데 clear를 사용하지 않고도 모두 삭제할 수 있는 방법도 있습니다. 바로 인덱스 범위를 지정해서 del을 사용해도 됩니다.

list1 = [1, 5, 3, 9, 5]
print ("원래 list1 : ", list1)


del list1[0:5]
print ("모두 삭제된 list1 : ", list1)


실행결과는 아래와 같습니다.

원래 list1 :  [1, 5, 3, 9, 5]
모두 삭제된 list1 :  []

그런데 만약 list 구조체의 항목수를 정확히 모르면 (프로그램 실행중에 추가 및 삭제 등이 빈번해서), 정확한 인덱스를 모르겠죠? 그러면 아래와 같이 하면 됩니다. 물론 list 구조체의 크기를 알아내는 방법이 있기는 하겠죠.

list1 = [1, 5, 3, 9, 5]
print ("원래 list1 : ", list1)

del list1[:]
print ("모두 삭제된 list1 : ", list1)


역시 마찬가지로 아래와 같이 동일한 실행결과를 볼 수 있습니다.


원래 list1 :  [1, 5, 3, 9, 5]
모두 삭제된 list1 :  []