sql.go 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. package sql
  2. import (
  3. "context"
  4. "fmt"
  5. "strings"
  6. "github.com/xwb1989/sqlparser"
  7. )
  8. var SafeSqlFunc = []string{
  9. "SUM", "AVG", "MAX", "MIN", "COUNT", "CONCAT", "SUBSTRING", "CHAR_LENGTH",
  10. "LOWER", "UPPER", "NOW", "DATE_FORMAT", "DATE_ADD", "DATEDIFF", "ABS",
  11. "CEIL", "FLOOR", "EXP", "LOG", "AND", "OR", "NOT", "CAST", "CONVERT",
  12. "COALESCE", "NULLIF",
  13. }
  14. type Record struct {
  15. Msg string `json:"msg"`
  16. }
  17. func CheckSQL(ctx context.Context, sqlQuery string) (bool, string, error) {
  18. stmt, err := sqlparser.Parse(sqlQuery)
  19. if err != nil {
  20. return false, err.Error(), err
  21. }
  22. r := &Record{}
  23. return checkStmt(ctx, stmt, r), r.Msg, nil
  24. }
  25. func checkStmt(ctx context.Context, stmt sqlparser.Statement, r *Record) bool {
  26. if stmt == nil {
  27. return true
  28. }
  29. switch stmt := stmt.(type) {
  30. case *sqlparser.Select:
  31. for _, i := range stmt.SelectExprs {
  32. if !checkSelectExpr(ctx, i, r) {
  33. return false
  34. }
  35. }
  36. for _, i := range stmt.From {
  37. if !checkTableExpr(ctx, i, r) {
  38. return false
  39. }
  40. }
  41. if stmt.Where != nil {
  42. if !checkExpr(ctx, stmt.Where.Expr, r) {
  43. return false
  44. }
  45. }
  46. for _, g := range stmt.GroupBy {
  47. if !checkExpr(ctx, g, r) {
  48. return false
  49. }
  50. }
  51. if stmt.Having != nil {
  52. if !checkExpr(ctx, stmt.Having.Expr, r) {
  53. return false
  54. }
  55. }
  56. for _, o := range stmt.OrderBy {
  57. if o == nil {
  58. continue
  59. }
  60. if !checkExpr(ctx, o.Expr, r) {
  61. return false
  62. }
  63. }
  64. if stmt.Limit != nil {
  65. if !checkExpr(ctx, stmt.Limit.Offset, r) {
  66. return false
  67. }
  68. if !checkExpr(ctx, stmt.Limit.Rowcount, r) {
  69. return false
  70. }
  71. }
  72. default:
  73. r.Msg = "bad stmt operation"
  74. return false
  75. }
  76. return true
  77. }
  78. func checkTableExpr(ctx context.Context, expr sqlparser.TableExpr, r *Record) bool {
  79. if expr == nil {
  80. return true
  81. }
  82. switch expr := expr.(type) {
  83. case *sqlparser.AliasedTableExpr:
  84. return checkSimpleTableExpr(ctx, expr.Expr, r)
  85. case *sqlparser.ParenTableExpr:
  86. for _, e := range expr.Exprs {
  87. if !checkTableExpr(ctx, e, r) {
  88. return false
  89. }
  90. }
  91. return true
  92. case *sqlparser.JoinTableExpr:
  93. if !checkTableExpr(ctx, expr.LeftExpr, r) {
  94. return false
  95. }
  96. if !checkTableExpr(ctx, expr.RightExpr, r) {
  97. return false
  98. }
  99. if !checkExpr(ctx, expr.Condition.On, r) {
  100. return false
  101. }
  102. return true
  103. }
  104. r.Msg = "bad table expr"
  105. return false
  106. }
  107. func checkExpr(ctx context.Context, expr sqlparser.Expr, r *Record) bool {
  108. if expr == nil {
  109. return true
  110. }
  111. switch expr := expr.(type) {
  112. default:
  113. return false
  114. case *sqlparser.AndExpr:
  115. if !checkExpr(ctx, expr.Left, r) {
  116. return false
  117. }
  118. if !checkExpr(ctx, expr.Right, r) {
  119. return false
  120. }
  121. case *sqlparser.OrExpr:
  122. if !checkExpr(ctx, expr.Left, r) {
  123. return false
  124. }
  125. if !checkExpr(ctx, expr.Right, r) {
  126. return false
  127. }
  128. case *sqlparser.NotExpr:
  129. if !checkExpr(ctx, expr.Expr, r) {
  130. return false
  131. }
  132. case *sqlparser.ParenExpr:
  133. if !checkExpr(ctx, expr.Expr, r) {
  134. return false
  135. }
  136. case *sqlparser.ComparisonExpr:
  137. if !checkExpr(ctx, expr.Left, r) {
  138. return false
  139. }
  140. if !checkExpr(ctx, expr.Right, r) {
  141. return false
  142. }
  143. if !checkExpr(ctx, expr.Escape, r) {
  144. return false
  145. }
  146. case *sqlparser.RangeCond:
  147. if !checkExpr(ctx, expr.Left, r) {
  148. return false
  149. }
  150. if !checkExpr(ctx, expr.From, r) {
  151. return false
  152. }
  153. if !checkExpr(ctx, expr.To, r) {
  154. return false
  155. }
  156. case *sqlparser.IsExpr:
  157. if !checkExpr(ctx, expr.Expr, r) {
  158. return false
  159. }
  160. case *sqlparser.ExistsExpr:
  161. if !checkExpr(ctx, expr.Subquery, r) {
  162. return false
  163. }
  164. case *sqlparser.SQLVal:
  165. // 可以
  166. case *sqlparser.NullVal:
  167. // 可以
  168. case sqlparser.BoolVal:
  169. // 可以
  170. case *sqlparser.ColName:
  171. // 检查ColName
  172. case sqlparser.ValTuple:
  173. for _, e := range expr {
  174. if !checkExpr(ctx, e, r) {
  175. return false
  176. }
  177. }
  178. case *sqlparser.Subquery:
  179. if !checkStmt(ctx, expr.Select, r) {
  180. return false
  181. }
  182. case sqlparser.ListArg:
  183. // 可以
  184. case *sqlparser.BinaryExpr:
  185. if !checkExpr(ctx, expr.Left, r) {
  186. return false
  187. }
  188. if !checkExpr(ctx, expr.Right, r) {
  189. return false
  190. }
  191. case *sqlparser.UnaryExpr:
  192. if !checkExpr(ctx, expr.Expr, r) {
  193. return false
  194. }
  195. case *sqlparser.IntervalExpr:
  196. if !checkExpr(ctx, expr.Expr, r) {
  197. return false
  198. }
  199. case *sqlparser.CollateExpr:
  200. if !checkExpr(ctx, expr.Expr, r) {
  201. return false
  202. }
  203. case *sqlparser.FuncExpr:
  204. if !checkFuncName(ctx, expr.Qualifier.String(), expr.Name.String(), r) {
  205. return false
  206. }
  207. for _, s := range expr.Exprs {
  208. if !checkSelectExpr(ctx, s, r) {
  209. return false
  210. }
  211. }
  212. case *sqlparser.CaseExpr:
  213. if !checkExpr(ctx, expr.Expr, r) {
  214. return false
  215. }
  216. if !checkExpr(ctx, expr.Else, r) {
  217. return false
  218. }
  219. for _, w := range expr.Whens {
  220. if w == nil {
  221. continue
  222. }
  223. if !checkExpr(ctx, w.Cond, r) {
  224. return false
  225. }
  226. if !checkExpr(ctx, w.Val, r) {
  227. return false
  228. }
  229. }
  230. case *sqlparser.ValuesFuncExpr:
  231. r.Msg = "bad values expr"
  232. return false // values表达式用于插入
  233. case *sqlparser.ConvertExpr:
  234. if !checkExpr(ctx, expr.Expr, r) {
  235. return false
  236. }
  237. case *sqlparser.SubstrExpr:
  238. if !checkExpr(ctx, expr.From, r) {
  239. return false
  240. }
  241. if !checkExpr(ctx, expr.To, r) {
  242. return false
  243. }
  244. if !checkColName(ctx, expr.Name, r) {
  245. return false
  246. }
  247. case *sqlparser.ConvertUsingExpr:
  248. if !checkExpr(ctx, expr.Expr, r) {
  249. return false
  250. }
  251. case *sqlparser.MatchExpr:
  252. if !checkExpr(ctx, expr.Expr, r) {
  253. return false
  254. }
  255. for _, s := range expr.Columns {
  256. if !checkSelectExpr(ctx, s, r) {
  257. return false
  258. }
  259. }
  260. case *sqlparser.GroupConcatExpr:
  261. for _, s := range expr.Exprs {
  262. if !checkSelectExpr(ctx, s, r) {
  263. return false
  264. }
  265. }
  266. for _, o := range expr.OrderBy {
  267. if o == nil {
  268. continue
  269. }
  270. if !checkExpr(ctx, o.Expr, r) {
  271. return false
  272. }
  273. }
  274. case *sqlparser.Default:
  275. if !checkColNameString(ctx, expr.ColName, r) {
  276. return false
  277. }
  278. }
  279. return true
  280. }
  281. func checkSimpleTableExpr(ctx context.Context, expr sqlparser.SimpleTableExpr, r *Record) bool {
  282. if expr == nil {
  283. return true
  284. }
  285. switch expr := expr.(type) {
  286. case sqlparser.TableName:
  287. return checkTableName(ctx, expr, r)
  288. case *sqlparser.Subquery:
  289. return checkStmt(ctx, expr.Select, r)
  290. }
  291. r.Msg = "bad simple table expr"
  292. return false
  293. }
  294. func checkSelectExpr(ctx context.Context, expr sqlparser.SelectExpr, r *Record) bool {
  295. if expr == nil {
  296. return true
  297. }
  298. switch expr := expr.(type) {
  299. case *sqlparser.StarExpr:
  300. return checkTableName(ctx, expr.TableName, r)
  301. case *sqlparser.AliasedExpr:
  302. return checkExpr(ctx, expr.Expr, r)
  303. case sqlparser.Nextval:
  304. return checkExpr(ctx, expr.Expr, r)
  305. }
  306. r.Msg = "bad select expr"
  307. return false
  308. }
  309. func checkTableName(ctx context.Context, tableName sqlparser.TableName, r *Record) bool {
  310. if tableName.IsEmpty() {
  311. return true
  312. }
  313. allowTableName, ok := ctx.Value("Allow-Table-Name").([]string)
  314. if ok && !tableName.Name.IsEmpty() && !InList(allowTableName, tableName.Name.String()) {
  315. r.Msg = fmt.Sprintf("bad table name for %s", tableName.Name.String())
  316. return false
  317. }
  318. allowDBName, ok := ctx.Value("Allow-DataBase-Name").([]string)
  319. if ok {
  320. if !tableName.Qualifier.IsEmpty() && !InList(allowDBName, tableName.Qualifier.String()) {
  321. r.Msg = fmt.Sprintf("bad table qualifier for %s", tableName.Qualifier.String())
  322. return false
  323. }
  324. } else {
  325. if !tableName.Qualifier.IsEmpty() {
  326. r.Msg = fmt.Sprintf("bad table qualifier for %s", tableName.Qualifier.String())
  327. return false
  328. }
  329. }
  330. return true
  331. }
  332. func checkColName(ctx context.Context, colname *sqlparser.ColName, r *Record) bool {
  333. if !checkTableName(ctx, colname.Qualifier, r) {
  334. return false
  335. }
  336. return checkColNameString(ctx, colname.Name.String(), r)
  337. }
  338. func checkColNameString(ctx context.Context, colname string, r *Record) bool {
  339. if len(colname) == 0 {
  340. return true
  341. }
  342. allowColName, ok := ctx.Value("Allow-Col-Name").([]string)
  343. if ok && !InList(allowColName, colname) && !InList(allowColName, fmt.Sprintf("`%s`", colname)) {
  344. r.Msg = fmt.Sprintf("bad table col for %s", colname)
  345. return false
  346. }
  347. return true
  348. }
  349. func checkFuncName(ctx context.Context, ident string, funcName string, r *Record) bool {
  350. if len(funcName) == 0 && len(ident) == 0 {
  351. return false
  352. }
  353. if len(ident) != 0 {
  354. allowColIdent, ok := ctx.Value("Allow-Func-Ident").([]string)
  355. if ok && !InList(allowColIdent, ident) {
  356. r.Msg = fmt.Sprintf("bad func ident for %s", ident)
  357. return false
  358. }
  359. }
  360. allowColName, ok := ctx.Value("Allow-Func-Name").([]string)
  361. if ok && !InList(allowColName, strings.ToUpper(funcName)) {
  362. r.Msg = fmt.Sprintf("bad func name for %s", funcName)
  363. return false
  364. } else if !ok {
  365. r.Msg = fmt.Sprintf("bad func name for %s", funcName)
  366. return false
  367. }
  368. return true
  369. }
  370. func InList[T string | int64](lst []T, element T) bool {
  371. for _, i := range lst {
  372. if i == element {
  373. return true
  374. }
  375. }
  376. return false
  377. }