|
|
|
@ -4,6 +4,7 @@ Package system runs system-level testing of rqlite. This includes testing of sin
|
|
|
|
|
package system
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"testing"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
@ -174,6 +175,106 @@ func Test_SingleParameterizedNode(t *testing.T) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Test_SingleNodeSQLInjection demonstrates that using the non-parameterized API is vulnerable to
|
|
|
|
|
// SQL injection attacks.
|
|
|
|
|
func Test_SingleNodeSQLInjection(t *testing.T) {
|
|
|
|
|
node := mustNewLeaderNode()
|
|
|
|
|
defer node.Deprovision()
|
|
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
|
stmt string
|
|
|
|
|
expected string
|
|
|
|
|
execute bool
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
stmt: `CREATE TABLE foo (id integer not null primary key, name text)`,
|
|
|
|
|
expected: `{"results":[{}]}`,
|
|
|
|
|
execute: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
stmt: `SELECT * FROM foo WHERE name="baz"`,
|
|
|
|
|
expected: `{"results":[{"columns":["id","name"],"types":["integer","text"]}]}`,
|
|
|
|
|
execute: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
stmt: fmt.Sprintf(`SELECT * FROM foo WHERE name=%s`, `"baz";DROP TABLE FOO`),
|
|
|
|
|
expected: `{"results":[{}]}`,
|
|
|
|
|
execute: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
stmt: `SELECT * FROM foo`,
|
|
|
|
|
expected: `{"results":[{"error":"no such table: foo"}]}`,
|
|
|
|
|
execute: false,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for i, tt := range tests {
|
|
|
|
|
var r string
|
|
|
|
|
var err error
|
|
|
|
|
if tt.execute {
|
|
|
|
|
r, err = node.Execute(tt.stmt)
|
|
|
|
|
} else {
|
|
|
|
|
r, err = node.Query(tt.stmt)
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf(`test %d failed "%s": %s`, i, tt.stmt, err.Error())
|
|
|
|
|
}
|
|
|
|
|
if r != tt.expected {
|
|
|
|
|
t.Fatalf(`test %d received wrong result "%s" got: %s exp: %s`, i, tt.stmt, r, tt.expected)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Test_SingleNodeNoSQLInjection demonstrates that using the parameterized API protects
|
|
|
|
|
// against SQL injection attacks.
|
|
|
|
|
func Test_SingleNodeNoSQLInjection(t *testing.T) {
|
|
|
|
|
node := mustNewLeaderNode()
|
|
|
|
|
defer node.Deprovision()
|
|
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
|
stmt []interface{}
|
|
|
|
|
expected string
|
|
|
|
|
execute bool
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
stmt: []interface{}{"CREATE TABLE foo (id integer not null primary key, name text)"},
|
|
|
|
|
expected: `{"results":[{}]}`,
|
|
|
|
|
execute: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
stmt: []interface{}{`SELECT * FROM foo WHERE name="baz"`},
|
|
|
|
|
expected: `{"results":[{"columns":["id","name"],"types":["integer","text"]}]}`,
|
|
|
|
|
execute: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
stmt: []interface{}{`SELECT * FROM foo WHERE name=?`, `"baz";DROP TABLE FOO`},
|
|
|
|
|
expected: `{"results":[{"columns":["id","name"],"types":["integer","text"]}]}`,
|
|
|
|
|
execute: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
stmt: []interface{}{`SELECT * FROM foo`},
|
|
|
|
|
expected: `{"results":[{"columns":["id","name"],"types":["integer","text"]}]}`,
|
|
|
|
|
execute: false,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for i, tt := range tests {
|
|
|
|
|
var r string
|
|
|
|
|
var err error
|
|
|
|
|
if tt.execute {
|
|
|
|
|
r, err = node.ExecuteParameterized(tt.stmt)
|
|
|
|
|
} else {
|
|
|
|
|
r, err = node.QueryParameterized(tt.stmt)
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf(`test %d failed "%s": %s`, i, tt.stmt, err.Error())
|
|
|
|
|
}
|
|
|
|
|
if r != tt.expected {
|
|
|
|
|
t.Fatalf(`test %d received wrong result "%s" got: %s exp: %s`, i, tt.stmt, r, tt.expected)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Test_SingleNodeCoverage(t *testing.T) {
|
|
|
|
|
node := mustNewLeaderNode()
|
|
|
|
|
defer node.Deprovision()
|
|
|
|
|