-
-
Notifications
You must be signed in to change notification settings - Fork 486
Open
Description
Hi!
I found a tricky case that should probably be known about, but I couldn't find the information.
TLDR> validation is breaking due to problems in json/v1 with case insensitivity, which allows you to bypass validation.
It's easier to explain with an example:
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"net/http"
"strings"
"github.com/getkin/kin-openapi/openapi3"
"github.com/getkin/kin-openapi/openapi3filter"
"github.com/getkin/kin-openapi/routers/gorillamux"
)
var schema = `openapi: 3.0.0
info:
title: Test API
version: 1.0.0
paths:
/test:
post:
requestBody:
content:
application/json:
schema:
type: object
properties:
value:
type: string
enum:
- "aniki"
responses:
'204':
description: OK
`
var examples = []struct {
name string
body string
}{
{"good", `{"value": "aniki"}`},
{"bad", `{"value": "beniki"}`},
{"evil", `{"value": "aniki", "Value": "beniki"}`},
{"chaotic evil", `{"Value": "beniki", "vaLue": "chaos"}`},
}
type ValueObj struct {
Value string `json:"value"`
}
func main() {
ctx := context.Background()
loader := &openapi3.Loader{Context: ctx, IsExternalRefsAllowed: true}
doc, err := loader.LoadFromData([]byte(schema))
if err != nil {
log.Fatal("load schema: ", err)
}
err = doc.Validate(ctx)
if err != nil {
log.Fatal("validate schema: ", err)
}
router, err := gorillamux.NewRouter(doc)
if err != nil {
log.Fatal("create router: ", err)
}
for _, ex := range examples {
httpReq, _ := http.NewRequest(http.MethodPost, "/test", strings.NewReader(ex.body))
httpReq.Header.Set("Content-Type", "application/json")
route, pathParams, _ := router.FindRoute(httpReq)
requestValidationInput := &openapi3filter.RequestValidationInput{
Request: httpReq,
PathParams: pathParams,
Route: route,
}
err := openapi3filter.ValidateRequest(ctx, requestValidationInput)
if err != nil {
fmt.Println(ex.name, "failed:", err)
} else {
fmt.Println(ex.name, "passed")
}
var val ValueObj
err = json.Unmarshal([]byte(ex.body), &val)
if err != nil {
log.Fatal("unmarshal: ", err)
}
fmt.Printf("%s value: %+v\n", ex.name, val)
fmt.Println("-----")
}
}output:
good passed
good value: {Value:aniki}
-----
bad failed: request body has an error: doesn't match schema: Error at "/value": value is not one of the allowed values ["aniki"]
Schema:
{
"enum": [
"aniki"
],
"type": "string"
}
Value:
"beniki"
bad value: {Value:beniki}
-----
evil passed
evil value: {Value:beniki}
-----
chaotic evil passed
chaotic evil value: {Value:chaos}
-----
As you can see, you can slip in any value and bypass the validation. This means that in many cases it is not worth relying on validation.
https://github.com/getkin/kin-openapi/blob/master/openapi3/schema.go#L1999
It seems we need to fix the code here a bit to solve this problem. You need to add an option to reduce all names to the same case.
go.mod
go 1.25.5
require github.com/getkin/kin-openapi v0.133.0
Metadata
Metadata
Assignees
Labels
No labels