Fall in IT.

GraphQL 보안과 성능 개선 방법 본문

기타

GraphQL 보안과 성능 개선 방법

D.Y 2022. 10. 27. 15:04

안녕하세요.

오늘은 GraphQL 보안과 성능 개선 방법에 대해서 알아보겠습니다.

 

GraphQL 보안과 성능 개선 방법

  • 타임아웃 설정
  • 데이터 개수 제한
  • 쿼리 깊이 제한
  • 쿼리 복잡도 제한
  • Filed Collection

GraphQL로 서버를 만들경우 클라이언트쪽 구현에 더 많은 자유도와 유연성을 부여할 수 있습니다.

여러개의 데이터를 조회할때도 한번의 쿼리로 조회(UnderFetching 해결)가 가능하고, 원하는 필드만 조회할 수 있습니다. (OverFetching 해결)

 

그러나, 자유도가 높은 만큼 한번의 쿼리에 너무 많은 데이터를 요청하여 문제가 발생할 수 있습니다.

한번에 너무 많은 데이터를 요청할 경우 서버 성능이 떨어질 뿐만 아니라 서비스가 다운 될 수 있습니다. 이런 경우를 대비해서 GraphQL 서비스의 보안과 성능을 개선할 수 있는 방법을 알아보겠습니다.

 

타임아웃 설정

각각의 요청에 처리하는 시간을 제한하는 방법입니다.

 

악성 혹은 대량의 쿼리가 들어올 경우를 대비해 타임아웃 시간을 설정해두고 일정시간 이상 걸리는 쿼리는 에러를 던지도록 처리하여 서버의 상태를 유지할 수 있습니다.

 

서버로 들어오는 모든 요청에 타임아웃을 설정할 수도 있고, 리졸버에 개별적으로 설정할 수도 있습니다.

 

데이터 개수 제한

쿼리가 반환하는 개수를 제한하는 방법입니다.

 

페이지네이션 처리를 할 경우 한 페이지에 가져올 데이터의 수(ex. first: 50)를 설정할 수 있는데, 이 숫자의 최대값을 지정해두는 방식입니다.

input으로 들어오는 인자값의 설정값의 제한만 걸어두면 되므로 간단하게 설정할 수 있습니다.

 

쿼리 깊이 제한

GraphQL은 관계된 데이터들을 타고들어가면서 조회가 가능한데, 제한이 없을 경우 무한히 조회할 수도 있습니다.

 

예를들면, User와 Post의 관계에서 하나의 포스트에는 올린 유저의 정보가 있고 유저의 정보에는 올린 포스트들이 있고 포스트들 안에는 태그된 유저들의 정보가 있고.. 이런식으로 매우 깊이가 깊은 복잡한 쿼리가 생성될 수 있습니다.

특히, 배열 형태의 오브젝트가 쿼리되는 경우 데이터의 양은 기하급수적으로 증가하게 됩니다.

query getPhoto($id: ID!) {
	Photo(id: $id) { // 1 depth
		name
		url
		...(생략)...
		postedBy { // 2 depth
			name
			age
			...(생략)...
			postedPhotos { // 3 depth
				name
				url
				...(생략)...
				taggedUsers { // 4 depth
					name
					age
					...(생략)...
				}
			}
		}
	}
}

이런 경우를 대비해서 쿼리 깊이의 제한을 설정할 수 있습니다.

만약, 깊이 제한(depth limit)을 3으로 설정할 경우 위와 같은 쿼리가 발생했을때 서버는 쿼리 실행을 중단하고 에러를 반환하여 서버의 안정성을 높여줍니다.

 

쿼리 복잡도 제한

쿼리 복잡도를 측정하여 설정한 복잡도를 넘어설 경우 에러를 반환하는 방법입니다.

 

쿼리의 깊이가 깊지 않더라도 쿼리에 포함된 필드가 많고 연산 비용이 높은 필드가 있을 경우 쿼리 복잡도는 높아질 수 있습니다.

쿼리 복잡도는 각 필드에 복잡도(weight) 값을 매겨 놓고 복잡도 값의 전체 합을 계산합니다. 쿼리 복잡도를 매길 때 수행 비용이 높은 리졸버가 있다면 해당하는 필드에 높은 복잡도 값을 매기면 됩니다.

 

Filed Collection

Field Collection은 클라이언트 측에서 요청한 필드를 확인하고 원하는 필드에 대한 정보만 조회할 수 있도록 하는 기능입니다.

 

GraphQL은 클라이언트 측에서 원하는 필드만 조회해서 사용할 수 있는 장점이 있습니다. 서버 또한 하나의 endpoint만 만들어두면 되기 때문에 개발 효율이 높아지게 됩니다.

 

그러나, 문제는 클라이언트 측에서 요청하지 않은 필드값을 만들기위해 연산비용이 높은 로직도 매번 동작한다는 사실입니다.

이를 해결하기 위해서 field collection을 사용하여 클라이언트 측에서 요청한 필드를 확인하고 연산이 높은 필드를 요청하지 않았다면 해당 연산은 제외하도록 코드를 작성하여 성능을 높일 수 있습니다.

 

참조

 

 

 

 

Comments