Local Database
컬렉션을 사용해 정리하기
내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.
Google 세이프 브라우징 v5는 클라이언트가 저장소가 없는 실시간 모드를 선택하지 않는 한 클라이언트가 로컬 데이터베이스를 유지할 것으로 예상합니다. 이 로컬 데이터베이스의 형식과 저장은 클라이언트가 결정합니다. 이 로컬 데이터베이스의 콘텐츠는 개념적으로 다양한 목록이 파일로 포함된 폴더로 생각할 수 있으며, 이러한 파일의 콘텐츠는 SHA256 해시 또는 가장 일반적으로 사용되는 해시 길이인 4바이트 해시 접두사가 있는 해당 접두사입니다.
사용 가능한 목록
목록은 고유한 이름으로 식별되며, 이 이름은 목록에서 예상되는 해시의 길이를 나타내는 접미사를 포함하는 이름 지정 규칙을 따릅니다. 위협 유형은 동일하지만 해시 길이가 다른 해시 목록은 별도의 이름이 지정된 목록으로, 해시 길이를 나타내는 접미사로 한정됩니다.
다음 목록은 해시 목록 메서드와 함께 사용할 수 있습니다.
목록 이름 |
상응하는 v4 ThreatType 열거형 |
설명 |
gc-32b |
없음 |
이 목록은 전역 캐시 목록입니다. 실시간 작동 모드에서만 사용되는 특수 목록입니다. |
se-4b |
SOCIAL_ENGINEERING |
이 목록에는 SOCIAL_ENGINEERING 위협 유형의 위협이 포함되어 있습니다. |
mw-4b |
MALWARE |
이 목록에는 데스크톱 플랫폼의 MALWARE 위협 유형 위협이 포함되어 있습니다. |
uws-4b |
UNWANTED_SOFTWARE |
이 목록에는 데스크톱 플랫폼의 UNWANTED_SOFTWARE 위협 유형의 위협이 포함되어 있습니다. |
uwsa-4b |
UNWANTED_SOFTWARE |
이 목록에는 Android 플랫폼의 UNWANTED_SOFTWARE 위협 유형의 위협이 포함되어 있습니다. |
pha-4b |
POTENTIALLY_HARMFUL_APPLICATION |
이 목록에는 Android 플랫폼의 POTENTIALLY_HARMFUL_APPLICATION 위협 유형의 위협이 포함되어 있습니다. |
나중에 추가 목록이 제공될 수 있으며, 이때 위의 표가 확장되고 hashList.list 메서드의 결과에 최신 목록과 유사한 결과가 표시됩니다.
데이터베이스 업데이트
클라이언트는 정기적으로 hashList.get 메서드 또는 hashLists.batchGet 메서드를 호출하여 데이터베이스를 업데이트합니다. 일반적인 클라이언트는 한 번에 여러 목록을 업데이트하려고 하므로 hashLists.batchGet 메서드를 사용하는 것이 좋습니다.
목록 이름은 변경되지 않습니다. 또한 목록이 표시되면 삭제되지 않습니다. 목록이 더 이상 유용하지 않은 경우 비워지지만 계속 존재합니다. 따라서 Google 세이프 브라우징 클라이언트 코드에 이러한 이름을 하드코딩하는 것이 적절합니다.
hashList.get 메서드와 hashLists.batchGet 메서드 모두 증분 업데이트를 지원합니다. 증분 업데이트를 사용하면 대역폭을 절약하고 성능을 개선할 수 있습니다. 증분 업데이트는 클라이언트의 목록 버전과 목록의 최신 버전 간의 델타를 전송하여 작동합니다. 클라이언트가 새로 배포되었으며 사용 가능한 버전이 없는 경우 전체 업데이트를 사용할 수 있습니다. 증분 업데이트에는 삭제 색인과 추가가 포함됩니다. 클라이언트는 먼저 지정된 색인의 항목을 로컬 데이터베이스에서 삭제한 다음 추가를 적용해야 합니다.
마지막으로 손상을 방지하기 위해 클라이언트는 저장된 데이터를 서버에서 제공한 체크섬과 대조해야 합니다. 체크섬이 일치하지 않을 때마다 클라이언트는 전체 업데이트를 실행해야 합니다.
목록 콘텐츠 디코딩
해시 및 해시 접두사 디코딩
모든 목록은 크기를 줄이기 위해 특수 인코딩을 사용하여 전송됩니다. 이 인코딩은 Google 세이프 브라우징 목록에 개념적으로 랜덤 정수와 통계적으로 구분할 수 없는 해시 또는 해시 접두사 집합이 포함되어 있음을 인식하여 작동합니다. 이러한 정수를 정렬하고 인접한 차이를 취하면 이러한 인접한 차이는 어떤 의미에서는 '작음'일 것으로 예상됩니다. 그러면 Golomb-Rice 인코딩이 이 소형성을 활용합니다.
4바이트 해시 접두사를 사용하여 a.example.com/
, b.example.com/
, y.example.com/
라는 세 개의 호스트 접미사 경로 접두사 표현식을 전송한다고 가정해 보겠습니다. 또한 k로 표시되는 Rice 매개변수가 다음과 같이 선택되었다고 가정합니다.
- 서버는 먼저 이러한 문자열의 전체 해시를 계산합니다. 각각의 해시는 다음과 같습니다.
291bc5421f1cd54d99afcc55d166e2b9fe42447025895bf09dd41b2110a687dc a.example.com/
1d32c5084a360e58f1b87109637a6810acad97a861a7769e8f1841410d2a960c b.example.com/
f7a502e56e8b01c6dc242b35122683c9d25d07fb1f532d9853eb0ef3ff334f03 y.example.com/
그런 다음 서버는 위의 각 항목에 대해 4바이트 해시 접두사를 형성합니다. 이는 32바이트 전체 해시의 첫 4바이트이며 big-endian 32비트 정수로 해석됩니다. Big-endianness는 전체 해시의 첫 번째 바이트가 32비트 정수의 최상위 바이트가 된다는 사실을 나타냅니다. 이 단계를 완료하면 정수 0x291bc542, 0x1d32c508, 0xf7a502e5가 생성됩니다.
서버는 이 세 개의 해시 접두사를 사전순으로 정렬해야 합니다 (빅엔디언의 숫자 정렬과 동일). 정렬 결과는 0x1d32c508, 0x291bc542, 0xf7a502e5입니다. 첫 번째 해시 접두사는 변경되지 않은 상태로 first_value
필드에 저장됩니다.
그런 다음 서버는 두 개의 인접한 차이(각각 0xbe9003a 및 0xce893da3)를 계산합니다. k가 30으로 선택된 경우 서버는 이 두 숫자를 각각 길이가 2비트와 30비트인 몫 부분과 나머지 부분으로 나눕니다. 첫 번째 숫자의 경우 몫 부분은 0이고 나머지는 0xbe9003a입니다. 두 번째 숫자의 경우 최상위 두 비트가 바이너리로 11이고 나머지는 0xe893da3이므로 몫 부분은 3입니다. 주어진 몫 q
의 경우 정확히 1 + q
비트를 사용하여 (1 << q) - 1
로 인코딩됩니다. 나머지는 k비트를 사용하여 직접 인코딩됩니다. 첫 번째 숫자의 몫 부분은 0으로 인코딩되고 나머지 부분은 바이너리 001011111010010000000000111010입니다. 두 번째 숫자의 몫 부분은 0111로 인코딩되고 나머지 부분은 001110100010010011110110100011입니다.
이러한 숫자가 바이트 문자열로 형성되면 리틀 엔디언이 사용됩니다. 개념적으로는 최하위 비트부터 긴 비트 문자열이 형성된다고 생각하는 것이 더 쉽습니다. 첫 번째 숫자의 몫 부분을 취하고 첫 번째 숫자의 나머지 부분을 앞에 추가합니다. 그런 다음 두 번째 숫자의 몫 부분을 앞에 추가하고 나머지 부분을 앞에 추가합니다. 그러면 다음과 같은 큰 숫자가 표시됩니다 (명확성을 위해 줄바꿈 및 주석 추가됨).
001110100010010011110110100011 # Second number, remainder part
0111 # Second number, quotient part
001011111010010000000000111010 # First number, remainder part
0 # First number, quotient part
한 줄로 작성하면 다음과 같습니다.
00111010001001001111011010001101110010111110100100000000001110100
이 숫자는 단일 바이트에 사용할 수 있는 8비트를 훨씬 초과합니다. 그러면 little endian 인코딩은 이 숫자의 최하위 8비트를 사용하여 첫 번째 바이트인 01110100으로 출력합니다. 명확성을 위해 위의 비트 문자열을 최하위 비트부터 시작하여 8개 그룹으로 그룹화할 수 있습니다.
0 01110100 01001001 11101101 00011011 10010111 11010010 00000000 01110100
그런 다음 little endian 인코딩은 오른쪽에서 각 바이트를 가져와 바이트 문자열에 넣습니다.
01110100
00000000
11010010
10010111
00011011
11101101
01001001
01110100
00000000
개념적으로 왼쪽의 큰 수에 새 부분을 앞부분에 추가 (즉, 더 많은 유효 자릿수를 추가)하지만 오른쪽에서 인코딩 (즉, 최소 유효 자릿수)하므로 인코딩과 디코딩을 점진적으로 실행할 수 있습니다.
결국 다음과 같은 결과가 발생합니다.
additions_four_bytes {
first_value: 489866504
rice_parameter: 30
entries_count: 2
encoded_data: "t\000\322\227\033\355It\000"
}
클라이언트는 위의 단계를 역순으로 따라 해시 접두사를 디코딩합니다.
삭제 색인 디코딩
삭제 색인은 32비트 정수를 사용하여 위와 동일한 기술을 사용하여 인코딩됩니다.
업데이트 빈도
클라이언트는 minimum_wait_duration
필드에서 서버의 반환 값을 검사하고 이를 사용하여 데이터베이스의 다음 업데이트를 예약해야 합니다. 이 값은 0일 수 있습니다 (minimum_wait_duration
필드가 완전히 누락됨). 이 경우 클라이언트는 즉시 다른 업데이트를 실행해야 합니다.
달리 명시되지 않는 한 이 페이지의 콘텐츠에는 Creative Commons Attribution 4.0 라이선스에 따라 라이선스가 부여되며, 코드 샘플에는 Apache 2.0 라이선스에 따라 라이선스가 부여됩니다. 자세한 내용은 Google Developers 사이트 정책을 참조하세요. 자바는 Oracle 및/또는 Oracle 계열사의 등록 상표입니다.
최종 업데이트: 2025-07-25(UTC)
[null,null,["최종 업데이트: 2025-07-25(UTC)"],[],[],null,["# Local Database\n\nGoogle Safe Browsing v5 expects the client to maintain a local database, except when the client chooses the [No-Storage Real-Time Mode](/safe-browsing/reference#no-storage-real-time-mode). It is up to the client the format and storage of this local database. The contents of this local database can conceptually be thought of as a folder containing various lists as files, and the contents of these files are SHA256 hashes, or their corresponding prefixes with four byte hash prefix being the most commonly used hash length.\n\n### Available Lists\n\nLists are identified by their distinct names which follows a naming convention where the name contains a suffix that signifies the length of the hash you should expect in the list. Hash lists with the same threat type but different hash length will be a separately named list that's qualified with a suffix that indicates the hash length.\n\nThe following lists are available for use with the hash list methods.\n\n| List Name | Corresponding v4 `ThreatType` Enum | Description |\n|-----------|------------------------------------|------------------------------------------------------------------------------------------------------|\n| `gc-32b` | None | This list is a Global Cache list. It is a special list only used in the Real-Time mode of operation. |\n| `se-4b` | `SOCIAL_ENGINEERING` | This list contains threats of the SOCIAL_ENGINEERING threat type. |\n| `mw-4b` | `MALWARE` | This list contains threats of the MALWARE threat type for desktop platforms. |\n| `uws-4b` | `UNWANTED_SOFTWARE` | This list contains threats of the UNWANTED_SOFTWARE threat type for desktop platforms. |\n| `uwsa-4b` | `UNWANTED_SOFTWARE` | This list contains threats of the UNWANTED_SOFTWARE threat type for Android platforms. |\n| `pha-4b` | `POTENTIALLY_HARMFUL_APPLICATION` | This list contains threats of the POTENTIALLY_HARMFUL_APPLICATION threat type for Android platforms. |\n\nAdditional lists can become available at a later date, at which time the above table will be expanded, and the results from the [hashList.list method](/safe-browsing/reference/rest/v5/hashList/list) will show a similar result with the most up to date lists.\n\n### Database Updates\n\nThe client will regularly call the [hashList.get method](/safe-browsing/reference/rest/v5/hashList/get) or the [hashLists.batchGet method](/safe-browsing/reference/rest/v5/hashLists/batchGet) to update the database. Since the typical client will want to update multiple lists at a time, it is recommended to use [hashLists.batchGet method](/safe-browsing/reference/rest/v5/hashLists/batchGet).\n\nThe list names will never be renamed. Furthermore, once a list has appeared, it will never be removed (if the list is no longer useful, it will become empty but will continue to exist). Therefore, it is appropriate to hard code these names in the Google Safe Browsing client code.\n\nBoth the [hashList.get method](/safe-browsing/reference/rest/v5/hashList/get) and the [hashLists.batchGet method](/safe-browsing/reference/rest/v5/hashLists/batchGet) support incremental updates. Using incremental updates saves bandwidth and improves performance. Incremental updates work by delivering a delta between client's version of the list and the latest version of the list. (If a client is newly deployed and does not have any versions available, a full update is available.) The incremental update contains removal indices and additions. The client is first expected to remove the entries at the specified indices from its local database, and then apply the additions.\n\nFinally, to prevent corruption, the client should check the stored data against the checksum provided by the server. Whenever the checksum does not match, the client should perform a full update.\n\n### Decoding the List Content\n\n#### Decoding Hashes and Hash Prefixes\n\nAll lists are delivered using a special encoding to reduce size. This encoding works by recognizing that Google Safe Browsing lists contain, conceptually, a set of hashes or hash prefixes, which are statistically indistinguishable from random integers. If we were to sort these integers and take their adjacent difference, such adjacent difference is expected to be \"small\" in a sense. [Golomb-Rice encoding](https://en.wikipedia.org/wiki/Golomb_coding) then exploits this smallness.\n\nSuppose that three host-suffix path-prefix expressions, namely `a.example.com/`, `b.example.com/`, and `y.example.com/`, are to be transmitted using 4-byte hash prefixes. Further suppose that the Rice parameter, denoted by k, is chosen to be\n\n1. The server would start by calculating the full hash for these strings, which are, respectively:\n\n 291bc5421f1cd54d99afcc55d166e2b9fe42447025895bf09dd41b2110a687dc a.example.com/\n 1d32c5084a360e58f1b87109637a6810acad97a861a7769e8f1841410d2a960c b.example.com/\n f7a502e56e8b01c6dc242b35122683c9d25d07fb1f532d9853eb0ef3ff334f03 y.example.com/\n\nThe server then forms 4-byte hash prefixes for each of the above, which is the first 4 bytes of the 32-byte full hash, interpreted as big-endian 32-bit integers. The big endianness refers to the fact that the first byte of the full hash becomes the most significant byte of the 32-bit integer. This step results in the integers 0x291bc542, 0x1d32c508, and 0xf7a502e5.\n\nIt is necessary for the server to sort these three hash prefixes lexicographically (equivalent to numerical sorting in big endian), and the result of the sorting is 0x1d32c508, 0x291bc542, 0xf7a502e5. The first hash prefix is stored unchanged in the `first_value` field.\n\nThe server then calculates the two adjacent differences, which are 0xbe9003a and 0xce893da3 respectively. Given that k is chosen to be 30, the server splits these two numbers into the quotient parts and remainder parts that are 2 and 30 bits long respectively. For the first number, the quotient part is zero and the remainder is 0xbe9003a; for the second number, the quotient part is 3 because the most significant two bits are 11 in binary and the remainder is 0xe893da3. For a given quotient `q` it is encoded into `(1 \u003c\u003c q) - 1` using exactly `1 + q` bits; the remainder is encoded directly using k bits. The quotient part of the first number is encoded as 0, and the remainder part is in binary 001011111010010000000000111010; the quotient part of the second number is encoded as 0111, and the remainder part is 001110100010010011110110100011.\n\nWhen these numbers are formed into a byte string, little endian is used. Conceptually it may be easier to imagine a long bitstring being formed starting from the least significant bits: we take the quotient part of the first number and prepend the remainder part of the first number; we then further prepend the quotient part of the second number and prepend the remainder part. This should result in the following large number (linebreaks and comments added for clarity): \n\n 001110100010010011110110100011 # Second number, remainder part\n 0111 # Second number, quotient part\n 001011111010010000000000111010 # First number, remainder part\n 0 # First number, quotient part\n\nWritten in a single line this would be \n\n 00111010001001001111011010001101110010111110100100000000001110100\n\nObviously this number far exceeds the 8 bits available in a single byte. The little endian encoding then takes the least significant 8 bits in that number, and outputs it as the first byte which is 01110100. For clarity, we can group the above bitstring into groups of eight starting from the least significant bits: \n\n 0 01110100 01001001 11101101 00011011 10010111 11010010 00000000 01110100\n\nThe little endian encoding then takes each byte from the right and puts that into a bytestring: \n\n 01110100\n 00000000\n 11010010\n 10010111\n 00011011\n 11101101\n 01001001\n 01110100\n 00000000\n\nIt can be seen that since we conceptually *prepend* new parts to the large number on the left (i.e. adding more significant bits) but we encode from the right (i.e. the least significant bits), the encoding and decoding can be performed incrementally.\n\nThis finally results in \n\n additions_four_bytes {\n first_value: 489866504\n rice_parameter: 30\n entries_count: 2\n encoded_data: \"t\\000\\322\\227\\033\\355It\\000\"\n }\n\nThe client simply follows the above steps in reverse to decode the hash prefixes.\n\n#### Decoding Removal Indices\n\nRemoval indices are encoded using the exact same technique as above using 32-bit integers.\n\n### Update Frequency\n\nThe client should inspect the server's returned value in the field `minimum_wait_duration` and use that to schedule the next update of the database. This value is possibly zero (the field `minimum_wait_duration` is completely missing), in which case the client SHOULD immediately perform another update."]]