Fixed SQL injections with ORDER BY and GROUP BY.
This commit is contained in:
parent
bf413d67d3
commit
037aaa8973
103
example/example.go
Normal file
103
example/example.go
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
"github.com/jinzhu/gorm"
|
||||||
|
_ "github.com/lib/pq"
|
||||||
|
_ "github.com/mattn/go-sqlite3"
|
||||||
|
)
|
||||||
|
|
||||||
|
var db gorm.DB
|
||||||
|
|
||||||
|
// Profile ...
|
||||||
|
type Profile struct {
|
||||||
|
gorm.Model
|
||||||
|
Name string `sql:"type:varchar(40);not null"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// User ...
|
||||||
|
type User struct {
|
||||||
|
gorm.Model
|
||||||
|
Username string `sql:"type:varchar(100);not null;unique"`
|
||||||
|
UserProfiles []*UserProfile
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserProfile ...
|
||||||
|
type UserProfile struct {
|
||||||
|
gorm.Model
|
||||||
|
ProfileID sql.NullInt64 `sql:"index;not null"`
|
||||||
|
UserID sql.NullInt64 `sql:"index;not null"`
|
||||||
|
Profile *Profile
|
||||||
|
User *User
|
||||||
|
State string `sql:"index;not null"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
var err error
|
||||||
|
db, err = gorm.Open("sqlite3", ":memory:")
|
||||||
|
// db, err := gorm.Open("postgres", "user=username dbname=password sslmode=disable")
|
||||||
|
// db, err := gorm.Open("mysql", "user:password@/dbname?charset=utf8&parseTime=True")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
db.LogMode(true)
|
||||||
|
|
||||||
|
db.AutoMigrate(new(Profile), new(User), new(UserProfile))
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
buyerProfile := &Profile{Name: "buyer"}
|
||||||
|
if err := db.Create(buyerProfile).Error; err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
sellerProfile := &Profile{Name: "seller"}
|
||||||
|
if err := db.Create(sellerProfile).Error; err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
user := &User{
|
||||||
|
Username: "username",
|
||||||
|
UserProfiles: []*UserProfile{
|
||||||
|
&UserProfile{
|
||||||
|
Profile: buyerProfile,
|
||||||
|
State: "some_state",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if err := db.Create(user).Error; err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now let's update the user
|
||||||
|
tx := db.Begin()
|
||||||
|
|
||||||
|
user.Username = "username_edited"
|
||||||
|
|
||||||
|
user.UserProfiles = append(
|
||||||
|
user.UserProfiles,
|
||||||
|
&UserProfile{
|
||||||
|
Profile: sellerProfile,
|
||||||
|
State: "some_state",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := tx.Model(user).Association("UserProfiles").Append(&UserProfile{
|
||||||
|
Profile: sellerProfile,
|
||||||
|
State: "some_state",
|
||||||
|
}).Error; err != nil {
|
||||||
|
tx.Rollback() // rollback the transaction
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// if err := tx.Save(user).Error; err != nil {
|
||||||
|
// tx.Rollback() // rollback the transaction
|
||||||
|
// panic(err)
|
||||||
|
// }
|
||||||
|
|
||||||
|
if err := tx.Commit().Error; err != nil {
|
||||||
|
tx.Rollback() // rollback the transaction
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
@ -62,12 +62,12 @@ func (s *search) Assign(attrs ...interface{}) *search {
|
|||||||
func (s *search) Order(value string, reorder ...bool) *search {
|
func (s *search) Order(value string, reorder ...bool) *search {
|
||||||
if len(reorder) > 0 && reorder[0] {
|
if len(reorder) > 0 && reorder[0] {
|
||||||
if value != "" {
|
if value != "" {
|
||||||
s.orders = []string{value}
|
s.orders = []string{s.db.dialect.Quote(value)}
|
||||||
} else {
|
} else {
|
||||||
s.orders = []string{}
|
s.orders = []string{}
|
||||||
}
|
}
|
||||||
} else if value != "" {
|
} else if value != "" {
|
||||||
s.orders = append(s.orders, value)
|
s.orders = append(s.orders, s.db.dialect.Quote(value))
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
@ -93,7 +93,7 @@ func (s *search) Offset(offset int) *search {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *search) Group(query string) *search {
|
func (s *search) Group(query string) *search {
|
||||||
s.group = s.getInterfaceAsSQL(query)
|
s.group = s.db.dialect.Quote(s.getInterfaceAsSQL(query))
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
29
sql_injection_test.go
Normal file
29
sql_injection_test.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package gorm_test
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestOrderSQLInjection(t *testing.T) {
|
||||||
|
DB.AutoMigrate(new(User))
|
||||||
|
|
||||||
|
DB.Save(&User{Name: "jinzhu"})
|
||||||
|
|
||||||
|
var users []*User
|
||||||
|
DB.Order("id;delete from users;commit;").Find(&users)
|
||||||
|
|
||||||
|
if len(users) != 1 {
|
||||||
|
t.Error("Seems like it's possible to use SQL injection with ORDER BY")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGroupSQLInjection(t *testing.T) {
|
||||||
|
DB.AutoMigrate(new(User))
|
||||||
|
|
||||||
|
DB.Save(&User{Name: "jinzhu"})
|
||||||
|
|
||||||
|
var users []*User
|
||||||
|
DB.Group("name;delete from users;commit;").Find(&users)
|
||||||
|
|
||||||
|
if len(users) != 1 {
|
||||||
|
t.Error("Seems like it's possible to use SQL injection with GROUP BY")
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user