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