[SK shieldus Rookies 16기][취약점 진단] HTTP의 개요, 쿠키와 세션, Access Control 실습

Jina·2023년 12월 22일
0

SK shieldus Rookies 16기

목록 보기
45/59
post-thumbnail
post-custom-banner

1. HTTP

1.1. 정의

  • WWW에서 정보를 주고 받을 수 있는 프로토콜
  • 클라이언트-서버 프로토콜

1.2. HTTP 특징

  1. 요청, 응답 구조
    • HTTP는 반드시 요청을 해야 응답을 준다.
  2. Stateless
    • 상태를 유지 하지 않기 때문에 요청과 요청 간의 관계를 알 수 없다.
    • 과거 70년도 에는 연결을 유지할 필요가 없었다. HTTP를 통해 데이터 시점, 서버 성능을 고려했을 때 Stateless가 효율적이었다. 시간이 지남에따라 연결 유지의 필요해졌다. StateFull 하기 위해서 Cookie 가 등장했다.
  3. 확장성
  4. TCP/IP 기반
# WebGoat URL로 HTTP 요청을 보내는 명령어
$ curl -v http://victim:8080/WebGoat

상호 합의 하에 연결을 하고, 4whs을 통해 연결을 종료한다.

# WebGoat URL로 HTTP 요청을 보내는 명령어
$ curl -v http://victim:8080/WebGoat

# WebGoat URL로 HTTP 요청을 보내는 명령어
# Basic 인증을 사용하여 WebGoat 리소스 정보를 요청
$ curl -v http://victim:8080/WebGoat/ -H "Authorization: basic d2ViZ29hdDp3ZWJnb2F0"

1.3. 리다이렉션

1.4. 기본인증(Basic Authenticate)

WWW-Authenticate: Basic realm="WebGoat Application"

  • 인코딩 방식으로 전달
  • 안전하지 않다. 왜? 매번 요청할 때마다 요청방식을 전달해야하기 때문에 ⇒ 안전하기 위해서는 Form 기반으로 전달해야 한다.

  • 정의
    Stateless한 HTTP 프로토콜에서 상태를 유지하기 위해 도입된 개념
  • 단점
    • 요청 헤더와 응답 헤더를 통해 전달되므로 전달 과정에서 탈취 및 도용될 수 있다.
    • 로컬PC 브라우저에 저장되고 JavaScript를 이용해서 쉽게 접근이 가능하므로 쉽게 탈취 및 위조, 변조, 도용될 수 있다.
  • 안전하게 Cookie 운영하는 방법
    • 가급적 중요한 정보는 쿠키에 포함 X
    • 중요한 정보를 쿠키에 포함해야하는 경우 쿠키 암호화
    • 쿠키 유효기간 또는 지속시간최소한으로 설정
    • 쿠키 생성 시 secure 속성 활성화
      • secure 속성이란? 보안 통신을 할 때만 쿠키 전달하도록 제한
    • 쿠키 생성 시 HttpOnly 속성 설정
      • HttpOnly 속성이란? 클라이언트에서 쿠키에 JavaScript나 개발자 도구를 이용해 직접 접근을 제한하는 것
  • 실습
    실습을 위해서 Tomcat v7.0 Server의 context.xml 파일에서 <Context> 태그에 useHttpOnly="false" 를 추가해줘야 한다. HttpOnly 속성이 true면 클라이언트에서 접근 시 " " 만 나온다.

    HttpOnly 속성이 제거(uncheck) 된 것을 확인할 수 있다.

    openeg에서 같은 계정으로 로그인해 각각 크롬와 파이어폭스에서 쿠키 값을 확인해보면 서로 다른 것을 확인할 수 있다. 왜? 각 브라우저는 자체 쿠키 저장소를 갖고 있기 때문에

로그인한 브라우저의 쿠키값을 추출해서 로그인하지 않은 브라우저에 설정 후 새로고침 ⇒ 서버는 세션 ID를 이용해서 사용자를 식별하는데, 세션 ID가 포함되어 있는 쿠키를 탈취 당하게 되면, 서버를 속여서 접근이 가능하게 됨

