3
0

More strict checking for ql operators

This prevents a couple of SQL injection attacks through QL
This commit is contained in:
Denis Arh
2020-12-09 11:11:42 +01:00
parent cf6f023454
commit 4c29350486
2 changed files with 81 additions and 13 deletions
+44 -4
View File
@@ -3,6 +3,7 @@ package ql
import (
"fmt"
"github.com/Masterminds/squirrel"
"strings"
)
// SelectStatement represents a SQL SELECT statement.
@@ -65,6 +66,29 @@ type (
}
)
var (
operators = map[string]bool{
`=`: true,
`!=`: true,
`<`: true,
`>`: true,
`>=`: true,
`<=`: true,
`<>`: true,
`+`: true,
`-`: true,
`*`: true,
`/`: true,
`AND`: true,
`OR`: true,
`XOR`: true,
`NOT LIKE`: true,
`LIKE`: true,
`IS`: true,
`IS NOT`: true,
}
)
func (n LNull) Validate() (err error) { return }
func (n LNull) String() string { return "NULL" }
@@ -83,8 +107,13 @@ func (n LString) String() string { return fmt.Sprintf("%q", n.Value) }
func (n LNumber) Validate() (err error) { return }
func (n LNumber) String() string { return n.Value }
func (n Operator) Validate() (err error) { return }
func (n Operator) String() string { return n.Kind }
func (n Operator) Validate() (err error) {
if !operators[strings.ToUpper(n.Kind)] {
return fmt.Errorf("unknown operator '%s'", n.Kind)
}
return
}
func (n Operator) String() string { return n.Kind }
func (n Keyword) Validate() (err error) { return }
func (n Keyword) String() string { return n.Keyword }
@@ -98,7 +127,10 @@ func (n Function) String() string { return fmt.Sprintf("%s(%s)", n.Name,
func (n Ident) Validate() (err error) { return }
func (n Ident) String() string { return n.Value }
func (n Column) Validate() (err error) { return }
func (n Column) Validate() (err error) {
return n.Expr.Validate()
}
func (n Column) String() (out string) {
out = n.Expr.String()
if n.Alias != "" {
@@ -158,7 +190,15 @@ func (nn ASTSet) String() (out string) {
return
}
func (nn Columns) Validate() (err error) { return }
func (nn Columns) Validate() (err error) {
for _, n := range nn {
if err = n.Validate(); err != nil {
return
}
}
return
}
func (nn Columns) String() (out string) {
for i, n := range nn {
if i > 0 {
+37 -9
View File
@@ -2,6 +2,7 @@ package ql
import (
"fmt"
"github.com/stretchr/testify/require"
"reflect"
"testing"
)
@@ -297,7 +298,7 @@ func TestAstParser_ColumnParser(t *testing.T) {
var tests = []struct {
in string
cols Columns
err error
err string
}{
{
in: `a AS b`,
@@ -370,15 +371,43 @@ func TestAstParser_ColumnParser(t *testing.T) {
},
},
},
{
in: `-- - DATE_FORMAT(some_date, '%Y-%m-01')`,
cols: Columns{
Column{
Expr: ASTNodes{
Function{
Name: "DATE_FORMAT",
Arguments: ASTSet{
Ident{Value: "some_date"},
LString{Value: "%Y-%m-01"},
},
},
},
},
},
err: "unknown operator '-- -'",
},
}
p := NewParser()
for i, test := range tests {
if cols, err := p.ParseColumns(test.in); err != test.err {
t.Fatalf("%d. %s: error mismatch:\n expected: %v\n got: %v\n\n", i, test.in, test.err, err)
} else if test.err == nil && !reflect.DeepEqual(test.cols, cols) {
t.Errorf("%d. %s\n\ncols does not match:\n\nexpected: %#v\n got: %#v\n\n", i, test.in, test.cols, cols)
}
for _, test := range tests {
t.Run(test.in, func(t *testing.T) {
var (
p = NewParser()
req = require.New(t)
)
cols, err := p.ParseColumns(test.in)
if test.err == "" {
req.NoError(err)
} else {
req.Error(err, test.err)
}
if err == nil {
req.Equal(test.cols, cols)
}
})
}
}
@@ -400,7 +429,6 @@ func TestAstParser_IdentModifier(t *testing.T) {
ident.Value = fmt.Sprintf("__wrap_%s_wrap__", ident.Value)
return ident, nil
}
if tree, err := p.ParseExpression(test.in); err != test.err {
t.Fatalf("%d. error mismatch:\n expected: %v\n got: %v\n\n", i, test.err, err)
} else if test.err == nil && test.out != tree.String() {