Skip to content

Commit c6fbf36

Browse files
committed
Server防SQL注入:createStatement改为prepareStatement
1 parent 5366aa8 commit c6fbf36

File tree

5 files changed

+104
-58
lines changed

5 files changed

+104
-58
lines changed

APIJSON-Java-Server/APIJSONDemo/src/main/java/apijson/demo/server/DemoSQLExecutor.java

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,13 @@
1616

1717
import java.sql.Connection;
1818
import java.sql.DriverManager;
19+
import java.sql.PreparedStatement;
1920
import java.sql.ResultSet;
2021
import java.sql.SQLException;
21-
import java.sql.Statement;
22+
import java.util.List;
2223

2324
import javax.validation.constraints.NotNull;
2425

25-
import com.alibaba.fastjson.JSONObject;
26-
2726
import zuo.biao.apijson.Log;
2827
import zuo.biao.apijson.server.AbstractSQLExecutor;
2928
import zuo.biao.apijson.server.SQLConfig;
@@ -47,40 +46,57 @@ public class DemoSQLExecutor extends AbstractSQLExecutor {
4746

4847

4948

50-
private SQLConfig config = null;
51-
@Override
52-
public JSONObject execute(SQLConfig config) throws Exception {
53-
this.config = config;
54-
return super.execute(config);
55-
}
56-
5749

5850
@Override
59-
public ResultSet executeQuery(@NotNull String sql) throws Exception {
60-
return getStatement().executeQuery(sql);
51+
public ResultSet executeQuery(@NotNull SQLConfig config) throws Exception {
52+
return getStatement(config).executeQuery();
6153
}
6254

6355
@Override
64-
public int executeUpdate(@NotNull String sql) throws Exception {
65-
return getStatement().executeUpdate(sql);
56+
public int executeUpdate(@NotNull SQLConfig config) throws Exception {
57+
return getStatement(config).executeUpdate();
6658
}
6759

6860

6961
private Connection connection = null;
70-
private Statement statement = null;
62+
private PreparedStatement statement = null;
7163
/**
64+
* @param config
7265
* @return
7366
* @throws Exception
7467
*/
75-
private Statement getStatement() throws Exception {
68+
private PreparedStatement getStatement(@NotNull SQLConfig config) throws Exception {
7669
if (connection == null || connection.isClosed()) {
7770
Log.i(TAG, "select connection " + (connection == null ? " = null" : ("isClosed = " + connection.isClosed()))) ;
7871

7972
connection = DriverManager.getConnection(config.getDBUri() + "?useUnicode=true&characterEncoding=UTF-8&user="
8073
+ config.getDBAccount() + "&password=" + config.getDBPassword());
81-
82-
statement = connection.createStatement(); //创建Statement对象
8374
}
75+
76+
// statement = connection.prepareStatement("SELECT ?,? FROM sys.apijson_user WHERE sex=? AND id IN (?,?,?)"); //创建Statement对象
77+
//// Object[] values = config.getWhere().values().toArray();
78+
//// if (values != null && values.length > 0) {
79+
//// for (int i = 0; i < values.length; i++) {
80+
//// statement.setObject(i + 1, values[i]);
81+
//// }
82+
//// }
83+
//
84+
// statement.setObject(1, "id");
85+
// statement.setObject(2, "name");
86+
// statement.setObject(3, 0);
87+
// statement.setObject(4, 82001);
88+
// statement.setObject(5, 82002);
89+
// statement.setObject(6, 38710);
90+
91+
statement = connection.prepareStatement(config.getSQL(true)); //创建Statement对象
92+
List<Object> valueList = config.getPreparedValues();
93+
if (valueList != null && valueList.isEmpty() == false) {
94+
for (int i = 0; i < valueList.size(); i++) {
95+
statement.setString(i + 1, "" + valueList.get(i));
96+
}
97+
}
98+
99+
84100
return statement;
85101
}
86102

@@ -100,7 +116,6 @@ public void close() {
100116
} catch (SQLException e) {
101117
e.printStackTrace();
102118
}
103-
config = null;
104119
statement = null;
105120
connection = null;
106121
}

APIJSON-Java-Server/APIJSONLibrary/src/main/java/zuo/biao/apijson/server/AbstractSQLConfig.java

Lines changed: 60 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ public abstract class AbstractSQLConfig implements SQLConfig {
7979

8080
private long id; //Table的id
8181
private RequestMethod method; //操作方法
82+
private boolean prepared; //预编译
8283
/**
8384
* TODO 被关联的表通过就忽略关联的表?(这个不行 User:{"sex@":"/Comment/toId"})
8485
*/
@@ -131,7 +132,12 @@ public AbstractSQLConfig setMethod(RequestMethod method) {
131132
this.method = method;
132133
return this;
133134
}
134-
135+
public boolean isPrepared() {
136+
return prepared;
137+
}
138+
public void setPrepared(boolean prepared) {
139+
this.prepared = prepared;
140+
}
135141

136142

137143
@Override
@@ -306,7 +312,7 @@ public String getColumnString() throws NotExistException {
306312
return column.contains(":") == false ? column : column.replaceAll(":", " AS ");//不能在这里改,后续还要用到:
307313
}
308314
}
309-
315+
310316

311317
@Override
312318
public String getValues() {
@@ -513,31 +519,31 @@ public String getWhereString() throws Exception {
513519
* @return
514520
* @throws Exception
515521
*/
516-
public static String getWhereString(RequestMethod method, Map<String, Object> where, boolean verifyName) throws Exception {
522+
public String getWhereString(RequestMethod method, Map<String, Object> where, boolean verifyName) throws Exception {
517523
Map<String, Object> where2 = where == null || where.isEmpty() ? null : new LinkedHashMap<String, Object>();
518524
if (where2 == null) {
519525
return "";
520526
}
521-
527+
522528
//强制排序,把id,id{},userId,userId{}放最前面,保证安全、优化性能
523529
Object id = where.remove(KEY_ID);
524530
Object idIn = where.remove(KEY_ID_IN);
525531
Object userId = where.remove(KEY_USER_ID);
526532
Object userIdIn = where.remove(KEY_USER_ID_IN);
527-
533+
528534
where2.put(KEY_ID, id);
529535
where2.put(KEY_ID_IN, idIn);
530536
where2.put(KEY_USER_ID, userId);
531537
where2.put(KEY_USER_ID_IN, userIdIn);
532538
where2.putAll(where);
533-
534-
539+
540+
535541
Set<Entry<String, Object>> set = where2.entrySet();
536-
542+
537543
boolean isFirst = true;
538544
String condition;
539545
String whereString = "";
540-
546+
541547
for (Entry<String, Object> entry : set) {
542548
if (entry == null) {
543549
continue;
@@ -552,19 +558,19 @@ public static String getWhereString(RequestMethod method, Map<String, Object> wh
552558

553559
isFirst = false;
554560
}
555-
561+
556562
//还原where,后续可能用到
557563
where.put(KEY_ID, id);
558564
where.put(KEY_ID_IN, idIn);
559565
where.put(KEY_USER_ID, userId);
560566
where.put(KEY_USER_ID_IN, userIdIn);
561567

562568
String s = whereString.isEmpty() ? "" : " WHERE " + whereString;
563-
569+
564570
if (s.isEmpty() && RequestMethod.isQueryMethod(method) == false) {
565571
throw new UnsupportedOperationException("写操作请求必须带条件!!!");
566572
}
567-
573+
568574
return s;
569575
}
570576

@@ -576,7 +582,7 @@ public static String getWhereString(RequestMethod method, Map<String, Object> wh
576582
* @return
577583
* @throws Exception
578584
*/
579-
private static String getWhereItem(String key, Object value
585+
private String getWhereItem(String key, Object value
580586
, RequestMethod method, boolean verifyName) throws Exception {
581587
Log.d(TAG, "getWhereItem key = " + key);
582588
//避免筛选到全部 value = key == null ? null : where.get(key);
@@ -618,18 +624,39 @@ else if (key.endsWith("<>")) {
618624
case 4:
619625
return getContainString(key, value);
620626
default: //TODO MySQL JSON类型的字段对比 key='[]' 会无结果! key LIKE '[1, 2, 3]' //TODO MySQL , 后面有空格!
621-
return (key + "='" + value + "'");
627+
return getEqualString(key, value);
622628
}
623629
}
624630

625631

632+
private String getEqualString(String key, Object value) {
633+
return (key + "=" + getValue(value));
634+
}
635+
636+
637+
/**
638+
* 使用prepareStatement预编译,值为 ? ,后续动态set进去
639+
*/
640+
private List<Object> preparedValues = new ArrayList<>();
641+
private Object getValue(@NotNull Object value) {
642+
if (isPrepared()) {
643+
preparedValues.add(value);
644+
return "?";
645+
}
646+
return "'" + value + "'";
647+
}
648+
@Override
649+
public List<Object> getPreparedValues() {
650+
return preparedValues;
651+
}
652+
626653
//$ search <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
627654
/**search key match value
628655
* @param in
629656
* @return {@link #getSearchString(String, Object[], int)}
630657
* @throws IllegalArgumentException
631658
*/
632-
public static String getSearchString(String key, Object value) throws IllegalArgumentException {
659+
public String getSearchString(String key, Object value) throws IllegalArgumentException {
633660
if (value == null) {
634661
return "";
635662
}
@@ -649,7 +676,7 @@ public static String getSearchString(String key, Object value) throws IllegalArg
649676
* @return LOGIC [ key LIKE 'values[i]' ]
650677
* @throws IllegalArgumentException
651678
*/
652-
public static String getSearchString(String key, Object[] values, int type) throws IllegalArgumentException {
679+
public String getSearchString(String key, Object[] values, int type) throws IllegalArgumentException {
653680
if (values == null || values.length <= 0) {
654681
return "";
655682
}
@@ -670,8 +697,8 @@ public static String getSearchString(String key, Object[] values, int type) thro
670697
* @param value
671698
* @return key LIKE 'value'
672699
*/
673-
public static String getLikeString(String key, Object value) {
674-
return key + " LIKE '" + value + "'";
700+
public String getLikeString(String key, Object value) {
701+
return key + " LIKE " + getValue(value);
675702
}
676703
//$ search >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
677704

@@ -683,7 +710,7 @@ public static String getLikeString(String key, Object value) {
683710
* @return {@link #getRegExpString(String, Object[], int)}
684711
* @throws IllegalArgumentException
685712
*/
686-
public static String getRegExpString(String key, Object value) throws IllegalArgumentException {
713+
public String getRegExpString(String key, Object value) throws IllegalArgumentException {
687714
if (value == null) {
688715
return "";
689716
}
@@ -703,7 +730,7 @@ public static String getRegExpString(String key, Object value) throws IllegalArg
703730
* @return LOGIC [ key REGEXP 'values[i]' ]
704731
* @throws IllegalArgumentException
705732
*/
706-
public static String getRegExpString(String key, Object[] values, int type) throws IllegalArgumentException {
733+
public String getRegExpString(String key, Object[] values, int type) throws IllegalArgumentException {
707734
if (values == null || values.length <= 0) {
708735
return "";
709736
}
@@ -724,8 +751,8 @@ public static String getRegExpString(String key, Object[] values, int type) thro
724751
* @param value
725752
* @return key REGEXP 'value'
726753
*/
727-
public static String getRegExpString(String key, String value) {
728-
return key + " REGEXP '" + value + "'";
754+
public String getRegExpString(String key, String value) {
755+
return key + " REGEXP " + getValue(value);
729756
}
730757
//$ search >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
731758

@@ -738,7 +765,7 @@ public static String getRegExpString(String key, String value) {
738765
* @return key condition0 AND key condition1 AND ...
739766
* @throws Exception
740767
*/
741-
public static String getRangeString(String key, Object range) throws Exception {
768+
public String getRangeString(String key, Object range) throws Exception {
742769
Log.i(TAG, "getRangeString key = " + key);
743770
if (range == null) {//依赖的对象都没有给出有效值,这个存在无意义。如果是客户端传的,那就能在客户端确定了。
744771
throw new NotExistException(TAG + "getRangeString(" + key + ", " + range
@@ -781,11 +808,11 @@ public static String getRangeString(String key, Object range) throws Exception {
781808
* @return IN ('key0', 'key1', ... )
782809
* @throws NotExistException
783810
*/
784-
public static String getInString(String key, Object[] in, boolean not) throws NotExistException {
811+
public String getInString(String key, Object[] in, boolean not) throws NotExistException {
785812
String condition = "";
786813
if (in != null) {//返回 "" 会导致 id:[] 空值时效果和没有筛选id一样!
787814
for (int i = 0; i < in.length; i++) {
788-
condition += ((i > 0 ? "," : "") + "'" + in[i] + "'");
815+
condition += ((i > 0 ? "," : "") + getValue(in[i]));
789816
}
790817
}
791818
if (condition.isEmpty()) {//条件如果存在必须执行,不能忽略。条件为空会导致出错,又很难保证条件不为空(@:条件),所以还是这样好
@@ -804,7 +831,7 @@ public static String getInString(String key, Object[] in, boolean not) throws No
804831
* @return {@link #getContainString(String, Object[], int)}
805832
* @throws NotExistException
806833
*/
807-
public static String getContainString(String key, Object value) throws NotExistException {
834+
public String getContainString(String key, Object value) throws NotExistException {
808835
if (value == null) {
809836
return "";
810837
}
@@ -824,7 +851,7 @@ public static String getContainString(String key, Object value) throws NotExistE
824851
* OR key LIKE '%, " + childs[i] + ", %' OR key LIKE '%, " + childs[i] + "]' ) ]
825852
* @throws IllegalArgumentException
826853
*/
827-
public static String getContainString(String key, Object[] childs, int type) throws IllegalArgumentException {
854+
public String getContainString(String key, Object[] childs, int type) throws IllegalArgumentException {
828855
boolean not = Logic.isNot(type);
829856
String condition = "";
830857
if (childs != null) {
@@ -837,7 +864,7 @@ public static String getContainString(String key, Object[] childs, int type) thr
837864
childs[i] = "\"" + childs[i] + "\"";
838865
}
839866
condition += (i <= 0 ? "" : (Logic.isAnd(type) ? AND : OR))
840-
+ "JSON_CONTAINS(" + key + ", '" + childs[i] + "')";
867+
+ "JSON_CONTAINS(" + key + ", " + getValue(childs[i]) + ")";
841868
}
842869
}
843870
if (condition.isEmpty()) {
@@ -861,7 +888,7 @@ public static String getContainString(String key, Object[] childs, int type) thr
861888
private static String getCondition(boolean not, String condition) {
862889
return not ? NOT + "(" + condition + ")" : condition;
863890
}
864-
891+
865892

866893
/**转为JSONArray
867894
* @param tv
@@ -971,7 +998,8 @@ public static String getRemoveString(String key, Object value) throws IllegalArg
971998
*/
972999
@JSONField(serialize = false)
9731000
@Override
974-
public String getSQL() throws Exception {
1001+
public String getSQL(boolean prepared) throws Exception {
1002+
setPrepared(prepared);
9751003
return getSQL(this);
9761004
}
9771005
/**
@@ -1340,8 +1368,8 @@ else if (key.endsWith("-")) {//缩减,PUT查询时处理
13401368
Log.i(TAG, "getRealKey return key = " + key);
13411369
return key;
13421370
}
1343-
1344-
1371+
1372+
13451373
public interface Callback {
13461374
AbstractSQLConfig getSQLConfig(RequestMethod method, String table);
13471375
}

0 commit comments

Comments
 (0)