json.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. // Unless explicitly stated otherwise all files in this repository are licensed
  2. // under the Apache License Version 2.0.
  3. // This product includes software developed at Datadog (https://www.datadoghq.com/).
  4. // Copyright 2016-present Datadog, Inc.
  5. package obfuscate
  6. import (
  7. "strconv"
  8. "strings"
  9. )
  10. // ObfuscateMongoDBString obfuscates the given MongoDB JSON query.
  11. func (o *Obfuscator) ObfuscateMongoDBString(cmd string) string {
  12. return obfuscateJSONString(cmd, o.mongo)
  13. }
  14. // ObfuscateElasticSearchString obfuscates the given ElasticSearch JSON query.
  15. func (o *Obfuscator) ObfuscateElasticSearchString(cmd string) string {
  16. return obfuscateJSONString(cmd, o.es)
  17. }
  18. // obfuscateJSONString obfuscates the given span's tag using the given obfuscator. If the obfuscator is
  19. // nil it is considered disabled.
  20. func obfuscateJSONString(cmd string, obfuscator *jsonObfuscator) string {
  21. if obfuscator == nil || cmd == "" {
  22. // obfuscator is disabled or string is empty
  23. return cmd
  24. }
  25. out, _ := obfuscator.obfuscate([]byte(cmd))
  26. // we should accept whatever the obfuscator returns, even if it's an error: a parsing
  27. // error simply means that the JSON was invalid, meaning that we've only obfuscated
  28. // as much of it as we could. It is safe to accept the output, even if partial.
  29. return out
  30. }
  31. type jsonObfuscator struct {
  32. keepKeys map[string]bool // the values for these keys will not be obfuscated
  33. transformKeys map[string]bool // the values for these keys pass through the transformer
  34. transformer func(string) string
  35. scan *scanner // scanner
  36. closures []bool // closure stack, true if object (e.g. {[{ => []bool{true, false, true})
  37. key bool // true if scanning a key
  38. wiped bool // true if obfuscation string (`"?"`) was already written for current value
  39. keeping bool // true if not obfuscating
  40. transformingValue bool // true if collecting the next literal for transformation
  41. keepDepth int // the depth at which we've stopped obfuscating
  42. }
  43. func newJSONObfuscator(cfg *JSONConfig, o *Obfuscator) *jsonObfuscator {
  44. keepValue := make(map[string]bool, len(cfg.KeepValues))
  45. for _, v := range cfg.KeepValues {
  46. keepValue[v] = true
  47. }
  48. var (
  49. transformKeys map[string]bool
  50. transformer func(string) string
  51. )
  52. if len(cfg.ObfuscateSQLValues) > 0 {
  53. transformer = sqlObfuscationTransformer(o)
  54. transformKeys = make(map[string]bool, len(cfg.ObfuscateSQLValues))
  55. for _, v := range cfg.ObfuscateSQLValues {
  56. transformKeys[v] = true
  57. }
  58. }
  59. return &jsonObfuscator{
  60. closures: []bool{},
  61. keepKeys: keepValue,
  62. transformKeys: transformKeys,
  63. transformer: transformer,
  64. scan: &scanner{},
  65. }
  66. }
  67. func sqlObfuscationTransformer(o *Obfuscator) func(string) string {
  68. return func(s string) string {
  69. result, err := o.ObfuscateSQLString(s)
  70. if err != nil {
  71. o.log.Debugf("Failed to obfuscate SQL string '%s': %s", s, err.Error())
  72. // instead of returning an empty string we explicitly return an error string here within the result in order
  73. // to surface the problem clearly to the user
  74. return "Datadog-agent failed to obfuscate SQL string. Enable agent debug logs for more info."
  75. }
  76. return result.Query
  77. }
  78. }
  79. // setKey verifies if we are currently scanning a key based on the current state
  80. // and updates the state accordingly. It must be called only after a closure or a
  81. // value scan has ended.
  82. func (p *jsonObfuscator) setKey() {
  83. n := len(p.closures)
  84. p.key = n == 0 || p.closures[n-1] // true if we are at top level or in an object
  85. p.wiped = false
  86. }
  87. func (p *jsonObfuscator) obfuscate(data []byte) (string, error) {
  88. var out strings.Builder
  89. keyBuf := make([]byte, 0, 10) // recording key token
  90. valBuf := make([]byte, 0, 10) // recording value
  91. p.scan.reset()
  92. for _, c := range data {
  93. p.scan.bytes++
  94. op := p.scan.step(p.scan, c)
  95. depth := len(p.closures)
  96. switch op {
  97. case scanBeginObject:
  98. // object begins: {
  99. p.closures = append(p.closures, true)
  100. p.setKey()
  101. p.transformingValue = false
  102. case scanBeginArray:
  103. // array begins: [
  104. p.closures = append(p.closures, false)
  105. p.setKey()
  106. p.transformingValue = false
  107. case scanEndArray, scanEndObject:
  108. // array or object closing
  109. if n := len(p.closures) - 1; n > 0 {
  110. p.closures = p.closures[:n]
  111. }
  112. fallthrough
  113. case scanObjectValue, scanArrayValue:
  114. // done scanning value
  115. p.setKey()
  116. if p.transformingValue && p.transformer != nil {
  117. v, err := strconv.Unquote(string(valBuf))
  118. if err != nil {
  119. v = string(valBuf)
  120. }
  121. result := p.transformer(v)
  122. out.WriteByte('"')
  123. out.WriteString(result)
  124. out.WriteByte('"')
  125. p.transformingValue = false
  126. valBuf = valBuf[:0]
  127. } else if p.keeping && depth < p.keepDepth {
  128. p.keeping = false
  129. }
  130. case scanBeginLiteral, scanContinue:
  131. // starting or continuing a literal
  132. if p.transformingValue {
  133. valBuf = append(valBuf, c)
  134. continue
  135. } else if p.key {
  136. // it's a key
  137. keyBuf = append(keyBuf, c)
  138. } else if !p.keeping {
  139. // it's a value we're not keeping
  140. if !p.wiped {
  141. out.Write([]byte(`"?"`))
  142. p.wiped = true
  143. }
  144. continue
  145. }
  146. case scanObjectKey:
  147. // done scanning key
  148. k := strings.Trim(string(keyBuf), `"`)
  149. if !p.keeping && p.keepKeys[k] {
  150. // we should not obfuscate values of this key
  151. p.keeping = true
  152. p.keepDepth = depth + 1
  153. } else if !p.transformingValue && p.transformer != nil && p.transformKeys[k] {
  154. // the string value immediately following this key will be passed through the value transformer
  155. // if anything other than a literal is found then sql obfuscation is stopped and json obfuscation
  156. // proceeds as usual
  157. p.transformingValue = true
  158. }
  159. keyBuf = keyBuf[:0]
  160. p.key = false
  161. case scanSkipSpace:
  162. continue
  163. case scanError:
  164. // we've encountered an error, mark that there might be more JSON
  165. // using the ellipsis and return whatever we've managed to obfuscate
  166. // thus far.
  167. out.Write([]byte("..."))
  168. return out.String(), p.scan.err
  169. }
  170. out.WriteByte(c)
  171. }
  172. if p.scan.eof() == scanError {
  173. // if an error occurred it's fine, simply add the ellipsis to indicate
  174. // that the input has been truncated.
  175. out.Write([]byte("..."))
  176. return out.String(), p.scan.err
  177. }
  178. return out.String(), nil
  179. }