사용자 정의 유형을 사용하여 Go에서 비밀 로깅 방지

Granted Approvals에 대한 코드베이스에는 다음과 같은 구조가 있습니다.

type Provider struct {
    OrgUrl string
    APIToken string
}


이 경우 apiToken라는 값이 있습니다. 그것은 비밀이고 우리는 그것이 어딘가에 유출되지 않았으면 합니다. 귀하의 비밀 값은 API 토큰일 수도 있고, 암호나 사용자 주소 또는 개인 정보 보호법 소송을 받고 싶지 않은 다른 것일 수도 있습니다.

이와 같이 문자열에 비밀을 저장하는 문제는 실수로 비밀을 기록하기가 매우 쉽다는 것입니다. fmt 또는 zap 줄만 있으면 암호 값이 일반 텍스트로 인쇄되고 외부 로깅 솔루션으로 전송될 수도 있습니다. 내보내지 않은 필드를 사용하는 것이 도움이 될 수 있지만 Zap은 여전히 ​​해당 필드를 포함합니다.

이 글을 읽고 있다면 로그에 민감한 데이터가 있는 것이 위험한 이유를 이미 알고 있을 것입니다. 그렇지 않은 경우 체크아웃할 수 있습니다this . 또는 . 또는 this . 또는…. 당신은 요점을 이해합니다.

눈을 굴리며 민감한 데이터를 절대 기록하지 않겠다고 한다면 이렇게 묻겠습니다. 확실합니까? 인쇄 기능에서 실수로 잘못된 변수 이름을 입력하지 않을 것입니까? 새로운 개발자가 팀에 합류하지 않을 건가요? 당신 팀의 어느 누구도 암호 재설정 기능이 작동하지 않는 이유를 디버깅하기 위해 마감일에서 하룻밤을 지내지 않을 것입니다. 난별로 확신이 들지 않아.

솔루션: 맞춤형 유형.

type Provider struct {
    OrgUrl StringValue
    APIToken SecretStringValue
}


이제 orgUrlapiToken가 문자열 유형이 아니라 StringValue 및 SecretStringValue입니다. 이러한 사용자 정의 유형은 모두 표준 문자열 유형에 대한 작은 추상화를 제공합니다.


type StringValue struct {
    Value string
}

type SecretStringValue struct {
    Value string
}


하지만 우리에게 중요한 부분은 그들이 Stringer 및 MarshalJSON 인터페이스를 구현하는 방법입니다.

func (s StringValue) String() string {
    return s.Value
}

func (s StringValue) MarshalJSON() ([]byte, error) {
    return json.Marshal(s.String())
}

func (s SecretStringValue) String() string {
    return "*****"
}

func (s SecretStringValue) MarshalJSON() ([]byte, error) {
    return json.Marshal(s.String())
}

SecretStringValue에 대한 String() 구현은 수정된 문자열 "*****"만 반환하며 JSON도 마찬가지입니다. 이렇게 하면 비밀을 fmt 또는 zap에 연결하여 실수로 비밀을 기록하는 것이 훨씬 더 어려워집니다.

이제 다음과 같은 경우:

oops := Provider{OrgURL:"commonfate.io",APIToken:"secret"}
fmt.Printf("%s", oops.APIToken)


또는:

oops := Provider{OrgURL: "commonfate.io", APIToken: "secret"}
b, _ := json.Marshal(oops)
fmt.Print(string(b))


그 대가로 얻을 수 있는 것은 ***** 또는 {"OrgUrl":"commonfate.io","APIToken":"*****"} 뿐입니다.

완전 무결점인가요? 아니요. 누군가 의도적으로 값을 인쇄하기로 결정한 경우 여전히 비밀을 기록할 수 있지만 적어도 이제 팀은 어떤 것이 비밀인지 또는 일반 값인지에 대해 더 명확한 컨텍스트를 갖게 되었습니다. 실수를 저지르기가 조금 더 어려워집니다. 그리고 보안에서는 이것이 우리가 진정으로 요구할 수 있는 전부입니다.

코드를 직접 확인하려면 Go Playground link을 참조하십시오. 그리고 우리가 우리 자신의 프로젝트에서 이것을 구현한 방법에 관심이 있다면 우리의 gconfig package을 확인할 수 있습니다.

좋은 웹페이지 즐겨찾기