보안 전략 및 속임수 방지

*이 콘텐츠는 AI(베타)를 사용해 번역되었으며, 오류가 있을 수 있습니다. 이 페이지를 영어로 보려면 여기를 클릭하세요.

Roblox는 클라이언트가 컨트롤의 물리적 시뮬레이션 개체에 대한 권한을 가지고 있는 분산 물리 시스템을 사용하여 클라이언트는 일반적으로 플레이어의 캐릭터 및 해당 캐릭터 근처의 해결된 물리 시뮬레이션 개체에 대한 액세스를 가지고 있습니다. 또한

함께, 이것은 숙련 된 악용자가 게임에서 속임수를 실행하여 얻을 수있는 코드를 얻을 수 있습니다. 여기에는 다음이 포함됩니다.

  • 자신의 캐릭터를 플레이스주변에 텔레포트합니다.
  • 보안되지 않은 RemoteEvents 을 발사하거나, RemoteFunctions 를 호출하여, 그들을 얻지 않고 자신에게 아이템을 수여하는 등의 행위.
  • 캐릭터의 WalkSpeed 을 조정하여 움직이는 속도가 빨라지도록 합니다.

일반적인 공격을 감지하기 위해 제한된 디자인 방어를 구현할 수는 있지만, 더 나은 신뢰성의 서버 사이드 미티게이션 전략을 구현하는 것이 좋습니다. 서버는 모든 실행 경험에 대한 최종 권한을 가지므로 실행 중인 모든 경험에 대해 더 나은 신뢰성의 서버 사이드 미티게이션 전략을 구현하는 것이

방어 디자인 전략

기본 디자인 결정은 "첫 번째 단계" 보안 조치로 플레이어가 다른 플레이어를 죽이는 것을 방지 할 수 있습니다. 예를 들어, 플레이어가 다른 플레이어를 죽이는 것에 대한 포인트를 획득하면 플레이어를 즉시 죽일 수 있도록 허용하는 몇 가지 봇을 만

접근예측 가능한 결과
봇을 감지하려는 코드를 작성하여 추적하세요.
새로 생성된 플레이어에 대한 포인트 획득을 줄이거나 완전히 제거합니다.

방어 디자인은 명백히 완벽하거나 포괄적인 솔루션이 아니지만, 서버 사이드 방어와 함께 더 넓은 보안 접근 방식에 기여할 수 있습니다.

서버 사이드 방어

최대한 많이, 서버는 최종 평결을 내려야 합니다 무엇이 "진실"인지 그리고 현재 세계의 상태는 무엇인지. 클라이언트는 물론 서버에 변경을 요청할 수 있지만, 서버는 결과를 다른 플레이어에게 복제하기 전에 검증하고 승인해야 합니다.

일부 물리 작업 제외하고 클라이언트의 데이터 모델에 대한 변경은 서버에 복제되지 않으므로 주요 공격 경로는 일반적으로 RemoteEventsRemoteFunctions 를 통해 네트워크 이벤트를 호출하는 것입니다. 클라이언트에서 자신

원격 런타임 유형 유효성 검사

한 공격 경로는 잘못된 입력인수를 가진 악의가 있는 플레이어가 RemoteEventsRemoteFunctions 를 호출하도록 하는 것입니다. 일부 시나리오에서 이런 리모트는 서버에서 이 리모트를 들으려는 코드를 오류가 있는 방식으로 오류가 발생할

원격 이벤트/함수를 사용할 때 서버의 타입 을 유효하게 하여 이 유형의 공격을 방지할 수 있습니다. 모듈 “t” , 서버에서 사용할 수 있는 유형 검사 기능을 제공합니다

StarterPlayerScripts의 LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteFunction = ReplicatedStorage:WaitForChild("RemoteFunctionTest")
-- 함수를 호출할 때 부품 색상 및 위치 지정
local newPart = remoteFunction:InvokeServer(Color3.fromRGB(200, 0, 50), Vector3.new(0, 25, 0))
if newPart then
print("The server created the requested part:", newPart)
elseif newPart == false then
print("The server denied the request. No part was created.")
end
ServerScriptService의 스크립트

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteFunction = ReplicatedStorage:WaitForChild("RemoteFunctionTest")
local t = require(ReplicatedStorage:WaitForChild("t"))
-- 필요 없는 대기 시간을 피하기 위해 미리 유형 유효성 검사기를 생성합니다.
local createPartTypeValidator = t.tuple(t.instanceIsA("Player"), t.Color3, t.Vector3)
-- 패스 속성으로 새 부품 생성
local function createPart(player, partColor, partPosition)
-- 패스된 인수를 확인하십시오
if not createPartTypeValidator(player, partColor, partPosition) then
-- 여기에서 타입 검사가 실패하면 "false"를 조용히 반환합니다.
-- 쿨다운이 없는 오류를 발생시키면 서버를 느리게 만들 수 있습니다.
-- 대신 클라이언트 피드백을 제공하십시오!
return false
end
print(player.Name .. " requested a new part")
local newPart = Instance.new("Part")
newPart.Color = partColor
newPart.Position = partPosition
newPart.Parent = workspace
return newPart
end
-- 원격 함수의 콜백에 "createPart()" 바인딩
remoteFunction.OnServerInvoke = createPart

