데이터 편집(Redaction)

URL 편집은 기본으로 적용되고 속성 편집은 선택 사항입니다. 기본으로 무엇을 URL에서 제거하는지, sanitizeUrl로 어떻게 확장하는지, attributeScrubbers로 속성 값을 어떻게 편집하는지 설명합니다.

SDK는 URL을 기록하기 전에 편집하며, 요청하면 속성 값도 편집합니다. 두 기능의 기본값은 의도적으로 다릅니다.

기본값옵션
URL 편집켜짐. 자격 증명과 널리 쓰이는 쿼리 파라미터 19종을 편집합니다직접 구현을 넣으려면 sanitizeUrl
속성 편집꺼짐. 규칙이 없으며 아무것도 바뀌지 않습니다규칙을 추가하려면 attributeScrubbers

두 기능은 세션 리플레이 마스킹 옵션(maskAllInputs, maskAllText, maskClass)을 대체하지 않습니다. 마스킹 옵션은 텔레메트리 속성이 아니라 기록되는 DOM 내용을 다룹니다.

URL 편집

NOTE — 설정하지 않아도 켜져 있습니다

SDK가 기록하는 모든 URL은 기본 정제 함수를 거칩니다. 이 동작을 위해 옵션을 지정할 필요도, init() 호출을 바꿀 필요도 없습니다.

무엇을 편집하는가

authority에 포함된 자격 증명. https://user:pass@api.example.com/v1https://REDACTED:REDACTED@api.example.com/v1이 됩니다. 비밀번호 없이 https://token@host 형태면 https://REDACTED@host가 됩니다.

쿼리 파라미터 19종의 값. 파라미터 이름은 그대로 두고 값만 치환합니다. 텔레메트리를 보는 운영자가 그 자리에 비밀 값이 있었다는 사실 자체는 알 수 있어야 하기 때문입니다.

https://app.example.com/checkout?token=abc123&plan=pro
https://app.example.com/checkout?token=REDACTED&plan=pro

기본 목록은 다음과 같습니다.

password, passwd, secret, api_key, apikey, auth, authorization, token, access_token, refresh_token, jwt, session, sessionid, key, private_key, client_secret, client_id, signature, hash

매칭 규칙

  • 이름 전체가 일치해야 하며, 대소문자는 구분하지 않습니다. ?Token=?TOKEN=은 편집되지만 ?tokenizer=, ?keyword=, ?monkey=는 편집되지 않습니다. 부분 문자열 매칭은 쓰지 않습니다. 기본 목록에는 key, auth, hash, session처럼 다른 이름 안에 흔히 들어가는 짧은 단어가 있고, 과잉 편집은 되돌릴 수 없기 때문입니다.
  • 이름은 디코딩한 뒤 비교합니다. +는 공백으로, 퍼센트 인코딩은 원래 문자로 되돌리고 앞뒤 공백을 제거하므로 ?%74oken=?%20token= 모두 편집됩니다.
  • 같은 이름이 여러 번 나오면 각각 편집합니다. ?token=a&token=b는 하나로 합쳐지지 않고 ?token=REDACTED&token=REDACTED가 됩니다.
  • 프래그먼트도 검사합니다. OAuth 2.0 implicit grant는 서버로 전송되지 않도록 access_token을 프래그먼트에 담습니다. 즉 실제로 비밀 값이 존재하는 자리입니다. #access_token=… 형태와 #/checkout?token=… 같은 해시 라우트를 모두 처리합니다. name=value 쌍이 없는 프래그먼트(#installation, #/orders/42)는 그대로 통과합니다.
  • 그 밖에는 아무것도 바꾸지 않습니다. 경로, 인코딩, 파라미터 순서, 호스트 대소문자, 기본 포트, 끝의 슬래시가 바이트 단위로 그대로 유지됩니다.

어디에 적용되는가

  • SDK가 내보내는 모든 Span과 모든 로그 레코드의 url.full. 내보내기 직전에 적용되므로 SDK가 직접 쓴 값뿐 아니라 업스트림 계측이 쓴 값도 함께 처리됩니다.
  • WebSocket 연결 Span의 http.url.
  • screenNameOption.urlWithSearchParamstrue여서 화면 이름에 쿼리 문자열이 포함되는 경우의 화면 이름.

기본 목록에 없는 파라미터

CAUTION — 사용 중인 파라미터 이름을 목록과 대조하세요

기본 목록은 널리 쓰이는 이름을 모아둔 것이지 사용 중인 이름을 추측한 것이 아닙니다. session_tokensessionToken은 목록에 없습니다. 목록에 있는 것은 session, sessionid, token, access_token입니다. api-key처럼 하이픈을 쓴 변형도 없습니다. 목록에 없는 파라미터에 비밀 값을 담고 있다면 목록을 확장하세요.

기본 목록을 대체하지 말고 확장하세요.

import { createSanitizeUrl } from '@sophonz/redaction';
 
SophonzSDK.init({
  collectorUrl: 'https://in.v0.sophonz.com',
  appName: '{{NAME_OF_YOUR_WEB_SERVICE}}',
  appVersion: '{{VERSION_OF_YOUR_WEB_SERVICE}}',
  appKey: '{{KEY_OF_YOUR_WEB_SERVICE}}',
  sanitizeUrl: createSanitizeUrl({
    additionalQueryParamsToScrub: ['session_token', 'sessionToken', 'api-key'],
  }),
});

createSanitizeUrl이 받는 옵션은 다음과 같습니다.

