Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Go をセキュアに書き進めるための
「ガードレール」を整備しよう / Let's Build Security Guardrails For Your Go Programs!

Go をセキュアに書き進めるための
「ガードレール」を整備しよう / Let's Build Security Guardrails For Your Go Programs!

Go Conference 2021 Spring (B7-S) で使用した資料です。
- セッションの詳細: https://gocon.jp/sessions/session-b7-s/
- 発表者: https://twitter.com/lmt_swallow
- 資料に誤りがあれば是非こちらにご連絡ください

Takashi Yoneuchi

April 24, 2021
Tweet

More Decks by Takashi Yoneuchi

Other Decks in Programming

Transcript

  1. ˜TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛ੔උ͠Α͏  ͋Εɺ͜Εͬͯ҆શ͚ͩͬʜʜ /* ... */ x := 0

    blah(unsafe.Pointer(x)) /* ... */ /* .... */ config = &tls.Config{ InsecureSkipVerify: true, }; /* .... */
  2. ˜TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛ੔උ͠Α͏  ͋Εɺ͜Εͬͯ҆શ͚ͩͬʜʜ /* ... */ x := 0

    blah(unsafe.Pointer(x)) /* ... */ /* .... */ config = &tls.Config{ InsecureSkipVerify: true, }; /* .... */ https://golang.org/pkg/math/rand
  3. ˜TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛ੔උ͠Α͏  ͋͋ɺ҆શͳίʔυΛॻ͘ͷ͸ർΕΔ ʜʜͦΕ͕ͨͱ͑(PͰ͋ͬͯ΋ʂ /* ... */ x :=

    0 blah(unsafe.Pointer(x)) /* ... */ /* .... */ config = &tls.Config{ InsecureSkipVerify: true, }; /* .... */ https://golang.org/pkg/math/rand
  4. ˜TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛ੔උ͠Α͏   ͦ΋ͦ΋ԿʹؾΛ͚ͭΔ΂͖͔Λ୭΋஌Βͳ͍··  ࣗ෼͸෼͔͍ͬͯΔ͕ɺνʔϜʹ஌ݟ͕ਁಁ͠ͳ͍  ஌͍ͬͯͯ΋஫ҙෆ଍Ͱ੬ऑͳίʔυΛॻ͍ͯ͠·͏ ΄͍͠ͷ͸ʜ

    ՝୊ ஌͍ͬͯͯ΋஫ҙෆ଍Ͱ ੬ऑͳίʔυΛॻ͍ͯ͠·͏ ՝୊ ࣗ෼͸෼͔͍ͬͯΔ͕ɺ νʔϜʹ஌ݟ͕ਁಁ͠ͳ͍ ՝୊ ͦ΋ͦ΋ԿʹؾΛ͚ͭΔ΂͖͔Λ୭΋஌Βͳ͍·· ՝୊ c := &http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, }, }, }
  5. ˜TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛ੔උ͠Α͏   ͦ΋ͦ΋ԿʹؾΛ͚ͭΔ΂͖͔Λ୭΋஌Βͳ͍··  ࣗ෼͸෼͔͍ͬͯΔ͕ɺνʔϜʹ஌ݟ͕ਁಁ͠ͳ͍  ஌͍ͬͯͯ΋஫ҙෆ଍Ͱ੬ऑͳίʔυΛॻ͍ͯ͠·͏ ΄͍͠ͷ͸ʜΨʔυϨʔϧ🚧

    ՝୊ ҎԼΛຬͨ͢Α͏ͳʮΨʔυϨʔϧʯ͕΄͍͠ʂ ✔ Α͋͘ΔϛεΛେ·͔ʹरͬͯ͘ΕΔ ✔ Ұਓͷ஌ݟΛνʔϜʹεέʔϧͤ͞ΒΕΔ ✔ ؾΛ͚ͭଓ͚ͳͯ͘΋ɺ໰୊Λػց͕ڭ͑ͯ͘ΕΔ ཧ૝ ஌͍ͬͯͯ΋஫ҙෆ଍Ͱ ੬ऑͳίʔυΛॻ͍ͯ͠·͏ ՝୊ ࣗ෼͸෼͔͍ͬͯΔ͕ɺ νʔϜʹ஌ݟ͕ਁಁ͠ͳ͍ ՝୊ ͦ΋ͦ΋ԿʹؾΛ͚ͭΔ΂͖͔Λ୭΋஌Βͳ͍·· ՝୊ c := &http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, }, }, }
  6. ˜TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛ੔උ͠Α͏  ΨʔυϨʔϧΛߏ੒͢ΔͨΊͷ ͭͷΞΫγϣϯ ஌͍ͬͯͯ΋஫ҙෆ଍Ͱ ੬ऑͳίʔυΛॻ͍ͯ͠·͏ ࣗ෼͸෼͔͍ͬͯΔ͕ɺ νʔϜʹ஌ݟ͕ਁಁ͠ͳ͍ ͦ΋ͦ΋ԿʹؾΛ͚ͭΔ΂͖

    ͔Λ୭΋஌Βͳ͍·· ՝୊ ·ͣ͸HPTFDͰΑ͋͘Δ ϛεΛݕग़Ͱ͖ΔΑ͏ʹ͢Δ HPSVMFHVBSE౳Λ׆༻ͯ͠ ஌ݟΛίʔυͱͯ͠஝ੵ͍ͯ͘͠ $*ʹHPTFD౳Λ഑ஔ͢Δ ॳظ͸SFWJFXEPHͷซ༻΋(PPE ΞΫγϣϯ
  7. ˜TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛ੔උ͠Α͏  ‣ యܕతͳ҆શͰͳ͍(PίʔυύλʔϯΛݕग़ͯ͘͠ΕΔπʔϧ ‣ HPMBOHDJMJOUܦ༝Ͱར༻Մೳ ‣ ,VCFSOFUFT΍$BEEZ౳ͷஶ໊ͳ(PϓϩδΣΫτͰ΋ར༻͞Ε͍ͯΔ HPTFD

    IUUQTHJUIVCDPNTFDVSFHPHPTFD $ gosec ./main.go [/app/main.go:6] - G404 (CWE-338): Use of weak random number generator (math/rand instead of crypto/rand) (Confidence: MEDIUM, Severity: HIGH) 5: func main() { > 6: sample := rand.Int() 7:
  8. ˜TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛ੔උ͠Α͏  ҆શͰͳ͍(PίʔυͷయܕྫΛݕग़Մೳ /* ... */ x := 0

    blah(unsafe.Pointer(x)) /* ... */ /* .... */ config = &tls.Config{ InsecureSkipVerify: true, }; /* .... */ ( ( HPTFD https://golang.org/pkg/math/rand (
  9. ˜TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛ੔උ͠Α͏  ‣ HP ܥύοέʔδ੡ ‣ HP ͸(Pඪ४ͷ੩తղੳ༻ͷύοέʔδ܈ ‣

    HPTFDͰ͸ओʹHPBTUʢߏจ໦पΓʣͱHPUZQFTʢܕपΓʣ͕ར༻͞Ε͍ͯΔ ‣ ֤ݕग़ϧʔϧ͸HP ͱHPTFDʹΑΔHP ͷUIJOXSBQQFSͰॻ͔ΕΔ HPTFDͷ͘͠Έ if ident, ok := n.Key.(*ast.Ident); ok { switch ident.Name { case "InsecureSkipVerify": if node, ok := n.Value.(*ast.Ident); ok { if node.Name != "false" { return gosec.NewIssue(c, n, t.ID(), "TLS InsecureSkipVerify set true.", gosec.High, gosec.High) } } // .... https://github.com/securego/gosec/blob/27a5ffb5c8f6dd3b6dea3b8e6019a2b3d43bf0f9/rules/tls.go#L64-L72
  10. ˜TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛ੔උ͠Α͏  ՝୊૊৫ݻ༗ͷϧʔϧ࡞੒ͰࠔΔ func applyUnsafeOpToDir(path string) error { /*

    ... */ } /* ... */ s := scanner.Text() applyUnsafeOpToDir("/etc") applyUnsafeOpToDir("/etc"+ "/gogogo") applyUnsafeOpToDir(s) ͦͦ͜͜ةͳ͍ؔ਺ ‣ QSJWBUFͳύοέʔδʹؔ͢ΔηΩϡϦςΟϧʔϧΛHPTFDʹ௥Ճ͢Δͷ͸ࠔ೉ ‣ 044ͳͷͰ૊৫ʹݻ༗ͷϧʔϧΛ࡞ͬͯ΋DPOUSJCVUFͰ͖ͳ͍ ‣ ҰԠHPTFDΛGPSLͯ͠ϝϯςφϯε͢Δͱ͍͏ख͸͋Δ͕ɺͭΒ͍ ‣ ࿑ྗ͸࠷খԽͭͭࣗ͠࡞-JOUFSΛ༻ҙͰ͖ͨΒخ͍͕͠ʜʜ ྫҾ਺͕ίϯύΠϧ ࣌ఆ਺Ͱͳ͍Մೳੑ͕ ͋Δ৔߹ʹܯࠂ͍ͨ͠
  11. ˜TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛ੔උ͠Α͏  ‣ (Pίʔυ޲͚ͷಠࣗ੩తղੳϧʔϧͷ࡞੒Λิॿ͢Δ-JOUFS ‣ ૊৫ಠࣗͷϧʔϧΛڧྗͳύλʔϯϚονϟʢETMύοέʔδʣΛ༻͍ͯهड़Ͱ͖Δ ‣ HPBOBMZTJT HPHSFQϕʔεͰ࡞੒͞Ε͍ͯΔ

    HPSVMFHVBSE IUUQTHJUIVCDPNRVBTJMZUFHPSVMFHVBSE m.Match(`copy($b, []byte($s))`). Where(m["s"].Type.Is(`string`)). Suggest(`copy($b, $s)`) sample := "test" copy(buf, []byte(sample)) ղੳϧʔϧͷྫ ݕग़͍ͨ͠அยͷྫ
  12. ˜TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛ੔උ͠Α͏  m.Match(`applyUnsafeOpToDir($x)`). Where(!m["x"].Const). Report(`$x should be a compile-time

    constant value`) func applyUnsafeOpToDir(path string) error { /* ... */ } /* ... */ s := scanner.Text() applyUnsafeOpToDir("/etc") applyUnsafeOpToDir("/etc"+ "/gogogo") applyUnsafeOpToDir(s) /app/main.go:39:2: permitOnlyConstant: s should be a compile-time constant value (rules.go:14) ղੳର৅ͷίʔυྫ ղੳϧʔϧͷྫ ղੳ݁Ռͷྫ ࠷ऴߦͷΑ͏ͳ ݺͼग़͠Λݕग़͍ͨ͠ʂ
  13. ˜TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛ੔උ͠Α͏  m.Match(`applyUnsafeOpToDir($x)`). Where(!m["x"].Const). Report(`$x should be a compile-time

    constant value`) func applyUnsafeOpToDir(path string) error { /* ... */ } /* ... */ s := scanner.Text() applyUnsafeOpToDir("/etc") applyUnsafeOpToDir("/etc"+ "/gogogo") applyUnsafeOpToDir(s) /app/main.go:39:2: permitOnlyConstant: s should be a compile-time constant value (rules.go:14) ղੳର৅ͷίʔυྫ ղੳϧʔϧͷྫ ղੳ݁Ռͷྫ
  14. ˜TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛ੔උ͠Α͏  m.Match(`applyUnsafeOpToDir($x)`). Where(!m["x"].Const). Report(`$x should be a compile-time

    constant value`) func applyUnsafeOpToDir(path string) error { /* ... */ } /* ... */ s := scanner.Text() applyUnsafeOpToDir("/etc") applyUnsafeOpToDir("/etc"+ "/gogogo") applyUnsafeOpToDir(s) /app/main.go:39:2: permitOnlyConstant: s should be a compile-time constant value (rules.go:14) ղੳର৅ͷίʔυྫ ղੳϧʔϧͷྫ ղੳ݁Ռͷྫ ^ \
  15. ˜TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛ੔උ͠Α͏  (PʹಛԽ͍ͯ͠Δ͔Βͦ͜ͷڧΈ΋ https://go-ruleguard.github.io/by-example/ m.Match(`fmt.Sprint($x)`). Where(m["x"].Type. Implements(`fmt.Stringer`)). Suggest(`$x.String()`) m.Match(`$x<$a

    && $x>$b`). Where(m["a"].Value.Int() <= m["b"].Value.Int()). Report("always false") ‣ HPSVMFHVBSE͸(PʹಛԽͯ͠࡞ΒΕ͍ͯΔ ‣ ͦͷͨΊྨࣅπʔϧͱൺ΂Δͱศརɾߴػೳ ‣ ίϯύΠϧ࣌ఆ਺ͷऔΓѻ͍ɺܕपΓͷऔΓѻ͍ɺʜ ܕ৘ใΛ༻͍ͨ ϧʔϧ ίϯύΠϧ࣌ఆ਺Λ ༻͍ͨϧʔϧ
  16. ˜TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛ੔උ͠Α͏  ܧଓతʹվળ͍ͯͨ͘͠Ίʹ ͜ͷखͷπʔϧͷಋೖ͸ॳظোน͕ߴ͍͕ʜʜ $ curl -sfL https://raw.githubusercontent.com/securego/gosec/ master/install.sh

    | sh -s -- -b $(go env GOPATH)/bin v2.7.0 $ gosec ./... /* ... */ Summary: Files: 77 Lines: 4034 Nosec: 0 Issues: 543 $ ʮ΋ͷౖ͍͢͝ΒΕͯΔͳɺಋೖ͸·ͨࠓ౓ߟ͑Δ͔ʜʯ
  17. ˜TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛ੔උ͠Α͏  ܧଓతʹվળ͍ͯͨ͘͠Ίʹ ͜ͷखͷπʔϧͷಋೖ͸ॳظোน͕ߴ͍͕ʜʜ $ curl -sfL https://raw.githubusercontent.com/securego/gosec/ master/install.sh

    | sh -s -- -b $(go env GOPATH)/bin v2.7.0 $ gosec ./main.go /* ... */ Summary: Files: 77 Lines: 4034 Nosec: 0 Issues: 543 $ ʮ΋ͷౖ͍͢͝ΒΕͯΔͳɺಋೖ͸·ͨࠓ౓ߟ͑Δ͔ʜʯ
  18. ˜TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛ੔උ͠Α͏  ,FZ5BLFBXBZT ஌͍ͬͯͯ΋஫ҙෆ଍Ͱ ੬ऑͳίʔυΛॻ͍ͯ͠·͏ ՝୊ ࣗ෼͸෼͔͍ͬͯΔ͕ɺ νʔϜʹ஌ݟ͕ਁಁ͠ͳ͍ ՝୊

    ͦ΋ͦ΋ԿʹؾΛ͚ͭΔ΂͖ ͔Λ୭΋஌Βͳ͍·· ՝୊ ·ͣ͸HPTFD͔Β࢝ΊΑ͏ HPSVMFHVBSE౳Λ׆༻Ͱ͖Δ $*ʹHPTFD౳Λ഑ஔͰ͖Δ ॳظ͸SFWJFXEPHͷซ༻΋(PPE &YBNQMFTBSFBWBJMBCMFBU IUUQTHJUIVCDPNTFDVSJUZBXBSFSFQPFYBNQMFT