데이터 유효성 검사

악의가 있는 플레이어가 시작할 수 있는 또 다른 공격은 기술적으로 유효한 형식을 보내지만 길이, 길이 또는 다른 방식으로 매우 큰, 긴 또는 손상된 문자열을 만드는 것입니다. 예를 들어, 서버가 길이에 따라 비용이 많이 드는 작업을 수행해야 하는 경우 플레이어는

마찬가지로, 두 infNaN 는 모두 type() 으로 변환되지만, 두 개 모두 1>number1> 을 발생시킬 수 있으며, 팔로잉같은 함수를 통해 잘못 처리되지 않도록 처리할 수 있습니다.


local function isNaN(n: number): boolean
-- NaN은 자체와 같지 않습니다.
return n ~= n
end
local function isInf(n: number): boolean
-- 숫자는 -inf 또는 inf일 수 있습니다.
return math.abs(n) == math.huge
end

악성 코드 사용자가 사용할 수 있는 또 다른 일반적인 공격은 tables 대신 Instance 를 보내는 것입니다. 복잡한 전용 데이터 형식은 일반적인 개체 참조가 될 수 있습니다.

예를 들어, 가격과 같은 아이템 데이터를 Class.NumberValue 개체에 저장하는 경험 내 상점 시스템을 제공하는 경우 악의 사용자는 팔로잉수행하여 다른 모든 검사를 회피할 수 있습니다.

StarterPlayerScripts의 LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local itemDataFolder = ReplicatedStorage:WaitForChild("ItemData")
local buyItemEvent = ReplicatedStorage:WaitForChild("BuyItemEvent")
local payload = {
Name = "Ultra Blade",
ClassName = "Folder",
Parent = itemDataFolder,
Price = {
Name = "Price",
ClassName = "NumberValue",
Value = 0, -- 부정 값을 사용하면 통화를 제공하는 대신 받을 수도 있습니다!
},
}
-- 서버에 악성 부하를 보내십시오(이것은 거부 될 것입니다)
print(buyItemEvent:InvokeServer(payload)) -- 출력 "잘못된 항목 제공"
-- 서버에 실제 아이템 보내기 (이 작업은 통과 할 것입니다!)
print(buyItemEvent:InvokeServer(itemDatafolder["Real Blade"])) -- Outputs "true" and remaining currency if purchase succeeds
ServerScriptService의 스크립트

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local itemDataFolder = ReplicatedStorage:WaitForChild("ItemData")
local buyItemEvent = ReplicatedStorage:WaitForChild("BuyItemEvent")
local function buyItem(player, item)
-- 패스된 항목이 스푸핑되지 않고 아이템 데이터 폴더에 있는지 확인하십시오.
if typeof(item) ~= "Instance" or not item:IsDescendantOf(itemDataFolder) then
return false, "Invalid item provided"
end
-- 서버는 다음 예시 흐름을 기반으로 구매를 처리할 수 있습니다.
end
-- 원격 함수의 콜백에 "buyItem()" 바인딩
buyItemEvent.OnServerInvoke = buyItem

값 유효성 검사

유효한 형식 및 데이터 유효성 검사 외에도 값 및 데이터 를 검사해야 합니다. 이는 요청된 컨텍스트에서 유효하고 논리적인지 확인하기 위함입니다. 두 가지 일반적

경험 내 상점

사용자 인터페이스가 있는 경험 내 상점 시스템을 고려하십시오, 예를 들어 "Buy"버튼이 있는 상품 선택 메뉴. 버튼이 누르면 클라이언트와 서버 사이에서 RemoteFunction 를 호출하여 구매를 요청할 수 있습니다. 그러나 경��

Example purchase flow from client to server through a RemoteEvent
클라이언트에서 서버로 구매 흐름 예시를 통해 클라이언트에서 서버로 구매 흐름을 구성하십시오.

무기 대상

전투 시나리오에서는 특히 조준 및 타겟 유효성 검사를 통해 값을 유효하게 하는 것에 주의를 기울여야 합니다.