1.6. Session

  • 정의
    • 쿠키의 단점을 보안하기 위해 나온 개념
    • 중요 정보를 서버의 세션에 저장하고, 사용자에게는 해당 세션에 접근할 수 있는 세션 ID를 발급
  • 단점
    • 중요 정보에 대한 직접적인 유출은 막을 수 있으나, 중요 정보 접근에 사용되는 세션 ID 발급 및 관리가 중요해진다.
  • 발생할 수 있는 문제점
    • 세션 ID 고정 : 인증 전후에 동일한 세션 ID를 사용하는 경우 발생
    • 세션 ID 훔치기 : 세션 ID가 요청, 응답을 통해서 전달되는 과정 또는 사용자 PC, 브라우저에 저장된 것을 탈취, 조작할 수 있을 때 발생
    • 세션 ID 추측 : 세션 ID의 생성 규칙을 유추할 수 있는 경우 발생
      1. 공격자가 다음에 생성될 세션 ID를 미리 설정
      2. 불특정 다수의 희생자에게 동일한 세션 ID가 발급되기를 대기
      3. 동일한 세션 ID를 발급받은 희생자가 생기면 공격자는 희생자의 권한으로 사이트 이용
    ⇒ 세션 ID를 발급, 관리를 잘못한 경우

실습문제1 - Stage 1

WebGoat > Access Control Flaws > LAB:Role Based Access Control

1. 목표

Employee Tom으로 Staff Listing Page에서 Tom의 프로필 삭제하기

2. 로그인해서 소속에 따른 페이지 확인하기

Tom(pw : tom) 로그인한 경우

Jerry(pw: jerry) 로그인한 경우

3. Jerry 로그인 상태에서 DeleteProfile 해보기

4. Tom 로그인 상태에서 Tom 프로필 삭제하기

ViewProfile > Tom employee_id=106 확인

SearchStaff 클릭 후 패킷 Intercept

employee_id, action을 변경

5. 성공하면 Stage 2: Add Business Layer Access Control 로 이동

실습문제2 - Stage 2

1. 목적

요청한 사용자의 권한 여부를 체크하는 로직을 추가하기

2. 소스 코드 분석

RoleBasedAccessContol.java

