Unity 멀티플레이어는 암호화 플러그인을 사용할 수 있으므로 네트워크를 통해 전송하는 모든 데이터는 전송되기 전에 암호화 플러그인을 거칩니다. 따라서 패킷 조작 또는 전용 게임 서버 공격을 통한 부정 행위로부터 게임을 보호할 수 있습니다.
Unity 멀티플레이어에는 빌트인 암호화 플러그인이 없으므로 암호화 알고리즘을 구현하고 아래에 나열된 필수 함수를 구현하는 자체 플러그인을 제공해야 합니다.
다음 다이어그램은 Unity 멀티플레이어가 암호화 플러그인(제공하는 경우)을 사용하는 방식을 보여줍니다.
게임이나 앱에 암호화 플러그인을 사용하도록 명령하려면 UnityEngine.Networking.NetworkTransport.LoadEncryptionLibrary(path)
를 호출해야 합니다. 여기에서 path
는 컴파일된 플러그인의 경로입니다. Windows에서는 대개 string.Format("{0}/Plugins/UnetEncryption.dll", Application.dataPath)
입니다.
이 함수를 호출하면 Unity는 파일이 존재하는지 확인하고 아래에 나열된 모든 필수 함수를 구현합니다. 이러한 함수들은 Unity의 멀티플레이어 시스템 자체에서 호출됩니다. 자체 암호화 플러그인을 생성하는 경우 C# 코드에서 호출하는 함수를 추가해야 합니다. 예를 들어 알고리즘을 초기화하거나 플러그인에 키 값을 제공할 수 있습니다. 이러한 작업은 C#에서 호출할 수 있는 네이티브 플러그인에 대한 일반적인 방식에서 수행할 수 있습니다.
참고 : 빌드된 게임 버전에서 플러그인 위치는 Assets 폴더와 같을 필요는 없으며 타겟 플랫폼마다 다를 수 있습니다. 현재 런타임 환경을 감지하는 코드를 작성하고 이를 기반으로 올바른 경로를 선택해야 합니다.
샘플 암호화 플러그인과 이를 사용하는 샘플 Unity 프로젝트는 Unity의 GitHub에서 얻을 수 있습니다. 이 샘플들은 자체 플러그인을 만들기 위한 시작점으로 활용할 수 있습니다.
생성하거나 사용하는 모든 암호화 플러그인은 다음 함수를 제공해야 합니다. 플러그인이 이러한 함수를 정의하지 않으면 Unity가 플러그인을 로드할 수 없습니다. 이러한 함수들은 Unity 런타임 자체에서 호출됩니다. 플러그인은 일반적으로 키 등록과 같이 사용자의 C# 코드에서 호출되는 additional 함수를 제공합니다.
int UNetEncryptionLib_Encrypt(
void * payload,
int payload_len,
void * dest,
int & dest_len,
int connection_id,
bool isConnect);
이 함수는 암호화를 수행합니다. 패킷이 네트워크를 통해 전송될 때마다 이 함수가 Unity 네트워킹에서 호출됩니다.
Encrypt
는 성공 시 0을 반환해야 합니다. 0이 아닌 다른 값을 반환하면 런타임은 패킷을 전송하지 않고 삭제합니다.
int UNetEncryptionLib_Decrypt(
void * payload,
int payload_len,
void * dest,
int & dest_len,
int & key_id);
이 함수는 암호화 해제를 수행합니다. 패킷이 네트워크에서 수신될 때마다 이 함수가 Unity 네트워킹에서 호출됩니다.
payload
는 수신된 패킷입니다.payload_len
는 payload 버퍼의 길이(바이트)입니다.dest
는 플러그인이 암호화 해제된 데이터를 작성해야 하는 버퍼입니다.dest_len
은 dest 버퍼의 용량(바이트)입니다. 플러그인은 이 값을 dest에 실제로 작성된 바이트 수로 교체해야 합니다.key_id
는 정수 식별자입니다. 플러그인은 사용된 암호화 해제 키를 고유하게 식별하는 값을 작성해야 합니다. 새 연결이 승인되면 서버에서 이 값은 ConnectionIdAssigned
로 다시 전달됩니다.Decrypt
는 성공 시 0을 반환해야 합니다. 0이 아닌 다른 값을 반환하면 패킷은 더 이상 처리되지 않고 삭제됩니다.
unsigned short UNetEncryptionLib_SafeMaxPacketSize(
unsigned short mtu);
NetworkTransport.AddHost
를 호출하기 전에 게임에서 이 함수를 호출하여 ConnectionConfig.PacketSize
(maximum transmission unit 또는 MTU라고도 불림)를 수정해야 합니다.
예를 들어 게임은 일반적으로 1000바이트의 MTU를 사용할 수 있습니다. HostConfig.DefaultConfig
를 통해 NetworkTransport.AddHost
로 전달하기 전에 ConnectionConfig.PacketSize
를 1000 바이트로 설정하면 NetworkTransport 레이어는 단일 패킷으로 1000 바이트 이하의 평문을 전송합니다.
암호화 플러그인은 일반적으로 payload 앞에 배치된 헤더 정보와 payload를 암호화 블록 크기로 반올림하는 작업으로 인해 약간의 성능 부하를 추가합니다. 예를 들어 18바이트의 평문을 전송하고, 플러그인이 49바이트의 헤더를 추가하고, AES를 사용하여 블록 크기가 16바이트인 데이터를 암호화하는 경우 알고리즘은 81바이트의 패킷을 생성합니다(18바이트의 평문은 최대 32바이트의 암호문으로 반올림되고 49바이트의 헤더가 추가됨).
Unity는 이 함수를 호출하여 전송하려는 패킷이 전송 가능한 한도를 초과하지 않도록 하며, 이때 네트워크 MTU와 암호화 알고리즘의 암호문 확장 및 패딩을 고려합니다.
mtu
는 최대 전송 단위입니다. 즉 플러그인이 생성할 최대 패킷 크기입니다.플러그인이 MTU보다 크지 않은 패킷을 생성하기 위해 단일 Encrypt 호출에 제공해야 하는 최대 평문 개수입니다.
Unity 멀티플레이어가 암호화 요구 사항에 맞도록 데이터를 분할하도록 알리려면 연결 구성에서 최대 패킷 크기를 설정해야 합니다. 일부 메시지가 네트워크를 통해 성공적으로 전송되지 않으면 최대 패킷 크기를 초과한 메시지가 삭제되었기 때문일 수 있습니다.
void UNetEncryptionLib_ConnectionIdAssigned(
int key_id,
unsigned short connection_id);
새 연결이 승인되고 ID가 할당되면 서버에서 이 함수가 호출됩니다.
key_id
: 키 식별자입니다. 이 패킷에 대한 이전 Decrypt
호출에 의해 작성되었습니다.connection_id
: 이 시점부터 사용될 연결 ID입니다. 특히, 클라이언트로 패킷을 다시 전송할 때 후속 Encrypt
호출에 대한 파라미터로 사용됩니다.