二、异常日志
(一)异常处理
第1条
这句话读起来有点拗口,实际上就是写一段代码我们知道他会出现空指针数值越界的形式的情况,就应该通过条件判断等形式处理,像解析json这种需要用异常捕获的就应该用异常捕获。
第6条
补充一下try-with-resouces的一些信息。
- try-with-resouces会自动关闭资源,但是该资源类(object)必须实现java.lang.AutoCloseable接口,比如BufferedReader使用此语句就可以自动关闭资源;
- 关闭资源顺序和打开顺序相反;
- 还可以使用catch和finally,但是catch和finally会在资源关闭后才运行;
简单的try-with-resouces语法如下; - JDK 还在改进此功能,比如在JDK9中如果有一个资源是final或者等效于final变量,可以在 try-with-resources 语句中使用该变量,而无需在 try-with-resources 语句中声明一个新变量。
static String readFirstLineFromFile(String path) throws IOException {
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
}
}
//实际上相当于
static String readFirstLineFromFileWithFinallyBlock(String path) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
} finally {
if (br != null) br.close();
}
}
再来一个直观的例子
public class Main2 {
public static void main(String[] args) {
try(ResourceSome some = new ResourceSome();
ResourceOther other = new ResourceOther()) {
some.doSome();
other.doOther();
} catch(Exception ex) {
ex.printStackTrace();
}
}
}
class ResourceSome implements AutoCloseable {
void doSome() {
System.out.println("do something");
}
@Override
public void close() throws Exception {
System.out.println("some resource is closed");
}
}
class ResourceOther implements AutoCloseable {
void doOther() {
System.out.println("do other things");
}
@Override
public void close() throws Exception {
System.out.println("other resource is closed");
}
}
最终输出为:
do something
do other things
other resource is closed
some resource is closed
第7条
第七句有的公司喜欢用这句话做面试题的,具体的面试题是这样的
/*
* java面试题20--如果catch里面有return语句,finally里面的代码还会执行吗?
*/
public class FinallyDemo2 {
public static void main(String[] args) {
System.out.println(getInt());
}
public static int getInt() {
int a = 10;
try {
System.out.println(a / 0);
a = 20;
} catch (ArithmeticException e) {
a = 30;
return a;
} finally {
a = 40;
}
return a;
}
}
第二题:
/*
* java面试题20--如果catch里面有return语句,finally里面的代码还会执行吗?
*/
public class FinallyDemo2 {
public static void main(String[] args) {
System.out.println(getInt());
}
public static int getInt() {
int a = 10;
try {
System.out.println(a / 0);
a = 20;
} catch (ArithmeticException e) {
a = 30;
return a;
} finally {
a = 40;
return a;
}
}
}
第一个执行结果是30,第二个执行结果是40;
第一个是因为 return a 在程序执行到这一步的时候,这里不是return a 而是 return 30;这个返回路径就形成了, 但是呢,它发现后面还有finally,所以继续执行finally的内容,a=40, 再次回到以前的路径,继续走return 30,形成返回路径之后,这里的a就不是a变量了,而是常量30。
第二个是因为return a 在程序执行到这一步的时候,这里不是return a 而是 return 30;这个返回路径就形成了,但是呢,它发现后面还有finally,所以继续执行finally的内容,a=40,再次回到以前的路径,继续走return 30,形成返回路径之后,这里的a就不是a变量了,而是常量30。
第一个执行结果是30,第二个执行结果是40;
第10条
里面提及到了JDK8的新特性之一,Optional避免空指针的问题。具体代码是如何避免的呢?
public class OptionalTest {
public static void main(String[] arg) {
/*------------------------- 第一种写法 ------------------------- */
//创建Optional对象,如果参数为空直接抛出异常
Optional<String> str=Optional.of("a");
//获取Optional中的数据,如果不存在,则抛出异常
System.out.println(str.get());//打印结果:a
//optional中是否存在数据
System.out.println(str.isPresent());//打印结果:true
//获取Optional中的值,如果值不存在,返回参数指定的值
System.out.println(str.orElse("b"));//打印结果:a
//获取Optional中的值,如果值不存在,返回lambda表达式的结果
System.out.println(str.orElseGet(()->LocalDateTime.now().toString()));//打印结果:a
//获取Optional中的值,如果值不存在,抛出指定的异常
System.out.println(str.orElseThrow(()->new RuntimeException()));//打印结果:a
/*------------------------- 第二种写法 ------------------------- */
Optional<String> str2=Optional.ofNullable(null);
//optional中是否存在数据
System.out.println(str2.isPresent());//打印结果:false
//获取Optional中的值,如果值不存在,返回参数指定的值
System.out.println(str2.orElse("b"));//打印结果:b
//获取Optional中的值,如果值不存在,返回lambda表达式的结果
System.out.println(str2.orElseGet(()->LocalDateTime.now().toString()));//打印结果:2018-01-18T10:57:40.270
//获取Optional中的值,如果值不存在,抛出指定的异常
System.out.println(str2.orElseThrow(()->new RuntimeException()));//打印结果:……threw exception [Request processing failed; nested exception is java.lang.RuntimeException] with root cause
}
}
(二)日志规约
三、单元测试
四、安全规约
第3条
比如where条件后面拼接1=1
第4条
解释一下ReDOS,全称Regular expression Denial of Service,翻译为 正则表达式拒绝服务攻击。开发人员使用了正则表达式来对用户输入的数据进行有效性校验, 当编写校验的正则表达式存在缺陷或者不严谨时, 攻击者可以构造特殊的字符串来大量消耗服务器的系统资源,造成服务器的服务中断或停止。
正则表达式引擎分成两类:一类称为DFA(确定性有限状态自动机),另一类称为NFA(非确定性有限状态自动机)。
DFA对于文本串里的每一个字符只需扫描一次,比较快,但特性较少;
NFA要翻来覆去吃字符、吐字符,速度慢,但是特性(如:分组、替换、分割)丰富。
比如我们定义一个正则表达式^(a+)+$ 来对字符串aaaaX匹配。使用NFA的正则引擎,必须经历2^4 =16次尝试失败后才能否定这个匹配。同理字符串为aaaaaaaaaaX就要经历2^10=1024次尝试。如果我们继续增加a的个数为20个、30个或者更多,那么这里的匹配会变成指数增长。
第6条
这里给CSRF举几个例子。
简单版:
假如博客园有个加关注的GET接口,blogUserGuid参数很明显是关注人Id,如下:
http://www.cnblogs.com/mvc/Follow/FollowBlogger.aspx?blogUserGuid=4e8c33d0-77fe-df11-ac81-842b2b196315
那我只需要在我的一篇博文内容里面写一个img标签:
img style="width:0;" src="http://www.cnblogs.com/mvc/Follow/FollowBlogger.aspx?blogUserGuid=4e8c33d0-77fe-df11-ac81-842b2b196315" / (此处没有闭合)
那么只要有人打开我这篇博文,那就会自动关注我。
从这个实例中可以看出,GET接口太容易被拿来做CSRF攻击,只要构造一个img标签,而img标签又是不能过滤的数据。接口最好限制为POST使用,GET则无效,降低攻击风险。
当然POST并不是万无一失,攻击者只要构造一个form就可以,但需要在第三方页面做,这样就增加暴露的可能性。
现在业界对CSRF的防御,一致的做法是使用一个Token(Anti CSRF Token)。也就是用户访问某个表单页面,服务端生成一个token放在用户session或者浏览器的cookie中,提交请求时会验证两者token是否一致,一致则合法,否则驳回。