public void handleRequest(WebSession s)
	{
		// Here is where dispatching to the various action handlers happens.
		// It would be a good place verify authorization to use an action.

		// System.out.println("RoleBasedAccessControl.handleRequest()");
		if (s.getLessonSession(this) == null) s.openLessonSession(this);

		String requestedActionName = null;
		try
		{
			// action 요청 파라미터 값을 추출
            requestedActionName = s.getParser().getStringParameter("action");
		} catch (ParameterNotFoundException pnfe)
		{
			// Let them eat login page.
			requestedActionName = LOGIN_ACTION;
		}
		// System.out.println("Requested lesson action: " + requestedActionName);

		try
		{
			DefaultLessonAction action = (DefaultLessonAction) getAction(requestedActionName);
			if (action != null)
			{
				// System.out.println("RoleBasedAccessControl.handleRequest() dispatching to: " +
				// action.getActionName());
				if (!action.requiresAuthentication())
				{
					// Access to Login does not require authentication.
					action.handleRequest(s);
				}
				else
				{
					// ***************CODE HERE*************************
					
					// *************************************************
					// 인증 여부 확인
                    if (action.isAuthenticated(s))
					{
						// 요청 처리
                        action.handleRequest(s);
					}
					else
						// 인증 오류 반환
                        throw new UnauthenticatedException();
				}
			}
           
           ...(생략)...

요청한 사용자의 권한 여부를 확인하지 않고, 인증 여부만 확인하고 요청을 처리하고 있다는 것을 확인할 수 있다.

3. 요청한 사용자의 권한 여부를 체크하는 로직을 추가하기

//
public void handleRequest(WebSession s)
	{
		// Here is where dispatching to the various action handlers happens.
		// It would be a good place verify authorization to use an action.

		// System.out.println("RoleBasedAccessControl.handleRequest()");
		if (s.getLessonSession(this) == null) s.openLessonSession(this);

		String requestedActionName = null;
		try
		{
			requestedActionName = s.getParser().getStringParameter("action");
		} catch (ParameterNotFoundException pnfe)
		{
			// Let them eat login page.
			requestedActionName = LOGIN_ACTION;
		}
		// System.out.println("Requested lesson action: " + requestedActionName);

		try
		{
			DefaultLessonAction action = (DefaultLessonAction) getAction(requestedActionName);
			if (action != null)
			{
				// System.out.println("RoleBasedAccessControl.handleRequest() dispatching to: " +
				// action.getActionName());
				if (!action.requiresAuthentication())
				{
					// Access to Login does not require authentication.
					action.handleRequest(s);
				}
				else
				{
					// ***************CODE HERE*************************

					// *************************************************
					/* 기존 코드 주석처리
					if (action.isAuthenticated(s))
					{
						action.handleRequest(s);
					}
					else
						throw new UnauthenticatedException();
					*/
					// ********************추가*******************
					// 요청 사용자의 인증 여부를 확인
					if (action.isAuthenticated(s)) {
						// 요청 사용자의 요청 권한 여부를 확인
						// isAuthorized(WebSession s, int employeeId, String functionId)
						if (action.isAuthorized(s, action.getUserId(s), action.getActionName())) {
							action.handleRequest(s);
						} else {
							// 권한 오류
							throw new UnauthorizedException();
						}
					} else {
						// 인증 오류
						throw new UnauthenticatedException();
					}
				}
			}
			else
				setCurrentAction(s, ERROR_ACTION);
						// ****************************************

4. 결과 확인

코드 수정 후 Stage 2에서 Stage 1과 동일하게 실습 진행 시 DeleteProfile 요청이 처리되지 않는 것을 확인할 수 있다.

실습문제3 - Stage 3

1. 목적

Tom으로 다른 직원의 프로필 조회하기

2. Tom으로 로그인한 상태로 ViewProfile 패킷 확인

3. employee_id를 Jerry의 id로 변경 후 결과 확인

Stage 4로 이동되어야 한다.

실습문제4 - Stage 4

예상 쿼리

SELECT * FROM employee WHERE employee_id=사원번호
  • 목록 조회 : 비슷한(동일) 유형의 데이터(레코드)가 나열되는 형식
  • 상세 조회 : 하나의 데이터(레코드)의 구성요소가 출력되는 형식
  • 목록 데이터에서 해당 레코드를 유일하게 식별할 수 있는 값 = 유일 키

😨 유일키만으로 데이터를 조회하는 경우 파라미터를 조작하면 목록에 나오지 않는 데이터의 열람이 가능해진다.

그렇기 때문에 목록 조회 기능을 구현할 때는 다양한 조건절을 추가해야한다.

  • 검색어
  • 정책 (예: del_yn 컬럼의 값이 'Y'인 데이터는 조회에서 제외)
  • 권한 (예: 로그인한 사용자와 동일한 전공인 학생만 조회하도록 제한)

상세 조회 기능 구현 시 목록 조회에서 적용한 조건레코드를 선택하기 위한 조건을 함께 사용해야 한다.

1. 목적

기존에는 hr 소속이 아니었어도 employee_id만 변경하면 프로필 조회가 가능했었다.

hr 소속이 아니면 프로필 조회를 못하게 소스코드 변경하기

2. 소스코드 확인

WebGoat/src/main/java/org/owasp/webgoat/lessons/RoleBasedAccessControl/ViewProfile.java

ViewProfile.java

현재 로그인한 직원 ID와 조회 대상 직원 ID를 확인하는 코드로 변경

3. 결과 확인

profile
공부 기록
post-custom-banner

0개의 댓글