EYEN
DIVA 1단계 본문
#0. 학습 목표
가. 코드 해석을 빠르게 하도록 디바의 코드 한 줄 한 줄이 무슨 의미인지 알기.
나. 나중에 비슷한 코드를 봤을 때 취약점인 줄 알도록 취약점 있는 코드와 취약점 원인인 라인알기, 보호기법이 씌워진 코드와 비교하기
#1 문제 분석
가. 목적
뭐가 어디에서 어떻게 로그되고 있는지 알기
나. 활용
소스코드, adb
#2 취약점 정보
가. 원인
개발자의 민감 정보 로깅
나. 취약점
adb logcat 했을 때 사용자가 입력한 credential 정보나 카드 번호나 민감개인정보가 로그로 나올 것이다.
다. 로그에 민감정보가 출력되는 게 취약점인 이유
1. 네트워크 트래픽을 가로채는 중간자 공격으로 데이터베이스,시스템까지의 권한을 갖지 않아도 민감정보에 접근가능하게 됨.
2. 시스템에 대한 액세스를 획득하면 로그 파일에 접근 가능
라. 보통 로그에 출력하는 정보
1. 어떤 스레드에서 받아온 요청인지
2. 어떤 메서드를 수행중인지
3. 응답 시간
4. 어떠한 요청 및 응답값을 보내주는지=> 원인
로그 클래스와 함수: log.isInfoEnabled log.info
#3 코드 분석
java 코드이다.
1.
package jakhar.aseem.diva;
내부 패키지 선언
2.
import android.os.Bundle;
패키지 android.os 는 안드로이드 운영체제의 핵심 기능을 지원하는 클래스들을 포함한다.
클래스 Bundle은 키-값 쌍 형태로 데이터를 저장할 수 있어 액티비티 간에 데이터를 전달하는 데 사용된다.
사용: Intent에 부가적인 데이터를 넣어 다음 액티비티로 전달하거나, 액티비티의 상태를 저장하고 복원하는 데 사용된다.
3.
import android.support.v7.app.AppCompatActivity;
클래스 AppcompatActivity는 안드로이드 Support 라이브러리의 일부로 이전 버전과의 호환성을 보장한다.
이전 버전의 안드로이드에서도 새로운 기능을 사용할 수 있게 해줌
Activity 클래스를 확장한 것으로, 안드로이드 앱의 화면을 관리하고 사용자 상호작용을 처리하는 데 사용
4.
import android.util.Log;
안드로이드 앱을 개발할 때 디버깅 및 로깅을 위해 사용되는 클래스를 가져오는 것.
Log 클래스는 안드로이드의 로깅 시스템을 사용하여 메세지를 기록하고 출력하는 데 사용된다.
Log 클래스는 다양한 로그 레벨에 대해 메시지를 기록할 수 있다.
Log.v(String tag, String msg) : VERBOSE 레벨의 로그를 출력, 가장 상세한 로그레벨
Log.d(String tag, String msg) : DEBUG 레벨의 로그를 출력, 개발 중 디버깅을 위해 사용
Log.i(String tag, String msg) : INFO 레벨의 로그를 출력, 앱의 상태나 정보를 기록할 때 사용
Log.w(String tag, String msg) : WARN 레벨의 로그를 출력, 경고성 메시지를 기록할 때 사용
Log.e(String tag, String msg) : ERROR 레벨의 로그를 출력, 오류를 기록할 때 사용
5.
import android.view.View;
클래스 View는 안드로이드 UI 구성 요소의 기본 클래스
버튼, 텍스트뷰, 이미지뷰 등 모든 사용자 인터페이스 요소는 이 클래스를 상속받음
View 클래스는 다양한 UI 이벤트를 처리하고, 사용자 상호작용을 감지하고, 레이아웃을 구성하며, 화면에 그래픽을 그리는 등의 기능을 제공
6.
import android.widget.EditText;
클래스 EditText는 사용자가 텍스트를 입력할 수 있는 편집 가능한 텍스트 상자를 나타냄
EditText는 View클래스를 상속받아 입력된 텍스트를 가져오거나 무언가로 설정하는 메서드, 입력 가능한 텍스트의 모양과 동작을 조정하는 속성 등을 제공한다.
7.
import android.widget.Toast;
Toast: 사용자에게 잠시동안 메시지를 표시하고 사라지는 알림창
이미지도 표시가능
8.
public class LogActivity extends AppCompatActivity {
이전 버전의 안드로이드와 호환하는 AppCompatActivity를 상속받는 클래스 LogActivity 정의
9.
public void onCreate(Bundle savedInstanceState)
onCreate() 메서드는 안드로이드 액티비티의 생명 주기 메서드 중 하나, 액티비티가 생성될 때 호출된다.
이 메서드는 파라미터로 객체 Bundle savedInstaceState를 받는다. 이 객체는 액티비티의 이전 상태를 포함하고 있다. 디바이스가 회전되면 액티비티가 파괴되고 다시 생성되는데, 이때 이전 상태를 저장하고 있는 Bundle 객체를 전달받아 활용하는 것.
그렇게 생성된 액티비티 onCreate는 밑에서 사용된다.
10.
super.onCreate(savedInstanceState);
부모 클래스 AppCompatActivity의 onCreate()메서드를 호출하는 코드
메서드를 호출하는 이유는 부모 클래스에서 수행되어야 하는 초기화 작업이나 기본 동작을 실행하기 위함
안드로이드 액티비티의 경우, onCreate() 메서드에서는 액티비티의 레이아웃을 설정하고 초기화하는 등의 작업이 수행되므로, 이를 부모 클래스에서 먼저 수행하도록 호출한다.
자식 클래스인 LogActivity에서 onCreate()메서드를 오버라이딩하면 올바르게 동작하지 않을 수 있다.
11.
setContentView(R.layout.activity_log);
현재 액티비티에 표시할 레이아웃을 설정하는 코드.
R.layout.activity_log는 레이아웃 파일의 리소스 식별자이다.
안드로이드 앱에서 UI는 XML 파일로 정의된다. R.layout.activity_log는 액티비티의 레이아웃을 정의한 XML 파일을 가리킨다.
setContentView() 메서드는 액티비티의 화면에 표시할 레이아웃을 설정하는 역할을 한다.
이 메서드를 호출하면 시스템은 해당 XML 파일을 읽어 액티비티의 화면에 표시한다.
activity_log.xml 파일에는 텍스트뷰, 버튼 등의 UI 요소가 정의되어 있다.
12.
public void checkout(View view) {
버튼이나 다른 뷰를 클릭했을 때 호출되는 이벤트 핸들러 메서드
View는 클릭된 뷰, 이게 view 파라미터로 전달된다.
그래서 이 메서드 내에서는 클릭된 뷰에 대한 작업을 수행한다.
13.
EditText cctxt = (EditText) findViewById(R.id.ccText);
액티비티나 프래그먼트에서 XML 레이아웃 파일에서 정의한 EditText 요소를 참조하는 코드
EditText cctxt: cctxt라는 텍스트입력칸 객체를 참조하는 변수 선언
findViewByid: XML 레이아웃에서 ccText라는 id를 가진 뷰를 찾아
(EditText): EditText 클래스로 형변환(굳이? EditText 클래스의 인스턴스임을 보장하기 위함)
14.
try { processCC(cctxt.getText().toString());
cctxt라는 EditText에서 getText() 메서드를 호출하여 사용자가 입력한 텍스트를 가져온다.
이때 CharSequence 형식으로 반환되어 toString 메서드를 통해 String으로 변환한다.
그러면 이 cctxt는 사용자가 입력한 텍스트를 나타내는 문자열이 된다.
processCC는 외부에 정의된 메서드로 cctxt를 처리한다.
15.
catch (RuntimeException e) {
RuntimeException이라는 예외 객체를 e라는 변수에 할당한다.
16.
Log.e("diva-log", "Error while processing transaction with credit card: " + cctxt.getText().toString());
클래스 Log의 우선 순위 e(error)
diva-log: 로그 메시지의 태그, 로그를 구분하는 데 사용되어, 태그를 지정함으로써 로그를 필터링하거나 구분할 수 있다.
17.
Toast.makeText(this, "An error occured. Please try again later", 0).show();
this: Context를 나타냄. 이 코드가 실행되는 컨텍스트에 따라 Toast가 표시되는 화면이 달라진다.
0: Toast의 지속 시간
.show(): Toast 객체를 화면에 표시하는 메서드, 이 메서드를 호출하지 않으면 Toast가 나타나지 않는다.
18.
private void processCC(String ccstr) {
private: 동일한 클래스 내에서만 접근 가능한 메서드
void: 메서드가 반환하는 값의 타입
String ccstr: 메서드의 파라미터
19.
RuntimeException e = new RuntimeException();
예외 발생시 RuntimeException 객체 생성하여 변수 e에 할당
20.
throw e;
개발자가 의도한대로 통과하지 못했을 때 일부러 예외를 발생시켜 메서드를 사용한 곳에서 예외처리를 하도록 다른 곳으로 던지는 역할
#4 취약점 예방
1. 로그 필터링
public class LogUtils {
public static void logSensitiveInfo(String sensitiveInfo) {
if (!isSensitive(sensitiveInfo)) {
// 민감하지 않은 정보는 로그에 기록
Log.d("AppTag", "Non-sensitive information: " + sensitiveInfo);
}
}
private static boolean isSensitive(String info) {
if (info.matches("\\b\\d{4}-\\d{4}-\\d{4}-\\d{4}\\b")) {
// 신용카드 번호인 경우
return true;
} else if (info.matches("\\b\\d{3}-\\d{2}-\\d{4}\\b")) {
// 소셜 보안 번호 (SSN)인 경우
return true;
} else if (info.contains("password") || info.contains("passwd")) {
// 비밀번호 관련 정보인 경우
return true;
} else {
return false;
}
}
}
2. 로그 암호화
public void logSensitiveInfo(String sensitiveInfo) {
String encryptedInfo = encrypt(sensitiveInfo);
Log.d("AppTag", "Encrypted sensitive information: " + encryptedInfo);
}
private String encrypt(String info) {
return Base64.encodeToString(info.getBytes(), Base64.DEFAULT);
}
3. 로그 마스킹
민감 정보를 ***로 뜨도록 마스킹
public void logSensitiveInfo(String sensitiveInfo) {
// 로그에 민감한 정보를 기록하기 전에 마스킹 처리합니다.
String maskedInfo = maskSensitiveInfo(sensitiveInfo);
// 마스킹된 정보를 로그에 출력합니다.
Log.d("AppTag", "Sensitive information: " + maskedInfo);
}
private String maskSensitiveInfo(String sensitiveInfo) {
// 민감한 정보를 마스킹하여 반환합니다.
// 여기서는 신용카드 번호를 마스킹하는 예시를 보여줍니다.
int visibleLength = 4; // 마스킹되지 않고 표시될 문자열 길이
int length = sensitiveInfo.length();
if (length <= visibleLength) {
// 민감한 정보가 너무 짧을 경우, 전체를 마스킹합니다.
return "****";
} else {
// 민감한 정보가 길 경우, 마지막 네 글자를 제외하고 마스킹합니다.
String visiblePart = sensitiveInfo.substring(0, length - visibleLength);
String maskedPart = sensitiveInfo.substring(length - visibleLength);
String maskedInfo = visiblePart.replaceAll(".", "*") + maskedPart;
return maskedInfo;
}
}
4. 로그 레벨 설정
민감 정보를 포함한 로그를 출력되지 않는 특정 로그 레벨로 설정
보통 설정된 로그레벨보다 우선 순위가 낮은 로그는 출력되지 않는다.
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
XML을 이렇게 설정하면 INFO 이상의 로그만 출력한다. 디버그레벨은 출력하지 않는다.