Share
Embed
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
Transcript
29 slides
-
TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛඋ͠Α͏ ͋Εɺ͜Εͬͯ҆શ͚ͩͬʜʜ /* ... */ x := 0
blah(unsafe.Pointer(x)) /* ... */ -
TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛඋ͠Α͏ ͋Εɺ͜Εͬͯ҆શ͚ͩͬʜʜ /* ... */ x := 0
blah(unsafe.Pointer(x)) /* ... */ /* .... */ config = &tls.Config{ InsecureSkipVerify: true, }; /* .... */ -
TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛඋ͠Α͏ ͋Εɺ͜Εͬͯ҆શ͚ͩͬʜʜ /* ... */ x := 0
blah(unsafe.Pointer(x)) /* ... */ /* .... */ config = &tls.Config{ InsecureSkipVerify: true, }; /* .... */ https://golang.org/pkg/math/rand -
TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛඋ͠Α͏ ͋͋ɺ҆શͳίʔυΛॻ͘ͷർΕΔ ʜʜͦΕ͕ͨͱ͑(PͰ͋ͬͯʂ /* ... */ x :=
0 blah(unsafe.Pointer(x)) /* ... */ /* .... */ config = &tls.Config{ InsecureSkipVerify: true, }; /* .... */ https://golang.org/pkg/math/rand -
TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛඋ͠Α͏ ৫ͷίʔυΛηΩϡΞʹอ্ͭͰͷ՝ ͍ͬͯͯҙෆͰ ੬ऑͳίʔυΛॻ͍ͯ͠·͏ ՝ ͔͍ࣗͬͯΔ͕ɺ νʔϜʹݟ͕ਁಁ͠ͳ͍ ՝
ͦͦԿʹؾΛ͚ͭΔ͖ ͔Λ୭Βͳ͍·· ՝ c := &http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, }, }, } -
TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛඋ͠Α͏ ৫ͷίʔυΛηΩϡΞʹอ্ͭͰͷ՝ ͍ͬͯͯҙෆͰ ੬ऑͳίʔυΛॻ͍ͯ͠·͏ ՝ ͔͍ࣗͬͯΔ͕ɺ νʔϜʹݟ͕ਁಁ͠ͳ͍ ՝
ͦͦԿʹؾΛ͚ͭΔ͖ ͔Λ୭Βͳ͍·· ՝ c := &http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, }, }, } -
TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛඋ͠Α͏ ৫ͷίʔυΛηΩϡΞʹอ্ͭͰͷ՝ ͍ͬͯͯҙෆͰ ੬ऑͳίʔυΛॻ͍ͯ͠·͏ ՝ ͔͍ࣗͬͯΔ͕ɺ νʔϜʹݟ͕ਁಁ͠ͳ͍ ՝
ͦͦԿʹؾΛ͚ͭΔ͖ ͔Λ୭Βͳ͍·· ՝ c := &http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, }, }, } -
TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛඋ͠Α͏ ͦͦԿʹؾΛ͚ͭΔ͖͔Λ୭Βͳ͍·· ͔͍ࣗͬͯΔ͕ɺνʔϜʹݟ͕ਁಁ͠ͳ͍ ͍ͬͯͯҙෆͰ੬ऑͳίʔυΛॻ͍ͯ͠·͏ ΄͍͠ͷʜ
՝ ͍ͬͯͯҙෆͰ ੬ऑͳίʔυΛॻ͍ͯ͠·͏ ՝ ͔͍ࣗͬͯΔ͕ɺ νʔϜʹݟ͕ਁಁ͠ͳ͍ ՝ ͦͦԿʹؾΛ͚ͭΔ͖͔Λ୭Βͳ͍·· ՝ c := &http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, }, }, } -
TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛඋ͠Α͏ ͦͦԿʹؾΛ͚ͭΔ͖͔Λ୭Βͳ͍·· ͔͍ࣗͬͯΔ͕ɺνʔϜʹݟ͕ਁಁ͠ͳ͍ ͍ͬͯͯҙෆͰ੬ऑͳίʔυΛॻ͍ͯ͠·͏ ΄͍͠ͷʜΨʔυϨʔϧ🚧
՝ ҎԼΛຬͨ͢Α͏ͳʮΨʔυϨʔϧʯ͕΄͍͠ʂ ✔ Α͋͘ΔϛεΛେ·͔ʹरͬͯ͘ΕΔ ✔ ҰਓͷݟΛνʔϜʹεέʔϧͤ͞ΒΕΔ ✔ ؾΛ͚ͭଓ͚ͳͯ͘ɺΛػց͕ڭ͑ͯ͘ΕΔ ཧ ͍ͬͯͯҙෆͰ ੬ऑͳίʔυΛॻ͍ͯ͠·͏ ՝ ͔͍ࣗͬͯΔ͕ɺ νʔϜʹݟ͕ਁಁ͠ͳ͍ ՝ ͦͦԿʹؾΛ͚ͭΔ͖͔Λ୭Βͳ͍·· ՝ c := &http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, }, }, } -
TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛඋ͠Α͏ ΨʔυϨʔϧΛߏ͢ΔͨΊͷ ͭͷΞΫγϣϯ ͍ͬͯͯҙෆͰ ੬ऑͳίʔυΛॻ͍ͯ͠·͏ ͔͍ࣗͬͯΔ͕ɺ νʔϜʹݟ͕ਁಁ͠ͳ͍ ͦͦԿʹؾΛ͚ͭΔ͖
͔Λ୭Βͳ͍·· ՝ ·ͣHPTFDͰΑ͋͘Δ ϛεΛݕग़Ͱ͖ΔΑ͏ʹ͢Δ HPSVMFHVBSEΛ׆༻ͯ͠ ݟΛίʔυͱͯ͠ੵ͍ͯ͘͠ $*ʹHPTFDΛஔ͢Δ ॳظSFWJFXEPHͷซ༻(PPE ΞΫγϣϯ -
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: -
TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛඋ͠Α͏ ҆શͰͳ͍(PίʔυͷయܕྫΛݕग़Մೳ /* ... */ x := 0
blah(unsafe.Pointer(x)) /* ... */ /* .... */ config = &tls.Config{ InsecureSkipVerify: true, }; /* .... */ ( ( HPTFD https://golang.org/pkg/math/rand ( -
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 -
TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛඋ͠Α͏ ՝৫ݻ༗ͷϧʔϧ࡞ͰࠔΔ func applyUnsafeOpToDir(path string) error { /*
... */ } /* ... */ s := scanner.Text() applyUnsafeOpToDir("/etc") applyUnsafeOpToDir("/etc"+ "/gogogo") applyUnsafeOpToDir(s) ͦͦ͜͜ةͳ͍ؔ ‣ QSJWBUFͳύοέʔδʹؔ͢ΔηΩϡϦςΟϧʔϧΛHPTFDʹՃ͢Δͷࠔ ‣ 044ͳͷͰ৫ʹݻ༗ͷϧʔϧΛ࡞ͬͯDPOUSJCVUFͰ͖ͳ͍ ‣ ҰԠHPTFDΛGPSLͯ͠ϝϯςφϯε͢Δͱ͍͏ख͋Δ͕ɺͭΒ͍ ‣ ࿑ྗ࠷খԽͭͭࣗ͠࡞-JOUFSΛ༻ҙͰ͖ͨΒخ͍͕͠ʜʜ ྫҾ͕ίϯύΠϧ ࣌ఆͰͳ͍Մೳੑ͕ ͋Δ߹ʹܯࠂ͍ͨ͠ -
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)) ղੳϧʔϧͷྫ ݕग़͍ͨ͠அยͷྫ -
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) ղੳରͷίʔυྫ ղੳϧʔϧͷྫ ղੳ݁Ռͷྫ ࠷ऴߦͷΑ͏ͳ ݺͼग़͠Λݕग़͍ͨ͠ʂ -
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) ղੳରͷίʔυྫ ղੳϧʔϧͷྫ ղੳ݁Ռͷྫ -
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) ղੳରͷίʔυྫ ղੳϧʔϧͷྫ ղੳ݁Ռͷྫ ^ \ -
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ʹಛԽͯ͠࡞ΒΕ͍ͯΔ ‣ ͦͷͨΊྨࣅπʔϧͱൺΔͱศརɾߴػೳ ‣ ίϯύΠϧ࣌ఆͷऔΓѻ͍ɺܕपΓͷऔΓѻ͍ɺʜ ܕใΛ༻͍ͨ ϧʔϧ ίϯύΠϧ࣌ఆΛ ༻͍ͨϧʔϧ -
TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛඋ͠Α͏ ܧଓతʹվળ͍ͯͨ͘͠Ίʹ ͜ͷखͷπʔϧͷಋೖॳظোน͕ߴ͍͕ʜʜ $ curl -sfL https://raw.githubusercontent.com/securego/gosec/ master/install.sh
| sh -s -- -b $(go env GOPATH)/bin v2.7.0 $ gosec ./... ʮࢼ͠ʹͬͯΈΑ͏ʂʯ -
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 $ ʮͷౖ͍͢͝ΒΕͯΔͳɺಋೖ·ͨࠓߟ͑Δ͔ʜʯ -
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 $ ʮͷౖ͍͢͝ΒΕͯΔͳɺಋೖ·ͨࠓߟ͑Δ͔ʜʯ -
TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛඋ͠Α͏ ‣ ֤छ-JOUFSπʔϧͷग़ྗΛίϝϯτͱͯ͠ߘͯ͘͠ΕΔ(Pπʔϧ ‣ (JU)VCͰͷࠩϨϏϡʔ࣌ʹɺࠩ෦ͷΈͷ-JOU݁ՌΛڭ͑ͯ͘ΕΔ ‣ πʔϧͷ'BMTF1PTJUJWFཱ͕ͭ߹Ͱɺదʹʹͭ͘ͱ͜ΖͰҙשىͰ͖Δ ‣
ίʔυશମʹରͯ͠େྔͷΞϥʔτ͕ग़ΔڥͰɺஈ֊తʹվળΛ࢝ΊΒΕΔ SFWJFXEPH🐾 IUUQTHJUIVCDPNSFWJFXEPHSFWJFXEPH ͜ͷ෦ͷݕࠪ݁ՌΛ ίϝϯτͱͯ͠ߘ ͜ͷ෦ͷݕࠪ݁Ռ Ұ୴ࣺͯΔ -
TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛඋ͠Α͏ ,FZ5BLFBXBZT ͍ͬͯͯҙෆͰ ੬ऑͳίʔυΛॻ͍ͯ͠·͏ ՝ ͔͍ࣗͬͯΔ͕ɺ νʔϜʹݟ͕ਁಁ͠ͳ͍ ՝
ͦͦԿʹؾΛ͚ͭΔ͖ ͔Λ୭Βͳ͍·· ՝ ·ͣHPTFD͔Β࢝ΊΑ͏ HPSVMFHVBSEΛ׆༻Ͱ͖Δ $*ʹHPTFDΛஔͰ͖Δ ॳظSFWJFXEPHͷซ༻(PPE &YBNQMFTBSFBWBJMBCMFBU IUUQTHJUIVCDPNTFDVSJUZBXBSFSFQPFYBNQMFT -
TIJGUKTJOGP (PΛηΩϡΞʹॻ͖ਐΊΔͨΊͷʮΨʔυϨʔϧʯΛඋ͠Α͏ ‣ େྔͷ(PQIFS͘Μͨͪ ‣ .BSJB-FUUBGSFFHPQIFSTQBDL ‣ IUUQTHJUIVCDPN.BSJB-FUUBGSFFHPQIFSTQBDL ‣
ΨʔυϨʔϧͷΠϥετ ‣ ͍Β͢ͱ ‣ IUUQTXXXJSBTVUPZBDPNCMPHQPTU@IUNM "QQFOEJYը૾ͷग़ࣗ