본문 바로가기
FE Development/React-Native

React Native 세션 타임아웃 (session timeout) 설정

by 개발자 데이빗 2021. 10. 7.

앱 보안 진단 결과 취약점 중 세션 타임아웃 미설정이 있어 세션 타임아웃을 구현하였다.

 

취약점

일정시간이 지난 후 사이트에 재 접속 하였을 때 로그인 상태가 유지되거나 동일 세션 ID가 생성되는 경우 취약할 수 있다.

공격자가 다른 취약점을 통해 획득한 세션 ID를 브라우저에 적용하여 재 로그인 될 때를 기다리다가 해당 권한으로 접근이 될 수 있다.

또한 로그인 후 세션을 종료하지 않고 자리를 비우는 동안 악의적인 사용자가 접속된 터미널을 이용하여 불법적인 행위를 시도할 수 있다.

 

 

설정 방법

react-native의 AppState를 사용하여 구현

앱이 백그라운드로 전환된 후 30분 이상 경과 후 앱 복귀 시 로그아웃 처리 하였다.

 

  useEffect(() => {
    const handleAppStateChange = async (nextAppState) => {
      const fromBackground =
          appState.current.match(/inactive|background/) &&
          nextAppState === "active";
      const fromForeground = Platform.OS === 'android' ? (
            appState.current.match(/active|foreground/) &&
            nextAppState === "background"
          ) : (
          appState.current.match(/active|foreground/) &&
          nextAppState === "inactive"
      );
      if (fromBackground) {
        const comeBackTime = new Date().toString();
        const sessionTimeOut = await AsyncStorage.getItem('AppStateTimeStamp');
        // 앱이 background로 전환된지 30분 이상 경과 후 앱 복귀 시 로그아웃 처리
        if(comeBackTime > sessionTimeOut) {
        	if(session){
            	signOut()
            }
          });
        }
      }
      if (fromForeground) {
          // 앱이 background로 전환될때 asyncStorage에 30분후 시간 저장
          const time = new Date();
          time.setTime(time.getTime() + 1000 * 1800);
          await AsyncStorage.setItem("AppStateTimeStamp", time.toString());
      }

      appState.current = nextAppState;
      console.log("AppState", appState.current);
    }
    AppState.addEventListener("change", handleAppStateChange);
    return () => {
      AppState.removeEventListener("change", handleAppStateChange);
    }
  },[])

 

구현시 주의할 점

Date 객체

Date 객체의 시간을 변경하는 메소드를 사용하여 새로운 변수에 할당할 수 없다.

const time = new Date('2021-10-06');
const _30minuteLater = time.setTime(time.getTime() + 1000 * 1800);
console.log(_30minuteLater); // 1633480200000
console.log(time); // 2021-10-06T00:30:00.000Z
console.log(time.toString()); // Wed Oct 06 2021 09:30:00 GMT+0900 (Korean Standard Time)

AsyncStorage

AsyncStorage에는 string 값을 저장하여야 하기 때문에 변환된 time.toString()으로 저장하여야 한다.

또한 포그라운드로 전환될 때 AsyncStorage로부터 가져온 time 값은 string 값이기 때문에 비교를 위한 현재 시간 또한 string으로 변환하여 비교한다.

아래와 같이 string으로 변환한 값을 비교하여도 간단하게 비교할 수 있었다.

const _30minuteLater = new Date()
_30minuteLater.setTime(_30minuteLater.getTime() + 1000 * 1800);
const _30minuteBefore = new Date()
_30minuteBefore.setTime(_30minuteBefore.getTime() - 1000 * 1800);
const now = new Date().toString();
console.log( now < _30minuteLater.toString()); // true
console.log( now < _30minuteBefore.toString()); // false

백그라운드 -> 포그라운드 상황에서는 안드로이드와 ios에서의 동작이 다르지 않지만 

포그라운드 -> 백그라운드 상황에서 안드로이드는 nextAppState로 inactive를 받아오지 않는다.

 

nextAppState

ios에서는 inactive -> background 순서로 받아오게 되어 플랫폼별로 분기처리를 하지 않으면 ios에서는 두번 동작하게 되므로 분기처리를 하여 정상적으로 작동하게 한다.

// ios에서는 inactive, background 두번 동작하게 된다.
const fromForeground =
  appState.current.match(/active|foreground/) &&
  nextAppState === "background" || "inactive";

// android, ios 분리
const fromForeground = Platform.OS === 'android' ? (
  appState.current.match(/active|foreground/) &&
  nextAppState === "background"
  ) : (
  appState.current.match(/active|foreground/) &&
  nextAppState === "inactive"
  );

 

댓글