Skip to content

Commit 0aad761

Browse files
committed
Server:新增对批量新增 Table[]:[{}] 的校验,修复任意批量新增其它表的安全漏洞;新增对 DATE, TIME, DATETIME 及对应数组的类型校验;删除废弃的大驼峰命名的校验类型
1 parent 779309c commit 0aad761

File tree

1 file changed

+94
-22
lines changed
  • APIJSON-Java-Server/APIJSONORM/src/main/java/apijson/server

1 file changed

+94
-22
lines changed

APIJSON-Java-Server/APIJSONORM/src/main/java/apijson/server/Structure.java

Lines changed: 94 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727
import static apijson.server.Operation.VERIFY;
2828

2929
import java.net.URL;
30+
import java.time.LocalDate;
31+
import java.time.LocalDateTime;
32+
import java.time.LocalTime;
3033
import java.util.ArrayList;
3134
import java.util.Arrays;
3235
import java.util.Collection;
@@ -104,7 +107,7 @@ public static JSONObject parseRequest(@NotNull final RequestMethod method, final
104107
// }
105108

106109
//解析
107-
return parse(name, target, request, creator, new OnParseCallback() {
110+
return parse(method, name, target, request, creator, new OnParseCallback() {
108111

109112
@Override
110113
public JSONObject onParseJSONObject(String key, JSONObject tobj, JSONObject robj) throws Exception {
@@ -128,6 +131,20 @@ public JSONObject onParseJSONObject(String key, JSONObject tobj, JSONObject robj
128131

129132
return parseRequest(method, key, tobj, robj, maxUpdateCount, creator);
130133
}
134+
135+
@Override
136+
protected JSONArray onParseJSONArray(String key, JSONArray tarray, JSONArray rarray) throws Exception {
137+
if (method == RequestMethod.POST && JSONRequest.isArrayKey(key)) {
138+
if (rarray == null || rarray.isEmpty()) {
139+
throw new IllegalArgumentException(method.name() + "请求,请在 " + name + " 内传 " + key + ":[{}] ,批量新增 Table[]:value 中 value 必须是包含表对象的非空数组!");
140+
}
141+
if (rarray.size() > maxUpdateCount) {
142+
throw new IllegalArgumentException(method + "请求," + name + "/" + key
143+
+ " 里面的 " + key + ":[{}] 中[]的长度不能超过 " + maxUpdateCount + " !");
144+
}
145+
}
146+
return super.onParseJSONArray(key, tarray, rarray);
147+
}
131148
});
132149

133150
}
@@ -205,7 +222,7 @@ public static JSONObject parseResponse(@NotNull final RequestMethod method, fina
205222
}
206223

207224
//解析
208-
return parse(name, target, response, creator, callback != null ? callback : new OnParseCallback() {});
225+
return parse(method, name, target, response, creator, callback != null ? callback : new OnParseCallback() {});
209226
}
210227

211228

@@ -217,7 +234,7 @@ public static JSONObject parseResponse(@NotNull final RequestMethod method, fina
217234
* @return
218235
* @throws Exception
219236
*/
220-
public static JSONObject parse(String name, JSONObject target, JSONObject real
237+
public static JSONObject parse(@NotNull final RequestMethod method, String name, JSONObject target, JSONObject real
221238
, SQLCreator creator, @NotNull OnParseCallback callback) throws Exception {
222239
if (target == null) {
223240
return null;
@@ -297,6 +314,9 @@ public static JSONObject parse(String name, JSONObject target, JSONObject real
297314
objKeySet.add(key);
298315
} else if (tvalue instanceof JSONArray) {//JSONArray
299316
tvalue = callback.onParseJSONArray(key, (JSONArray) tvalue, (JSONArray) rvalue);
317+
if (method == RequestMethod.POST && JSONRequest.isArrayKey(key)) {
318+
objKeySet.add(key);
319+
}
300320
} else {//其它Object
301321
tvalue = callback.onParseObject(key, tvalue, rvalue);
302322
}
@@ -343,7 +363,7 @@ public static JSONObject parse(String name, JSONObject target, JSONObject real
343363
real.remove(rk);
344364
continue;
345365
}
346-
366+
347367
Object rv = real.get(rk);
348368

349369
//不允许传远程函数,只能后端配置
@@ -352,8 +372,13 @@ public static JSONObject parse(String name, JSONObject target, JSONObject real
352372
}
353373

354374
//不在target内的 key:{}
355-
if (rk.startsWith("@") == false && objKeySet.contains(rk) == false && rv instanceof JSONObject) {
356-
throw new UnsupportedOperationException(name + " 里面不允许传 " + rk + ":{} !");
375+
if (rk.startsWith("@") == false && objKeySet.contains(rk) == false) {
376+
if (rv instanceof JSONObject) {
377+
throw new UnsupportedOperationException(name + " 里面不允许传 " + rk + ":{} !");
378+
}
379+
if (method == RequestMethod.POST && rv instanceof JSONArray && JSONRequest.isArrayKey(rk)) {
380+
throw new UnsupportedOperationException("POST 请求," + name + " 里面不允许 " + rk + ":[] 等未定义的 Table[]:[{}] 批量操作键值对!");
381+
}
357382
}
358383
}
359384
//判断不允许传的key>>>>>>>>>>>>>>>>>>>>>>>>>
@@ -380,7 +405,7 @@ public static JSONObject parse(String name, JSONObject target, JSONObject real
380405
}
381406
//校验重复>>>>>>>>>>>>>>>>>>>
382407

383-
408+
384409
//还原 <<<<<<<<<<
385410
target.put(TYPE.name(), type);
386411
target.put(VERIFY.name(), verify);
@@ -393,7 +418,7 @@ public static JSONObject parse(String name, JSONObject target, JSONObject real
393418
target.put(NECESSARY.name(), necessary);
394419
target.put(DISALLOW.name(), disallow);
395420
//还原 >>>>>>>>>>
396-
421+
397422
Log.i(TAG, "parse return real = " + JSON.toJSONString(real));
398423
return real;
399424
}
@@ -475,34 +500,32 @@ public static void type(@NotNull String tk, @NotNull String tv, Object rv) throw
475500
if (rv == null) {
476501
return;
477502
}
478-
503+
479504
switch (tv) {
480-
case "BOOLEAN":
481-
case "Boolean": // @Deprecated,用 BOOLEAN 替代,最快在 4.0.0 移除,请尽快修改 Request 表 structure 字段对应值里的 Boolean
482-
//Boolean.parseBoolean(real.getString(tk)); 只会判断null和true
505+
case "BOOLEAN": //Boolean.parseBoolean(real.getString(tk)); 只会判断null和true
483506
if (rv instanceof Boolean == false) { //JSONObject.getBoolean 可转换Number类型
484507
throw new UnsupportedDataTypeException(tk + ":value 的value不合法!类型必须是 BOOLEAN !");
485508
}
486509
break;
487-
case "NUMBER": // 整数
488-
case "Long": // @Deprecated,用 Number 替代,最快在 4.0.0 移除,请尽快修改 Request 表 structure 字段对应值里的 Long
510+
case "NUMBER": //整数
489511
try {
490512
Long.parseLong(rv.toString()); //1.23会转换为1 real.getLong(tk);
491513
} catch (Exception e) {
492514
throw new UnsupportedDataTypeException(tk + ":value 的value不合法!类型必须是 NUMBER !");
493515
}
494516
break;
495-
case "DECIMAL": // 小数
496-
case "Double": // @Deprecated,用 Decimal 替代,最快在 4.0.0 移除,请尽快修改 Request 表 structure 字段对应值里的 Double
517+
case "DECIMAL": //小数
497518
try {
498519
Double.parseDouble(rv.toString());
499520
} catch (Exception e) {
500521
throw new UnsupportedDataTypeException(tk + ":value 的value不合法!类型必须是 DECIMAL !");
501522
}
502523
break;
503524
case "STRING":
504-
case "String": // @Deprecated,用 STRING 替代,最快在 4.0.0 移除,请尽快修改 Request 表 structure 字段对应值里的 String
505525
case "URL":
526+
case "DATE":
527+
case "TIME":
528+
case "DATETIME":
506529
if (rv instanceof String == false) { //JSONObject.getString 可转换任何类型
507530
throw new UnsupportedDataTypeException(tk + ":value 的value不合法!类型必须是 STRING !");
508531
}
@@ -513,17 +536,36 @@ public static void type(@NotNull String tk, @NotNull String tv, Object rv) throw
513536
throw new UnsupportedDataTypeException(tk + ":value 的value不合法!类型必须是 URL !");
514537
}
515538
}
539+
else if (tv.equals("DATE")) {
540+
try {
541+
LocalDate.parse((String) rv);
542+
} catch (Exception e) {
543+
throw new UnsupportedDataTypeException(tk + ":value 的value不合法!类型必须是格式为 YYYY-MM-DD(例如 2020-02-20)的 DATE !");
544+
}
545+
}
546+
else if (tv.equals("TIME")) {
547+
try {
548+
LocalTime.parse((String) rv);
549+
} catch (Exception e) {
550+
throw new UnsupportedDataTypeException(tk + ":value 的value不合法!类型必须是格式为 HH:mm:ss(例如 12:01:30)的 TIME !");
551+
}
552+
}
553+
else if (tv.equals("DATETIME")) {
554+
try {
555+
LocalDateTime.parse((String) rv);
556+
} catch (Exception e) {
557+
throw new UnsupportedDataTypeException(tk + ":value 的value不合法!类型必须是格式为 YYYY-MM-DDTHH:mm:ss(例如 2020-02-20T12:01:30)的 DATETIME !");
558+
}
559+
}
516560
break;
517561
case "OBJECT":
518-
case "Object": // @Deprecated,用 OBJECT 替代,最快在 4.0.0 移除,请尽快修改 Request 表 structure 字段对应值里的 Object
519562
if (rv instanceof Map == false) { //JSONObject.getJSONObject 可转换String类型
520563
throw new UnsupportedDataTypeException(tk + ":value 的value不合法!类型必须是 OBJECT !");
521564
}
522565
break;
523566
default:
524567
switch (tv) {
525568
case "ARRAY":
526-
case "Array": // @Deprecated,用 ARRAY 替代,最快在 4.0.0 移除,请尽快修改 Request 表 structure 字段对应值里的 Array
527569
if (rv instanceof Collection == false) { //JSONObject.getJSONArray 可转换String类型
528570
throw new UnsupportedDataTypeException(tk + ":value 的value不合法!类型必须是 ARRAY !");
529571
}
@@ -578,6 +620,36 @@ public static void type(@NotNull String tk, @NotNull String tv, Object rv) throw
578620
}
579621
}
580622
break;
623+
case "DATE[]":
624+
type(tk, "ARRAY", rv);
625+
for (Object o : (Collection<?>) rv) {
626+
try {
627+
type(tk, "DATE", o);
628+
} catch (UnsupportedDataTypeException e) {
629+
throw new UnsupportedDataTypeException(tk + ":value 的value不合法!类型必须是 DATE[] !");
630+
}
631+
}
632+
break;
633+
case "TIME[]":
634+
type(tk, "ARRAY", rv);
635+
for (Object o : (Collection<?>) rv) {
636+
try {
637+
type(tk, "TIME", o);
638+
} catch (UnsupportedDataTypeException e) {
639+
throw new UnsupportedDataTypeException(tk + ":value 的value不合法!类型必须是 TIME[] !");
640+
}
641+
}
642+
break;
643+
case "DATETIME[]":
644+
type(tk, "ARRAY", rv);
645+
for (Object o : (Collection<?>) rv) {
646+
try {
647+
type(tk, "DATETIME", o);
648+
} catch (UnsupportedDataTypeException e) {
649+
throw new UnsupportedDataTypeException(tk + ":value 的value不合法!类型必须是 DATETIME[] !");
650+
}
651+
}
652+
break;
581653
//目前在业务表中还用不上,单一的类型校验已经够用
582654
// case "JSON":
583655
// try {
@@ -591,11 +663,11 @@ public static void type(@NotNull String tk, @NotNull String tv, Object rv) throw
591663
default:
592664
throw new UnsupportedDataTypeException(
593665
"服务器内部错误,类型 " + tv + " 不合法!Request表校验规则中 TYPE:{ key:value } 中的 value 必须是"
594-
+ " [ BOOLEAN, NUMBER, DECIMAL, STRING, URL, OBJECT, ARRAY, BOOLEAN[], NUMBER[], DECIMAL[], STRING[], URL[] ] 中的一个!");
666+
+ " [ BOOLEAN, NUMBER, DECIMAL, STRING, URL, OBJECT, ARRAY, BOOLEAN[], NUMBER[], DECIMAL[], STRING[], URL[] ] 中的一个!");
595667
}
596-
668+
597669
}
598-
670+
599671
}
600672

601673

0 commit comments

Comments
 (0)