옵션타입기본값설명
additionalQueryParamsToScrubreadonly string[][]기본 19종에 더해서 편집할 이름
queryParamsToScrubreadonly string[]기본 19종기본 목록을 통째로 대체합니다. 위 옵션을 권장합니다
redactCredentialsbooleantrueauthority의 user:password@를 편집합니다
scrubFragmentbooleantrue프래그먼트에서도 파라미터를 찾습니다

sanitizeUrl

((url: string) => string, 선택)

URL 정제 함수를 통째로 대체합니다.

WARNING — 직접 만든 함수는 기본 동작과 함께 실행되지 않고 기본 동작을 대체합니다

직접 함수를 넘기면, 그 함수가 편집하지 않는 한 기본 19종 파라미터는 더 이상 편집되지 않습니다. 기본 동작을 유지하면서 이름을 추가하려면 위의 createSanitizeUrl을 사용하세요.

이 함수는 고객 페이지의 핫 패스에서 실행되므로 SDK가 모든 호출을 감싸고, 실패하면 안전한 쪽으로 처리합니다.

함수의 동작결과
문자열 반환반환한 값이 기록됩니다
예외 발생해당 URL은 REDACTED로 기록되고, 실패는 diag로 한 번 보고됩니다
문자열이 아닌 값 반환해당 URL은 REDACTED로 기록되고, 실패는 diag로 한 번 보고됩니다

따라서 url.full 값이 정확히 REDACTED라면 URL이 비어 있었다는 뜻이 아니라 정제 함수가 그 URL을 처리하지 못했다는 뜻입니다.

속성 편집

attributeScrubbers

(AttributeScrubber[], 선택)

모든 Span과 모든 로그 레코드의 속성에 적용되는 키 단위 편집 규칙입니다. Span은 종료 시점에, 로그 레코드는 발생 시점에 처리하므로 계측이 나중에 추가한 속성도 빠짐없이 거칩니다.

NOTE — 기본 규칙은 없습니다

아무것도 설정하지 않으면 아무것도 바뀌지 않으며, 프로세서 자체가 생성되지 않습니다. URL 편집과 정반대의 기본값이며 의도한 결과입니다. 속성 키는 http.request.header.authorization, app.screen.name, session.id처럼 구조화된 네임스페이스이지 작성자가 자유롭게 붙인 이름이 아닙니다. 그래서 일반적인 기본 목록을 두면 쓸모 있는 키는 거의 못 맞히면서 session.id 같은 핵심 키를 조용히 비워버릴 위험만 커집니다. 실제로 비밀 값을 담는 속성은 고객이 직접 넣은 것이고, 그 이름을 아는 사람도 고객입니다.

하나의 규칙은 매처와 선택적인 변환으로 이루어집니다.

필드타입설명
keysreadonly string[]정확히 일치하는 속성 키. 대소문자를 구분합니다
keyPatternRegExp | readonly RegExp[]키에 대해 검사할 정규식
shouldScrub(key: string) => boolean임의의 조건식. 위 두 가지로 표현할 수 없을 때만 사용하세요
scrub(key: string, value) => value | undefined치환할 값. 생략하면 REDACTED, undefined를 반환하면 속성이 제거됩니다

매처는 최소 하나가 필요합니다. 매처가 없는 규칙은 아무것도 매칭하지 못하므로 시작 시점에 제외되고 diag로 보고됩니다.

SophonzSDK.init({
  collectorUrl: 'https://in.v0.sophonz.com',
  appName: '{{NAME_OF_YOUR_WEB_SERVICE}}',
  appVersion: '{{VERSION_OF_YOUR_WEB_SERVICE}}',
  appKey: '{{KEY_OF_YOUR_WEB_SERVICE}}',
  attributeScrubbers: [
    // 값을 'REDACTED'로 치환
    { keys: ['app.user.email'] },
    // 키 계열 전체를 매칭
    { keyPattern: /^http\.request\.header\./ },
    // 비우지 않고 변환
    {
      keys: ['app.query'],
      scrub: (_key, value) =>
        typeof value === 'string' ? value.slice(0, 64) : value,
    },
    // 속성 자체를 제거
    { keys: ['app.internal'], scrub: () => undefined },
  ],
});

매칭되는 규칙은 모두, 선언한 순서대로 실행되며 값을 이어받습니다. 자르는 규칙 뒤에 해시하는 규칙을 두면 읽는 순서 그대로 합성됩니다.

shouldScrub보다 keyskeyPattern을 권장합니다. 선언형 매처는 하나의 공유 집합과 공유 정규식 목록으로 컴파일되므로 어떤 규칙과도 무관한 속성은 조회 한 번으로 끝납니다. shouldScrub을 선언하면 그 규칙은 이 빠른 경로에서 빠집니다.

규칙이 예외를 던질 때

고객이 제공한 규칙은 모두 감싸서 호출하며, 두 가지 실패를 다르게 처리합니다.

예외 발생 위치결과
scrub값이 REDACTED가 되고 규칙은 계속 동작합니다. 매처가 반응했다는 것은 그 키가 비밀 값을 담을 수 있다는 뜻이므로 안전한 쪽으로 처리합니다
shouldScrub속성을 그대로 두고 해당 규칙은 페이지가 살아 있는 동안 비활성화됩니다. 예외를 던진 조건식은 그 키에 대해 아무것도 알려주지 못했고, 계속 호출하면 모든 속성마다 예외가 발생합니다

두 경우 모두 규칙마다 한 번씩만 diag로 보고하므로, 모든 Span에서 실패하는 규칙이 콘솔을 가득 채우는 일은 없습니다. 하나가 고장 나도 다른 규칙은 영향을 받지 않습니다.