플레이어가 다른 플레이어에게 레이저 빔을 발사할 수 있는 게임을 상상하십시오. 클라이언트가 서버에게 누구에게 피해를 입을지 알려주는 대신, 서버는 샷의 원본 위치와 부품/위치를 알고 있어야 합니다. 서버는 팔로잉검증할 수 있습니다.

  • 클라이언트가 보고하는 위치 샷은: 서버의 플레이어 캐릭터 근처에 있습니다. 서버와 클라이언트는 대기 시간 때문에 약간 다르게 보이므로 추가 인내심이 필요합니다.

  • 클라이언트가 보고하는 위치 타격 은 클라이언트가 타격하는 위치, 서버에서 서버에 보고됩니다.

  • 클라이언트가 쏠 위치와 쏠 위치 사이에 정적 장애가 없습니다. 이 검사는 클라이언트가 벽을 통과하여 쏠 위치를 보고하는 위치와 클라이언트가 쏠 위치를 보고하는 위치 사이에서 유효한 샷이 거부되지 않도록 합니다. 이 검사는 대기 시간을 피하기 위해 유효한 장소만 검사해야 합니다. 추가로 , 다음과 같이 서버 사이드 유효성 검사를 구현하는 것이 좋습니다.

  • 플레이어가 무기를 발사한 마지막 시간을 추적하고 유효하게 인증하여 플레이어가 너무 빠르게 쏠 수 없도록 합니다.

  • 서버에서 각 플레이어의 탄약 수량을 추적하고 발사 플레이어가 무기 공격을 수행할 탄약을 충분히 가지고 있는지 확인하십시오.

  • 팀을 구현했거나 플레이어 대 봇 전투 시스템을 구현했다면, 적이 아닌 팀원이 타격당하는 것을 확인하십시오.

  • 타격 플레이어가 생존 중인지 확인하십시오.

  • 서버에 무기 및 플레이어 상태를 저장하고 플레이어가 다시 불러오거나 sprinting과 같은 현재 작업으로 차단되지 않은지 확인하십시오.

데이터 저장소 조작

플레이어 데이터를 저장하기 위해 DataStoreService 를 사용하는 경험에서 악용자는 유효하지 않은 인벤토리, 더 희미한 메서드 등을 이용하여 Class.DataStore 에 저장하지 못하도록 방지할 수 있습니다. 이 점은 특히 아이템

클라이언트 입력과 관련하여 플레이어 데이터에 영향을 주는 RemoteEvent 또는 RemoteFunction 을 통해 수행되는 모든 작업이 팔로잉같이 안전화됩니다.

  • Instance 값은 DataStore에 인스턴스를 serialize할 수 없으며 실패합니다. 형식 유효성 검사를 사용하여 이를 방지하십시오.
  • DataStores 에는 데이터 제한 이 있습니다. 임의 길이의 문자열을 확인하고/또는 제한하여 이를 피하려면 클라이언트가 임의의 키를 테이블에 추가할 수 없도록 하는 것과 함께 확인해야 합니다.
  • 테이블 인덱스는 NaN 또는 nil 일 수 없습니다. 클라이언트에 의해 전달된 모든 테이블을 반복하고 모든 인덱스가 유효한지 확인하십시오.
  • DataStores 는 UTF-8 문자만 수락할 수 있으므로 클라이언트가 제공하는 모든 문자열을 utf8.len()

원격 스로틀링

클라이언트가 서버를 컴퓨터적으로 비용이 많이 드는 작업이나 DataStoreService 와 같은 제한된 요금 서비스에 액세스하도록 허용하는 경우, 서비스가 너무 자주 호출되지 않도록 하려면 요금 제한을

이동 유효성 검사

경쟁적인 경험의 경우, 서버에서 플레이어 캐릭터의 이동을 확인하여 플레이어가 맵 주위를 텔레포트하거나 지나치게 빠르게 이동하지 않도록 하세요.

  1. 1초 증가 시, 캐릭터의 새 위치를 이전에 캐시된 위치와 비교합니다.

    Image showing moving character's position on a straight path in increments of 1 second
  2. 캐릭터의 최대 거리 기반 변경 사항을 결정하십시오(현재 서버 대기 시간에 대한 길이 배수) WalkSpeed (스터드 당 1초), WalkSpeed (16개의 기본 길이)에 대한 절대적인 길이 Class

    Image showing tolerable change in distance based on character's walk speed
  3. 실제 거리 델타와 용인 델타를 비교하고 다음과 같이 진행합니다.

    • 용인 가능한 확인위해 캐릭터의 새로운 위치를 미리 저장하십시오.
    • 예기치 않거나 용이 먹을 수 없는 델타(잠재적 속도/순간이동 악용)에 대해:
      1. 플레이어에게 "오프셋" 값을 증가하여 플레이어에게 적용되는 벌점 값을 줄이십시오, 대신 엄청난 서버 대기 시간 또는 기타 비 악용 요소로 인한 "틀린 양"에 대한 벌점 값을 감소시켜줍니다.
      2. 30-60초 동안 많은 범죄가 발생하면 Kick() 경험 전체에서 플레이어를 제거합니다; 그렇지 않으면 "범죄 수" 카운트를 재설정하십시오. 플레이어가 부정 행위로 킥당하면 트랙을 유지하기 위해 이벤