More strict checking for ql operators
This prevents a couple of SQL injection attacks through QL
This commit is contained in:
+44
-4
@@ -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 {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user