73 lines
3.1 KiB
Go
73 lines
3.1 KiB
Go
package mysqlproxy
|
|
|
|
import "testing"
|
|
|
|
func TestReadOnlyMonitoringQueries(t *testing.T) {
|
|
wave := `SELECT id, code, startPickUploadSts, startPickUploadRetryCount,
|
|
pickingGuideUploadSts, pickingGuideUploadRetryCount, completeTaskUploadSts, completeTaskUploadRetryCount
|
|
FROM shopee_wave WHERE created >= FROM_UNIXTIME(?) AND created < FROM_UNIXTIME(?)
|
|
AND (startPickUploadSts = 950 OR pickingGuideUploadSts = 950 OR completeTaskUploadSts = 950)
|
|
ORDER BY created DESC,id DESC LIMIT 200`
|
|
allowed := []string{
|
|
"SELECT UNIX_TIMESTAMP('2026-10-12 00:00:00'), TIME_TO_SEC('00:00:05'), SEC_TO_TIME(5), LEFT('abc', 2)",
|
|
`EXPLAIN FORMAT=TRADITIONAL SELECT thread_id,UNIX_TIMESTAMP(start_time),CAST(TIME_TO_SEC(query_time) AS CHAR),
|
|
db,LEFT(CONVERT(sql_text USING utf8mb4),2000),rows_examined,rows_sent
|
|
FROM mysql.slow_log WHERE start_time>=FROM_UNIXTIME(?) AND start_time<FROM_UNIXTIME(?) AND db=DATABASE() AND query_time>=SEC_TO_TIME(?)
|
|
ORDER BY start_time DESC LIMIT 200`,
|
|
"SELECT FROM_UNIXTIME(0)",
|
|
"SELECT FROM_UNIXTIME(0, '%Y-%m-%d')",
|
|
"SELECT CHAR(39)",
|
|
"SELECT CHAR(65, 66 USING utf8mb4)",
|
|
"SELECT SUBSTRING_INDEX('a@b', '@', 1)",
|
|
wave,
|
|
"EXPLAIN " + wave,
|
|
"EXPLAIN FORMAT=TRADITIONAL " + wave,
|
|
`SELECT COUNT(*) FROM information_schema.USER_PRIVILEGES
|
|
WHERE PRIVILEGE_TYPE IN ('INSERT','UPDATE','DELETE','CREATE','DROP','ALTER','SUPER','GRANT OPTION')
|
|
AND GRANTEE=CONCAT(CHAR(39),SUBSTRING_INDEX(CURRENT_USER(),'@',1),CHAR(39),'@',CHAR(39),SUBSTRING_INDEX(CURRENT_USER(),'@',-1),CHAR(39))`,
|
|
"SELECT @@version,@@slow_query_log,@@log_output,CAST(@@long_query_time AS CHAR)",
|
|
`SELECT TABLE_NAME,COUNT(*) FROM information_schema.STATISTICS
|
|
WHERE TABLE_SCHEMA=DATABASE() AND SEQ_IN_INDEX=1 AND
|
|
((TABLE_NAME='shopee_wave' AND COLUMN_NAME='created') OR (TABLE_NAME='location_inventory' AND COLUMN_NAME='lastUpdated')) GROUP BY TABLE_NAME`,
|
|
}
|
|
for _, query := range allowed {
|
|
t.Run(query, func(t *testing.T) {
|
|
if err := CheckReadOnly(query); err != nil {
|
|
t.Fatalf("read-only monitoring query rejected: %v", err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestReadOnlyMonitoringFunctionsStillCheckArguments(t *testing.T) {
|
|
denied := []string{
|
|
"SELECT UNIX_TIMESTAMP(SLEEP(1))",
|
|
"SELECT TIME_TO_SEC(LOAD_FILE('/tmp/time'))",
|
|
"SELECT SEC_TO_TIME(GET_LOCK('x', 1))",
|
|
"SELECT LEFT('abc', (SELECT SLEEP(1)))",
|
|
"SELECT app.unix_timestamp()",
|
|
"SELECT app.time_to_sec('00:00:05')",
|
|
"SELECT app.sec_to_time(5)",
|
|
"SELECT app.left('abc', 2)",
|
|
"SELECT FROM_UNIXTIME(SLEEP(1))",
|
|
"SELECT FROM_UNIXTIME(0, LOAD_FILE('/tmp/format'))",
|
|
"SELECT CHAR(SLEEP(1))",
|
|
"SELECT CHAR(65, (SELECT SLEEP(1)) USING utf8mb4)",
|
|
"SELECT CHAR(@x := 65)",
|
|
"SELECT SUBSTRING_INDEX(LOAD_FILE('/tmp/file'), '@', 1)",
|
|
"SELECT SUBSTRING_INDEX('a@b', '@', GET_LOCK('x', 1))",
|
|
"SELECT app.from_unixtime(0)",
|
|
"SELECT app.substring_index('a@b', '@', 1)",
|
|
"EXPLAIN ANALYZE SELECT FROM_UNIXTIME(0)",
|
|
"EXPLAIN FORMAT=TRADITIONAL SELECT CHAR(SLEEP(1))",
|
|
"SELECT CHAR(65); DELETE FROM t",
|
|
}
|
|
for _, query := range denied {
|
|
t.Run(query, func(t *testing.T) {
|
|
if err := CheckReadOnly(query); err == nil {
|
|
t.Fatal("unsafe query accepted")
|
|
}
|
|
})
|
|
}
|
|
}
|